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/
Android下Opengl ES实现单屏幕双眼显示的更多相关文章
- Android平台OpenGL ES/Assimp/OpenCV/GLM集成说明
Android平台OpenGL ES/Assimp/OpenCV/GLM集成说明 本文代码见: https://github.com/jiangxincode/OpenGLDemo 集成Assimp ...
- 【Qt for Android】OpenGL ES 绘制彩色立方体
Qt 内置对OpenGL ES的支持.选用Qt进行OpenGL ES的开发是很方便的,很多辅助类都已经具备.从Qt 5.0開始添加了一个QWindow类,该类既能够使用OpenGL绘制3D图形,也能够 ...
- OpenGL ES 3D空间中自定义显示空间
在Android中,我们所熟知的是在ES管线中,其在图元装配时,会进行图元组装与图元分配,这样就回剪裁出来视景体中的物体.但是如果我想在3D场景中规定一个区域,凡是在这个区域中的物体就能显示出来,非这 ...
- Android OpenGL ES(四)----调整屏幕的宽高比
1.宽高比问题 我们如今相当熟悉这样一个事实,在OpenGL里,我们要渲染的一切物体都要映射到X轴和Y轴上[-1,1]的范围内,对于Z轴也一样.这个范围内的坐标被称为归一化设备坐标,其独立于屏幕实际尺 ...
- 通过 PC 远程控制 Android 的应用 -- 可以将手机屏幕投射显示到电脑上
测试结果中的部分测试图:Mobizen手机界面: 电脑界面: 主界面 视频 全屏视频 WebKey手机界面: 电脑界面: AirMore手机界面: 电脑界面:主界面 镜像 全屏镜像 Airdroid手 ...
- EGL接口介绍-----Android OpenGL ES底层开发
引自:http://www.cnitblog.com/zouzheng/archive/2011/05/30/74326.html EGL 是 OpenGL ES 和底层 Native 平台视窗系统之 ...
- 如何使用Android中的OpenGL ES媒体效果
引自:http://www.2cto.com/kf/201506/404366.html Android的媒体效果框架允许开发者可以很容易的应用多种令人印象深刻的视觉效果到照片或视频之上.作为这个媒体 ...
- Android OpenGL ES(五)GLSurfaceView .
Android OpenGL ES 相关的包主要定义在 javax.microedition.khronos.opengles GL 绘图指令 javax.microedition.khrono ...
- Android OpenGL ES 开发(一): OpenGL ES 介绍
简介OpenGL ES 谈到OpenGL ES,首先我们应该先去了解一下Android的基本架构,基本架构下图: 在这里我们可以找到Libraries里面有我们目前要接触的库,即OpenGL ES. ...
随机推荐
- Spring入门之通过注解 处理 数据库事务
用Spring 中的事务写的银行转帐的例子:(环境同上一个贴子) 一.表结构: (create table (id int,username varchar(10),salary int);) 二.文 ...
- day10上节内容补充和初始函数
1.上节内容补充 文件的删除和修改: #文件的删除和修改 #文件中全部都要修改 # with open('歌词',encoding='utf-8') as f1,open('歌词.bak','w',e ...
- 高通Quick Charge高速充电原理分析
1 QC 2.0 1.1 高通Quick Charge 2.0 高速充电原理分析 高通的QC2.0高速充电须要手机端和充电器都要支持才行. 当将充电器端通过数据线连到手机上时,充电器默认的是将D+和D ...
- L - Sum It Up(DFS)
L - Sum It Up Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d & %I64u Descr ...
- SharePoint服务器端对象模型 之 对象模型概述(Part 1)
在一个传统的ASP.NET开发过程中,我们往往会把开发分为界面展现层.逻辑业务层和数据访问层这三个层面.作为一个应用开发平台,SharePoint是微软在直观的开发能力和自由的扩展能力之间,取到的一个 ...
- an open source web server and reverse proxy
https://www.nginx.com/resources/admin-guide/ NGINX is an open source web server and reverse proxy th ...
- camke GUI工具 选择 vs2017 时,如何指定工具集 v140 而不是默认的 v141?
在参数位置加入 v140 即可,不需要加 -T
- [转载]在服务器端判断request来自Ajax请求(异步)还是传统请求(同步),x-requested-with XMLHttpRequest
在服务器端判断request来自Ajax请求(异步)还是传统请求(同步) 在服务器端判断request来自Ajax请求(异步)还是传统请求(同步): 两种请求在请求的Header不同,Ajax 异步 ...
- ABAP权限检查,TCode与权限对象进行关联
一.确认权限对象,和关联字段: Tcode:SU21 维护权限对象例如"M_MSEG_WMB",它关联字段为'WERKS'M_MSEG_WMB 物料凭证:工厂 二.在ABAP代码中 ...
- jvm性能监控工具
jvm可能存在的问题: OutOfMemoryError:内存不足 内存泄露 线程死锁 锁竞争(Lock Contention) Java消耗过多的CPU 一.jps(j ...