視頻教程請關注 http://edu.csdn.net/lecturer/lecturer_detail?lecturer_id=440
一個朋友在問(我也曾經遇到過這樣的事情),尤其是在地理信息上面,地圖上的一些矢量數據,以及
影像數據,在地圖沒有變化(比如,縮放,平移,編輯)都是不需要繪制的,只有需要繪制的時候,在去繪制
背景,想必,這個道理大家一定都很明白,但是OpenGL每次在繪制的時候是必須都要進入渲染管線進行繪制
於是很多人就在想,是否可以把一些不需要變化的數據繪制到圖片上,需要繪制的時候在進行重新繪制,就像
windows DC一樣呢?在OpenGL早期的版本中是沒有把數據繪制到圖片上這個功能的,當然在創建OpenGL
的時候有這個選項,本人親身試驗過,那個效率,那個差呀,OpenGL初始化代碼如下所示:
PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SUPPORT_DIRECTDRAW | PFD_SWAP_EXCHANGE, PFD_TYPE_RGBA, 32, 8, 0, 8, 8, 8, 0, 0, 0, 32, 8, 8, 8, 8, 24, 8, 0, PFD_MAIN_PLANE, 0, 0, 0, 0 };
紅色的部分就是繪制到圖片的選項。
這種方案是不可取的,且不說他的效率問題,也滿足不了目前的需求,在OpenGL1.1版本中,我們可以操作顏色緩沖區,或者
叫幀緩沖區,在OpenGL中,至少存在兩個緩沖區(當我們選擇雙緩沖繪制的時候),我們可以把數據繪制到緩沖區以后,在將
緩沖區的數據直接的生成到紋理上,這樣在把紋理繪制到背景中,這樣,就可以有選擇的去更新背景,而不是實時的去繪制背景
數據,流程如下圖所示:
代碼如下所示:
glClearColor(1, 1, 1, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushAttrib(GL_COLOR_BUFFER_BIT | GL_PIXEL_MODE_BIT); // for GL_DRAW_BUFFER and GL_READ_BUFFER glDrawBuffer(GL_BACK); glReadBuffer(GL_BACK); //! 繪制數據到GL_BACK緩沖區 //! 繪制完成,將緩沖區內容cpopy到紋理 glBindTexture(GL_TEXTURE_2D, textureId); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT); glBindTexture(GL_TEXTURE_2D, 0); glPopAttrib(); // GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT //! 其他實時繪制內容
當然,這個方式比較老土,但能實現我們想要的功能,而且效率也不賴。在新的OpenGL版本中實現這個過程有很多方式
例如比較流行的就是FBO( Fram buffer object),幀緩沖區對象,其實就是我們上面的過程,所不同的是:上面我們用到
的緩沖區是OpenGL給我們創建的,我們沒有辦法干預創建的過程,而后者則可以干預這個過程,我們可以自己去創建幀
緩沖區,並使用它,當然這個需要更高的OpenGL版本,你需要做更多的事情。
下面是創建Frame Buffer Object 的代碼:
glGenFramebuffersEXT(1, &targetId._FBOID); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, targetId._FBOID); glGenRenderbuffersEXT(1, &targetId._RBOID); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, targetId._RBOID); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); //glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId, 0); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, targetId._RBOID); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
創建了以后,為了把數據繪制到上面,我們還需要給他綁定一個紋理,這個過程就像我們創建一個內存DC一樣,如果沒有和圖片綁定
繪制是沒有任何意義的;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, targetId._FBOID); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId._texture, 0);
綁定紋理以后,以后的繪制,則是將數據繪制到紋理上了;代碼中可以這樣使用:
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, targetId->_FBOID);
glBegin()
...
glEnd()
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
在一種方式就是PBuffer:像素緩沖區,過程和這個相似。每一種方式都有自己的優點與缺點,在不同的場合用不同的方式
做到最大化利用就對了。
后續會專門對離屏渲染做專門的例程。感謝大家閱讀,本人能力有限,錯誤,誤導之處請指教。