OSG圖形設備接口GraphicsContext

一、圖形設備與相機html

      在Camera類的成員函數中,setGraphicContext()函數的工做是設置相機對應的圖形設備對象,換句話說,下面要介紹的GraphicsContext類就是圖形設備對象的載體。用一句話來描述的話,GraphicsContext是任意圖形子系統的抽象層接口,它提供了統一的圖形設備操做函數,用來實現渲染結果和底層設備的交互;同時它還具備平臺無關性,於是將OSG的渲染過程與操做系統平臺剝離開來,使二者相互獨立。用戶便可以將渲染的內容傳遞給Windows或者X11的窗口與像素緩存對象,也能夠自定義一個支持OpenGL的圖形設備,並將結果反映在其上。linux

      圖形設備對象的主要工做是提供場景渲染結果的載體,這個載體能夠顯示緩存,進而繪製到一個圖像窗口中,也能夠是其餘特殊的緩存對象,從而實現複雜的渲染和圖像屢次曝光等功能,建立一個圖像設備不能簡單地使用new運算符,由於GraphicContext類是一個不能被實例化的抽象類(這個體如今valid()等一大批純虛函數上);一般應當使用createContext()靜態函數,自動根據當前的用戶環境和特性參數traits,構建一個平臺相關的圖形設備對象。 緩存

[html]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. osg::ref_ptr<osg::GraphicsContextgc = osg::GraphicsContext::creteGraphicsContext(traits)  

 

二、窗口與像素緩存(Pixel Buffer)ide

      Windows下的每個窗口都附帶了一個設備環境(Device Context,DC)。當須要在窗口中直接進行二維圖像繪製時,可使用Windows圖形設備接口函數(GDI)來完成操做。若是但願在某個Windows的窗口中實現三維場景的渲染,則須要將一個OpenGL渲染環境(Rendering Context, RC)的標識與此窗口的設備環境相關聯;若是當前的OpenGL指令都要輸出到某一個窗口,還應當指定該窗口的渲染環境爲「當前渲染環境」。假設已知窗口句柄爲hwnd,那麼一個簡單的渲染窗口的實現過程以下。函數

 

[html]  view plain  copy
 
  1. HDC hdc = GetDC(hwnd);  
  2. HGLRC hrc = wglCreateContext(hdc);  
  3. ----  
  4. wglMakeCurrent(hdc, hrc);  

 

        對於一個OpenGL而言,參與三維繪製的窗口能夠有多個,可是一個渲染環境只能與一個窗口的設備環境相關聯;而且任意時刻都只能有一個渲染環境被指定爲當前環境。優化

      而對於OSG來講,有關窗口及其渲染環境的操做都是由GraphicsContext的派生類osgViewer::GraphicsWindow來完成的。有關這個類及其「平臺相關」子類的具體實現,參見後文「人機交互與圖形設備接口」的內容。ui

      像素緩存(Pixel Buffer, PBuffer)是一種較新的OpenGL擴展功能,用於實現離屏渲染(Off-screen Rendering)以及渲染到紋理(又稱紋理烘焙,Render to Texture)。簡單地說, PBuffer機制將原本渲染到顯示緩存的場景數據換向輸出到一處用戶緩存中,進而能夠將渲染數據綁定到紋理圖片,甚至直接取出進行處理。將場景渲染的數據綁定到一張紋理圖片的動做稱爲「紋理烘焙」;而使用着色器進行逐頂點或逐像素的數學運算,經過glReadPixels()等函數將渲染到紋理的結果從新取出,並加以儲存和從新運用的過程,則屬於通用GPU計算(General-purpose Computing on Graphics Process Units, GPGPU)的範疇。spa

      OpenGL的像素緩存能夠理解成一個創建在已有窗口上的一個虛擬窗口設備,它一樣須要建立一個「窗口」句柄,爲這個句柄分配設備環境,而且爲設備環境關聯渲染環境。由此獲得的PBuffer設備能夠像普通窗口同樣被操做,可是它還容許將這個「窗口」綁定到指定的紋理對象,從而將渲染到該「窗口」的場景內容烘焙到紋理上。假設已知一個實際窗口的設備環境hdc,在其基礎上構建一個PBuffer窗口的基本步驟以下。操作系統

 

[html]  view plain  copy
 
  1. HWND pbufferHwnd = reinterpret_cast<HWND>(wglCreatePbufferARB(hdc, ---));  
  2. HDC pbufferHdc = wglGetPbufferDCARB(reinterpret_cast<HRBUFFERARB>(pbufferHwnd));  
  3. HGLRC pbufferHrc = wglCreateContext(pbufferHdc);  
  4. ----  
  5. wglMakeCurrent(pbufferHdc, pbufferHrc);  
  6. ----  
  7. glBindTexture(----);  
  8. wglBindTexImageARB(reinterpret_cast<HPBUFFERARB>(phbufferHwnd), ---);  

 

    OSG中完整地封裝了像素緩存的實現機制。正是因爲pBuffer設備和窗口的相似之處,各個平臺上的pBuffer類的實現一樣都是由GraphicContext的派生類來完成的,包括核心庫osgViewer下的PixelBufferWin32(Windows平臺下的實現)、PixelBufferX11(Linux X11下的實現)和PixelBufferCarbon(Mac OS X下的實現)類。當將前文中說起的Traits::pbuffer參數設置爲真時,系統就會根據當前系統平臺的類別加載相應的PBuffer設備。固然直接使用createGraphicsContext()函數啓動一個PBuffer也許沒有太大的意義,更多的是在執行渲染到紋理功能時建立一個與之綁定的PBuffer設備。具體參看下一節的內容。.net

三、渲染到紋理(Rende to Texture)

      上一節已經提到過,渲染到紋理(紋理烘焙)這一功能有兩個主要做用——是實現場景離屏渲染以後的「後置處理」(Post-processing);二是實現多種不一樣場景的融合顯示。

      一個典型的例子以下所述:在一個房間中放置一臺播放着精彩節目的電視,房間是主場景;而電視節目則屬於另外一個場景,它做爲紋理被顯示在電視屏幕的模型之上,於是成爲了主場景的組成部分。重要的是,節目的播放、節目頻道的替換,以及節目信號是否忽然中斷等,這些複雜的變故與主場景並無直接關係,對於整個房間而言,那只是一幅不斷更新着的紋理圖片而已。

      上一節介紹了像素緩存(PBuffer)這一經常使用的OpenGL機制,然而實現紋理烘焙的手段並不僅有像素緩存一種而已。經常使用的渲染到紋理的手段包括直接複製幀緩存(Frame buffer)中的像素、使用像素緩存設備、以及使用使用幀緩存對象(Frame Buffer Object, FBO)3種。

     直接複製幀緩存(Frame buffer)中的像素: OpenGL中提供了多種從當前幀的緩存數據中生成二維紋理的方法。效率較低的例如使用glReadPixels()提取像素再傳遞給glTexImage2D();而效率較高的則使用glCopyTexImage2D()或者glCopyTexSubImage()函數,直接將顯示緩存中的數據保存爲紋理圖片。可是不管怎樣,這都是一種間接地「渲染到紋理」的方案,於是其中老是免不了一個「將數據複製到紋理」的步驟。

     使用像素緩存設備 : 由此產生的一個優化方案就是使用像素緩存設備。正如以前介紹的那樣,它省卻了複製的過程,而是直接將子場景渲染到與之綁定的紋理中。所以PBuffer雖然可能在一些老式和低端的顯卡上沒法獲得全面的支持,但依然足以取代直接複製幀緩存的作法,從而進一步提高了紋理烘焙的效率。

     幀緩存對象: 然而PBuffer仍是有一些沒法使人忽視的問題,例如每個PBuffer設備都必須創建一個本身的渲染環境(RC);它們各自有本身的像素格式、深度和模板緩存;對多個PBuffer進行切換和管理都十分困難。所以,一個新的解決方案誕生了,那就是幀緩存對象(Frame Buffer Object, FBO)擴展。

      幀緩存的意義在於,它是一段2D數據的存儲空間,保存了OpenGL渲染管線最終獲得的像素數據。幀緩存的數據直接輸出到窗口系統,即做爲顯示緩存使用,這種默認的緩存對象又稱爲「窗口系統支持」(Window-system-provided)的幀緩存。

      若是將幀緩存的信息換向輸出到一個虛擬窗口設備,並進而綁定到紋理對象,那麼這就是以前所說的PBuffer的概念。若是另外定義一種不參與顯示的,由「應用程序建立」(Application-created)的幀緩存,則稱爲幀緩存對象(FBO)。當FBO與一個紋理對象綁定時,它實現的便是「渲染到紋理」的操做;若是它與一處內存空間綁定,那麼所執行的操做稱爲「離屏渲染」,咱們能夠隨後取出該空間的內容,將其保存到圖片或執行其餘的後置處理。

      FBO支持多達16個綁定通道,能夠綁定渲染結果的多個顏色緩存值、深度緩存值以及模板緩存值到紋理或者自定義空間之上。FBO易於管理,多個FBO對象之間的切換也十分迅速,而且它還具備平臺無關的特性(要知道PBuffer是平臺相關的)。

    OpenGL中定義和綁定FBO的基本流程以下:

 

[html]  view plain  copy
 
  1. /* 建立FBO對象那個*/  
  2. GLuint fboID;  
  3. glGenFramebuffersEXT(1, &fboID);  
  4. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID);  
  5. /*綁定FBO與一個二維紋理對象textureID*/  
  6. glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT,  
  7.                          GL_COLOR_ATTACHMENT0_EXT,  
  8.                          GL_TEXTURE_2D, textureId, 0);  
  9. /*渲染子場景到紋理*/  
  10. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);  
  11. drawSubScene();  
  12. glBindFrameBufferEXT(GL_FRAMEBUFFER_EXT, 0);  

    而OSG中則直接使用Camera類實現了對於FBO、PBuffer和讀取幀緩存3種紋理烘焙方式的支持。

相關文章
相關標籤/搜索