Android下Opengl ES实现单屏幕双眼显示

http://blog.csdn.net/u011371324/article/details/68946779

默认情况下,Opengl ES使用系统提供的帧缓冲区作为绘图表面,一般情况下,如果只在屏幕的表面绘图的话,系统提供的默认帧缓冲区很高效,但是很多应用程序需要渲染到纹理。此时,就需要我们自己来创建帧缓冲区对象。比如在VR中就需要使用帧缓冲对象在同一块屏幕上来实现双眼显示模式。

 

首先,说下渲染到纹理的概念。

渲染到纹理(Render to Texture),将我们要绘制的场景保存到一张纹理当中,打个比喻,类似于利用手机的截图操作,手机的画面就好比是已经渲染好的内容,截图得到的图片相当于纹理,然后将它附加到缓冲区对象上。

 

在Opengl中,帧缓冲区是渲染管线的最后一步,即可以理解为将在屏幕上显示的信息都保存在这里,它像一个容器,里面有颜色附着、纹理、模板、深度等信息,下图就是帧缓冲区、渲染缓冲区对象、纹理的关系。

                                                                                                

 

 

当我们自己不创建帧缓冲区对象时,使用的是系统默认提供的,此时,当前我们的渲染操作都是针对系统的帧缓冲区对象,就像向该容器中放信息,而在显示时,也是由该容器提供信息。

 

所以想要在一块屏幕上显示左右两块区域的图像时,就需要再增加2个“容器”,来暂时保存纹理等信息,显示时再将这两个容器的信息交给系统的容器,即将2个自己创建的帧缓冲区对象的纹理作为系统缓冲区对象的纹理,然后进行绘图显示

 

有个疑问是,既然都是容器,为什么还要用自己创建呢?

假设同一个屏幕上的两个区域显示两幅图像,左右场景不同,渲染管线出来只有一张纹理放到“容器”中,两个管线得到两张纹理,但是系统的帧缓冲区只对应一个渲染管线,不能直接使用两张纹理,所以就需要弄两个“容器”来缓存一下两张纹理,然后在屏幕显示每一帧的过程中,在左右两部分分别使用两张纹理进行绘制,再得到一个整合后的纹理,然后交给系统的帧缓冲区。这样,就能实现同一个屏幕上的两个区域显示两幅图像,利用两个“容器”(自己创建的帧缓冲区对象)类似于卸磨杀驴。

 


 

使用帧缓冲对象渲染到纹理的基本操作,其中,初始化缓冲区对象最为关键,主要有以下几个步骤

 

a)创建帧缓冲对象
b)创建与帧缓冲对象一起使用的纹理对象
c)创建渲染缓冲区对象
d)绑定帧缓冲区对象
e)绑定纹理对象
f)设置纹理的参数,格式、尺寸等设置
g)绑定渲染缓冲区对象并设置尺寸
h)连接纹理对象到缓冲区对象的颜色附着上
i)连接渲染缓冲区对象到深度附着

 

上面是基本的理论部分,下面直接上代码

 

int[] temp = new int[1];

//generate fbo id

GLES20.glGenFramebuffers(1, temp, 0);

fboId = temp[0];

//generate texture

GLES20.glGenTextures(1, temp, 0);

fboTex = temp[0];

//generate render buffer

GLES20.glGenRenderbuffers(1, temp, 0);

renderBufferId = temp[0];

//Bind Frame buffer

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);

//Bind texture

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fboTex);

//Define texture parameters

GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, fboWidth, fboHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,null);

GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);

GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);

//Bind render buffer and define buffer dimension

GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderBufferId);

GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, fboWidth, fboHeight);

//Attach texture FBO color attachment

GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, fboTex, 0);

//Attach render buffer to depth attachment

GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, renderBufferId);

//we are done, reset

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, 0);

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

 

以上就是初始化帧缓冲对象的过程,基本的操作相对比较固定

 

下面的函数是安卓中利用Opengl es绘制的每一帧,大致过程:在你想要得到的纹理前先绑定初始化好的帧缓冲对象,设置窗口,然后开始渲染你的纹理,渲染完之后,解除绑定,切换到系统的帧缓冲区,再进行绘制,最简单的就是你可以画一个矩形,然后将纹理贴到上面,最终显示到屏幕上。

 

public void RenderToTexture (GL10 arg0){

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);

GLES20.glViewport(0, 0, fboWidth, fboHeight);

        ******Rendering Code*******

       

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

}

 

public void onDrawFrame(GL10 arg0)

{

    //call FBORenderer to render to texture

    fbor.RenderToTexture();//调用RenderToTexture 方法,将纹理保存在fbor的缓冲区中

    //reset the projection, because viewport is set by FBO renderer is different

    GLES20.glViewport(0, 0, vwidth, vheight);

    float ratio = (float)vwidth/(float)vheight;

    float a = 5f;

    Matrix.orthoM(m_fProj, 0, -a*ratio, a*ratio, -a*ratio, a*ratio, 1, 10);   

    //multiply view matrix with projection matrix

    Matrix.multiplyMM(m_fVPMat, 0, m_fProj, 0, m_fView, 0);

    //below procedure is same as any other rendering

    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT|GLES20.GL_DEPTH_BUFFER_BIT);

   

    GLES20.glUseProgram(iProgId);

   

    vertexBuffer.position(0);

    GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);

    GLES20.glEnableVertexAttribArray(iPosition);

   

    texBuffer.position(0);

    GLES20.glVertexAttribPointer(iTexCoords, 2, GLES20.GL_FLOAT, false, 0, texBuffer);

    GLES20.glEnableVertexAttribArray(iTexCoords);

   

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iTexId);

    GLES20.glUniform1i(iTexLoc, 0);

    //since I'm multi-texturing, bind fboId to texture1

    GLES20.glActiveTexture(GLES20.GL_TEXTURE1);

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fboId);

    GLES20.glUniform1i(iTexLoc1, 1);

    //for rotating cube

    Matrix.setIdentityM(m_fModel, 0);

    Matrix.rotateM(m_fModel, 0, -xAngle, 0, 1, 0);

    Matrix.rotateM(m_fModel, 0, -yAngle, 1, 0, 0);

    //multiply model matrix with view-projection matrix

    Matrix.multiplyMM(m_fMVPMat, 0, m_fVPMat, 0, m_fModel, 0);   

    //pass model-view-projection matrix to shader

    GLES20.glUniformMatrix4fv(iMVPMat, 1, false, m_fMVPMat, 0);   

    //draw cube

GLES20.glDrawElements(GLES20.GL_TRIANGLES, cube.m_nIndeces, GLES20.GL_UNSIGNED_SHORT, indexBuffer);

}

 

 

上面给出的仅仅是一个缓冲区对象的主要代码部分,对于实现双眼显示的话,要创建两个缓冲区对象,分别渲染纹理到这两个缓冲区中,

然后在onDraw()函数中可以绘制两个矩形,每个矩形分别贴上这两张纹理,递交给系统的帧缓冲区(解绑定时已经切换到系统缓冲区对象啦,

所以按照正常的绘制流程就行了) ,此时,屏幕上就显示了左右两张图像了。

 

  

 

参考:http://opengles2learning.blogspot.kr/2014/02/render-to-texture-rtt.html

参考:Opengl ES 3.0编程指南

参考:http://learnopengl-cn.readthedocs.io/zh/latest/04%20Advanced%20OpenGL/05%20Framebuffers/

转载于:https://www.cnblogs.com/jukan/p/6837817.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/372207.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle Service Bus –线程阻塞案例研究

本案例研究描述了在AIX 6.1和IBM Java VM 1.6上运行的Oracle Service Bus 11g遇到的线程阻塞问题的完整根本原因分析过程。 本文也是您提高线程转储分析技能的绝佳机会,我强烈建议您学习并正确理解以下分析方法。 与过早的中间件(Weblogic)重…

java 可以重载等于号码_Java面试之Java基础4——重载与重写的区别

目录重载与重写的概念重载与重写的区别重载与重写的总结构造器是否能被重写override为什么函数不能根据返回类型来区分重载重载与重写的概念重载:同样一个方法可以根据输入参数列表的不同,做出不同的处理。普通方法和构造器方法都能够重载。方法重载&…

二维数组、多维数组

二维数组: 定义二维数组 int[,] myArray new int[几个一维数组,数组中的个数]; 数组可以具有多个维度。例如,下列声明创建一个四行两列的二维数组(可以理解为4个1维数组,数组中包含2个元素): int[,] myArray new int[4,2]; int[…

一张大图片有多个小图片

这个页面也是我看到别人的写的,感觉不错,就自己留下了为了以后自己可以容易找到,也希望可以方便到别人。 写这个页面 需要注意的是: 1.写每一个小图片的位置时候,要用id,这样等级就高了,不然不起作用。 2.因…

Android Studio混淆

这一篇说一下Android Studio的代码混淆: 第一步:要想使混淆生效,要修改项目(App)下的build.gradle一处内容:minifyEnabled 的值 设置为true,当前项目就可以使用混淆了。 apply plugin: com.and…

Java 8:测试Lambda水

Java 8大约有一年的时间了,它具有我非常期待的语言功能: Lambda Expression 。 令人遗憾的是,另一个重要功能Java平台模块已延迟到Java9。但是,将lambda表达式(或闭包)添加到该语言中将使Java编程变得更好。…

基于阀值的工作流引擎设计

最近在做工作流处理流程部分的工作,顺便研究了一下工作流引擎的一些设计理念和原理。由于以前接触过人工智能神经网络的一些东西,发现工作流引擎和神经网络还是颇有一些相似之处,都是满足一定的条件下向下一个节点传递。在神经网络的神经元中…

Git之安装管理

1.Git安装部署 Git是分布式的版本控制系统,我们只要有了一个原始Git版本仓库,就可以让其他主机克隆走这个原始版本仓库,从而使得一个Git版本仓库可以被同时分布到不同的主机之上,并且每台主机的版本库都是一样的,没有主…

Java执行程序服务类型

ExecutorService功能是Java 5附带的。它扩展了Executor接口,并提供了线程池功能来执行异步简短任务。 使用Java 6提供的ExecutorService接口有五种异步执行任务的方法。 ExecutorService execService Executors.newCachedThreadPool(); 这…

MySQL的主动优化和被动优化_MySQL“被动”性能优化汇总!

年少不知优化苦,遇坑方知优化难。 ——村口王大爷本文内容导图如下:我之前有很多文章都在讲性能优化的问题,比如下面这些:当然,本篇也是关于性能优化的,那性能优化就应该一把梭子吗?还是要符合一…

python2

一、管理库的安装 安装pip 提示报错:安装pip提示No module named setuptools Windows环境下Python默认是没有安装setuptools这个模块的,这也是一个第三方模块。下载地址为http://pypi.python.org/pypi/setuptools。下载后直接运行ez_setup.py 参考地址&…

【图】最短路径——Floyed算法和Dijkstra算法

最短路径问题(floyed.cpp dijkstra.cpp) 题目描述平面上有n个点(n<100)&#xff0c;每个点的坐标均在-10000&#xff5e;10000之间。其中的一些点之间有连线。若有连线&#xff0c;则表示可从一个点到达另一个点&#xff0c;即两点间有通路&#xff0c;通路的距离为两点间的…

Java并发– CyclicBarrier示例

Java中的CyclicBarrier是JDK 5中java.util.Concurrent包中引入的同步器&#xff0c;以及其他并发实用程序&#xff08;如Counting Semaphore &#xff0c; BlockingQueue &#xff0c; ConcurrentHashMap等&#xff09;。CyclicBarrier与CountDownLatch类似&#xff0c;我们在上…

JasperReports JSF插件用例–简单列表报告

这是JasperReports JSF插件系列的第一篇“用例文章” &#xff0c;我将专注于一个简单的需求&#xff0c;并且我将进一步深入。 起点是我们已经为图书商店完成的项目设置&#xff0c;我将向其中添加一个列表&#xff0c;其中包含在数据库中注册的其他图书&#xff0c;该列表也将…

ER图流程图

ER图&#xff1a;ER图分为实体、属性、关系三个核心部分。实体是长方形体现&#xff0c;而属性则是椭圆形&#xff0c;关系为菱形。 图书馆管理系统流程图&#xff08;图片源于网上&#xff09;&#xff1a;对于程序员来说&#xff0c;我们要知道&#xff1a;整个系统中&#x…

php源码仿三一重工,织梦仿三一重工业大学气企业网站php源码

★模板引荐★源码称呼&#xff1a;仿三一重工业大学气企业网站php源码仿三一重工业大学气企业网站php源码&#xff0c;尝试完备无错&#xff0c;兼容合流欣赏器。模板包括安置证明&#xff0c;并包括尝试数据。本模板鉴于DEDECms 5.7 GBK安排&#xff0c;须要 UTF-8版本的请本人…

php树莓派魔镜,用树莓派和显示器制作一面“魔镜”

所需要的材料一台显示器一块和显示器大小相同的双面镜一些2*4米的细木条树莓派机器必要组件(电源、HDMI线、usb无线网卡、键盘)木工工具(锯子、磨砂机、螺丝刀)螺丝、液态钉子选一个合适的显示器镜子的大小完全由显示器的类型和大小决定&#xff0c;所以我希望得到一个尽量大的…

【数字图像处理】[3]--直方图规范化

【数字图像处理】[3]--直方图规范化直方图规范化出现的原因是因为直方图均衡只能产生出固定的图像&#xff0c;不满足于需求&#xff0c;有时我们需要让直方图变成特定的直方图&#xff0c;于是有了直方图规范化原理&#xff1a;可能只看公式没什么感觉&#xff0c;我们来举一个…

JavaFX 2.0布局窗格– GridPane

毫无疑问&#xff0c; GridPane是JavaFX 2.0中功能最强大&#xff0c;最灵活的布局窗格。 它在由行和列组成的灵活网格中布置其子项&#xff0c;与Swing的GridBagLayout或HTML的表格模型非常相似。 这种方法使该窗格非常适合于任何形式的表单&#xff08;例如网站上的联系表单&…

java ui自动化测试脚本,如何用Airtest编写UI自动化脚本(示例代码)

前言游戏并不像app一样直接把渲染树节点暴露出来&#xff0c;这就造成游戏UI自动化在元素定位上的不方便性&#xff0c;不过依赖airtest的图片识别&#xff0c;我们可以直接跳过元素检查&#xff0c;以图片对比的形式进行自动化&#xff0c;虽然效率可能会低一些&#xff0c;但…