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.pswp.cn/news/372207.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372207.shtml
英文地址,請注明出處:http://en.pswp.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.因…

java中如何調用dal接口案例_關于Java:接口的目的

好吧,我認為接口是一種強制對象實現一定數量功能的方法,而不必使用繼承。有點像合同。我半明白他們的意思。但是,如果界面中的所有內容都是:public interface animal{void eat(object food);}它沒有這樣的實現,那么無論…

Android Studio混淆

這一篇說一下Android Studio的代碼混淆: 第一步:要想使混淆生效,要修改項目(App)下的build.gradle一處內容:minifyEnabled 的值 設置為true,當前項目就可以使用混淆了。 apply plugin: com.and…

內存訪問模式很重要

在高性能計算中,通常會說高速緩存未命中的代價是算法的最大性能損失。 多年來,處理器速度的提高大大超過了延遲到主內存的速度。 通過更寬的多通道總線,到主內存的帶寬已大大增加,但是延遲并未顯著減少。 為了掩蓋這種延遲&#x…

上傳頭像將光標去掉

οnfοcus"this.blur();" unselectable"on" οnfοcus"this.blur();"支持火狐,谷歌等主流瀏覽器 unselectable支持ie瀏覽器轉載于:https://www.cnblogs.com/jar-gon/p/6841239.html

java底層 文件操作_JAVA的文件操作【轉】

11.3 I/O類使用由于在IO操作中,需要使用的數據源有很多,作為一個IO技術的初學者,從讀寫文件開始學習IO技術是一個比較好的選擇。因為文件是一種常見的數據源,而且讀寫文件也是程序員進行IO編程的一個基本能力。本章IO類的使用就從…

JAVA多線程,真的能提高效率嗎

舉個栗子 比如挖一個隧道,有2種開工方法1、只在山的一頭挖,直至挖到山的另一頭,從而打通隧道,這可以看成是單線程 2、在山的兩頭挖,同時開工,最后在山的中間接通,從而打通隧道,這感覺…

Java 8:測試Lambda水

Java 8大約有一年的時間了,它具有我非常期待的語言功能: Lambda Expression 。 令人遺憾的是,另一個重要功能Java平臺模塊已延遲到Java9。但是,將lambda表達式(或閉包)添加到該語言中將使Java編程變得更好。…

java定義js函數_JS中可以先使用函數,然后再定義.

首先要說明的,下面這種方式是對的,雖然不知道為什么,很奇怪為什么可以先使用,再定義,希望有了解的人可以給個說法.hello(www.openj.cn);function hello(name){alert("hello " name)};本文首發于 http://blog.openj.cn下面的這種定義函數方式,對于寫一些比較復雜的代碼…

基于閥值的工作流引擎設計

最近在做工作流處理流程部分的工作,順便研究了一下工作流引擎的一些設計理念和原理。由于以前接觸過人工智能神經網絡的一些東西,發現工作流引擎和神經網絡還是頗有一些相似之處,都是滿足一定的條件下向下一個節點傳遞。在神經網絡的神經元中…

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 參考地址&…

Java Mybatis

Mybatis轉載于:https://www.cnblogs.com/leading-index/p/6853031.html

Java例外:java lang NoSuchMethodError

如果查看錯誤消息java.lang.NoSuchMethodError,您可能會理解Java虛擬機正在嘗試向我們表明您調用的方法在類或接口中不可用。 您還可能在執行沒有公共static void main()方法的類時拋出此錯誤。要了解其背后的原因,請閱讀本文。 …

【圖】最短路徑——Floyed算法和Dijkstra算法

最短路徑問題(floyed.cpp dijkstra.cpp) 題目描述平面上有n個點(n<100)&#xff0c;每個點的坐標均在-10000&#xff5e;10000之間。其中的一些點之間有連線。若有連線&#xff0c;則表示可從一個點到達另一個點&#xff0c;即兩點間有通路&#xff0c;通路的距離為兩點間的…