跳轉到內容

OpenGL 程式設計/OpenGL ES 概述

來自華夏公益教科書,開放世界的開放書籍

什麼是 OpenGL ES 2.0?

[編輯 | 編輯原始碼]

嵌入式系統 OpenGL (OpenGL ES) 是 OpenGL 3D 圖形 API 的一個子集。它專為嵌入式裝置而設計,例如行動電話、PDA 和影片遊戲機。支援 OpenGL ES 2.0 的著名平臺包括iPhone 3GS 及更高版本、Android 2.2 及更高版本和WebGL。桌面顯示卡驅動程式通常不支援 OpenGL ES API。然而,截至 2010 年,一些顯示卡製造商在其桌面驅動程式中引入了 ES 支援[1]

與其他 OpenGL 版本的差異

[編輯 | 編輯原始碼]

對於熟悉其他 OpenGL 版本的人來說,以及瀏覽網路查詢 OpenGL ES 2.0 資訊時需要注意的一點是,OpenGL ES 2.0 API 與 OpenGL <= 3.0 和 OpenGL ES 1.x 相去甚遠。

  • 不支援固定管道
    • 這意味著沒有內建的燈光、霧、多紋理或頂點變換(平移/旋轉等)支援。這些功能必須作為自定義著色器實現。對於標準用途,這些著色器非常簡單,大多數情況下只需複製貼上即可。
  • 僅使用頂點陣列/頂點緩衝區處理頂點
    • 不支援立即模式 (glBegin/glEnd) 和顯示列表。
  • 輔助函式較少
    • 例如,glFrustum()、glTranslate() 和 glRotate() 不存在。

這些設計決策導致 API 規模更小,但也需要更深入地瞭解渲染過程,並且需要付出更多努力(可能需要編寫更多樣板程式碼)才能設定渲染管道。從某種意義上說,OpenGL ES 2.0(釋出於 2007 年)領先於它的時代:對於桌面 OpenGL 來說,直到 OpenGL 3.1(釋出於 2009 年)才將傳統功能從核心功能中刪除。

OpenGL ES 2.0 管道結構

[編輯 | 編輯原始碼]

以下是 OpenGL ES 2.0 管道的粗略概述。我們將在後面更詳細地討論各個階段。有關非常詳細的說明,請參閱OpenGL ES 2.0 規範

  1. 頂點著色器
    • 輸入:屬性(頂點位置和其他每個頂點的屬性,例如透過頂點陣列/頂點緩衝區的紋理位置)、取樣器(紋理)、統一變數(常量)
    • 輸出:gl_Position(在裁剪座標中)、gl_FrontFacing(自動生成)、gl_PointSize(用於點精靈)、使用者定義的變元(到片段著色器)
  2. 圖元裝配
    • 三角形/線條/點精靈
    1. 裁剪
    2. 透視除法(產生裝置座標)
    3. 視口變換(產生視窗座標)
  3. 光柵化
    1. 剔除
    2. 深度偏移
    3. 變元插值
    4. 片段著色器
      • 輸入:gl_FragCoord、gl_FrontFacing、gl_PointCoord、取樣器(紋理)、統一變數(常量)、插值的變元(來自頂點著色器)
      • 輸出:gl_FragColor
  4. 片段操作
    1. 剪下測試
    2. 模板測試
    3. 深度測試
    4. 混合
    5. 抖動
  5. 渲染目標
    • 視窗系統提供的可繪製物件(直接渲染到螢幕)
    • 幀緩衝區和附加的渲染緩衝區(充當顏色、深度或模板緩衝區)或附加的紋理緩衝區

關於著色器的一般性說明

[編輯 | 編輯原始碼]

著色器是在 GPU 上執行的小程式。語法類似於 C,但有許多限制。著色器的輸入稱為屬性(用於每個頂點/每個片段的輸入)和統一變數(用於所有頂點/片段的常量)。使用者定義的輸出稱為變元

設定頂點和片段著色器包括將著色器(作為包含GLSL 的字串)傳遞給 OpenGL ES API,編譯兩個著色器並將它們連結(在連結期間,檢查輸入/輸出變元的對應關係),並將緩衝區繫結到統一變數和變元。

頂點著色器

[編輯 | 編輯原始碼]

對於每個輸入頂點,頂點著色器都會呼叫一次。頂點著色器的主要任務是為管道後面的階段提供頂點位置。此外,它還可以計算其他屬性,這些屬性可以作為片段著色器後面的輸入。最基本的著色器只是將頂點位置作為輸入,並將輸入資料直接分配給 gl_Position 變元。通常,著色器會執行與模型檢視投影矩陣(作為統一變數常量傳遞)的乘法,以允許對輸入幾何體進行平移和旋轉以及透視投影,可能傳遞紋理座標並計算光照引數。

其他使用者輸出通常包括

  • 紋理座標。這些座標可以只是從輸入屬性中傳遞到簡單的紋理貼圖,但也可以生成或處理以實現反射表面和環境對映,或其他效果,例如動態紋理貼圖。
  • 霧因子。對於霧效果,可以在頂點著色器中計算圖元到眼睛的距離。片段著色器稍後可以根據此值淡出片段。
  • 光照引數。根據光源位置(作為統一變數常量傳遞)和頂點法線(需要作為額外的每個頂點的輸入),可以為片段著色器生成光照引數。

請注意,在 OpenGL ES 2.0 中,透過取樣器在頂點著色器中進行紋理訪問是可選的,並且可能在某些裝置上不受支援。

圖元裝配

[編輯 | 編輯原始碼]

在圖元裝配階段,將執行幾個座標變換

  • 裁剪。位於視體之外的圖元將被丟棄,部分位於視體之外的圖元將被裁剪。頂點著色器的變元輸出也會被裁剪。
  • 透視除法。gl_Position 的三個主要元素(xyz)透過除以第四個頂點元素 w 歸一化為 [-1.0...1.0]。結果是歸一化的裝置座標。
  • 視口變換。透過使用 glViewport() 和 glDepthRangef() 設定的引數進行線性變換,將座標轉換為視窗座標。

光柵化

[編輯 | 編輯原始碼]

光柵化是指從圖元建立二維光柵化影像的過程,即為每個圖元計算片段(畫素)集。對於多邊形光柵化,這包括以下步驟。

  • 剔除。如果使用 FrontFace() 和 CullFace() 啟用,則可以丟棄從背面看到的多邊形。
  • 深度偏移。可以使用 PolygonOffset() 對多邊形座標應用深度偏移。這可以防止位於同一平面的多邊形的 Z 抖動。
  • 變元插值。在作為片段著色器輸入準備時,頂點著色器的變元輸出和深度將被插值。

片段著色器

[編輯 | 編輯原始碼]

片段著色器對每個圖元片段(畫素)呼叫一次。片段著色器的主要任務是為每個輸出片段提供顏色值。最基本的片段著色器只是將一個常數值分配給它的 gl_FragColor 輸出。通常,片段著色器會執行紋理查詢,並根據頂點著色器之前計算的照明引數來實現照明。

片段操作

[編輯 | 編輯原始碼]
  • 剪下測試。如果使用 glEnable(GL_SCISSOR_TEST) 啟用,則僅繪製指定矩形區域內的畫素。使用 glScissor() 配置。
  • 模板緩衝區測試。如果使用 glEnable(GL_STENCIL_TEST) 啟用,則只有在透過與模板緩衝區的測試後,才能更新畫素。使用 glStencil*() 配置。
  • 深度緩衝區測試。如果使用 glEnable(GL_DEPTH_TEST) 啟用,則只有在透過深度緩衝區測試後,才會繪製畫素,從而實現隱藏面剔除。使用 glDepthFunc() 配置。需要提供深度緩衝區。
  • 混合。如果使用 glEnable(GL_BLEND) 啟用,則片段著色器輸出的畫素可以與輸出緩衝區中已經存在的畫素值混合。混合的配置使用 glBlend*() 完成。
  • 抖動。如果使用 glEnable(GL_DITHER) 啟用,則可以使用抖動來增加感知到的顏色深度。無法進一步控制抖動過程。
  • 抗鋸齒。使用 glEnable(GL_SAMPLE_COVERAGE)、glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE) 和 glSampleCoverage(),可以配置簡單的抗鋸齒。

渲染目標

[編輯 | 編輯原始碼]

生成的畫素有幾個可能的目標。

  • 視窗系統提供的可繪製物件(直接渲染到螢幕)
  • 幀緩衝區和附加的渲染緩衝區

幀緩衝區物件具有三個附加的物件:深度或模板渲染緩衝區,以及顏色渲染緩衝區 *或* 紋理緩衝區。顏色渲染緩衝區不能用作紋理源。

  • glGenRenderbuffers()、glGenFramebuffers()、glBindRenderbuffer()、glRenderbufferStorage()、glBindFramebuffer()、glFramebufferRenderbuffer()、glFramebufferTexture*()、glCheckFramebufferStatus()、glDeleteRenderbuffers()、glDeleteFramebuffers()

待辦事項 - 請參閱 [2] 等以獲取程式碼示例

如何...

[編輯 | 編輯原始碼]

配置透視、平移和旋轉物件

[編輯 | 編輯原始碼]

應用模型檢視變換以及世界物件的平移/旋轉必須在頂點著色器中完成。你應該使用一個實用程式庫來執行這些計算。例如,在桌面 OpenGL 幫助方法的文件中描述了數學運算,這些方法在 OpenGL ES 2.0 中被省略。

進一步閱讀

[編輯 | 編輯原始碼]
華夏公益教科書