图元装配和光栅化
轉載請以鏈接形式標明出處:
本文出自:103style的博客
OpenGL ES 3.0學習匯總
- OpenGL ES 3.0 學習記錄匯總
目錄
本文主要介紹:
- OpenGL ES支持的 圖元 和 幾何形狀對象 的類型,以及它們的繪制方法。
- OpenGL ES 圖形管線 頂點著色器 之后的 圖元裝配 階段。
- OpenGL ES 圖形管線的 光柵化 階段。
圖元
圖元可以用 glDrawArrays、glDrawElements、glDrawRangeElements、glDrawArraysInstanced、glDrawElementsInstanced 命令繪制的幾何形狀對象。
OpenGL ES 3.0 可以繪制以下圖元:
- 三角形
- 直線
- 點精靈
三角形
OpenGL ES 支持的三角形圖元有 GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN。
以下為對應的示例:
- GL_TRIANGLES :繪制一系列單獨的三角形。
在上圖中繪制了頂點為 (V0,V1,V2)、(V3,V4,V5) 兩個三角形。
總共繪制了 n / 3 個三角形,n 為 glDraw*** API中 Count 指定的索引。 - GL_TRIANGLE_STRIP :繪制一系列相互連接的三角形。
在上圖中繪制了頂點為 (V0,V1,V2)、(V2,V1,V3) 注意順序、(V2,V3,V4) 三個三角形。
總共繪制了 n - 2 個三角形,n 為 glDraw*** API中 Count 指定的索引。 - GL_TRIANGLE_FAN :繪制一系列相連的三角形。
在上圖中繪制了頂點為**(V0,V1,V2)、(V0,V2,V3)、(V0,V3,V4)** 三個三角形。
總共繪制了 n - 2 個三角形,n 為 glDraw*** API中 Count 指定的索引。
直線
OpenGL ES支持的直線圖元有 GL_LINES、GL_LINE_STRIP、GL_LINE_LOOP。
-
GL_LINES :繪制一系列不相連的線段。
在上圖中繪制了端點為 (V0,V1)、(V2,V3) 、(V4,V5) 的單獨線段。
總共繪制了 n / 2 個線段,n 為 glDraw*** API中 Count 指定的索引。 -
GL_LINE_STRIP :繪制一系列相連的線段。
在上圖中繪制了3條端點為 (V0,V1)、(V1,V2)、(V2,V3) 的線段。
總共繪制了 n - 1 個線段,n 為 glDraw*** API中 Count 指定的索引。 -
GL_LINE_LOOP :除了最后一條線段之外,和 GL_LINE_STRIP 類似。
在上圖中繪制了端點為**(V0,V1、(V1,V2)、(V2,V4)、(V3,V4)和(V4,V0)** 的線段。
總共繪制了 n 條線段,n 為 glDraw*** API中 Count 指定的索引。
線段的寬度可以用 glLineWidth
void glLineWidth(GLfloat width)width : 指定線寬,以像素表示width 受限與OpenGL ES 3.0 支持的線寬范圍, 可通過以下代碼查詢:
GLfloat lineWidthRange[2]; glGetFloatv(GL_ALIASED_LINE_WIDTH_SIZE, lineWidthRange);點精靈
OpenGL ES支持的點精靈圖元是 GL_POINTS。 點精靈對指定的每個頂點繪制。通常用于粒子效果當作點而非正方形繪制,從而實現高效渲染。
點精靈 是 指定位置和半徑的屏幕對齊的正方形。
gl_PointSize 是用于頂點著色器中 輸出點半徑 的內建變量。同樣也受到OpenGL ES 3.0實現所支持的非平滑點尺寸范圍限制,可通過以下代碼查詢:
OpenGL ES 3.0 將窗口的 左下 視為 原點區域, 而 點精靈 的原點為 左上。
gl_PointCoord 是 片段著色器 只為 點精靈 構建的 內建變量。用 mediump 聲明為一個 vec2 變量。賦值范圍為 [0,1]。
以下代碼為 繪制一個帶有紋理的點精靈:
#version 300 es percision mediump float; uniform sampler2D s_texSprite; layout(location = 0) out vec4 outColor; void main() {outColor = texture(s_texSprite, gl_PointCoord); }繪制圖元
在上文中我們講到 圖元可以用 glDrawArrays、glDrawElements、glDrawRangeElements、glDrawArraysInstanced、glDrawElementsInstanced 命令繪制的幾何形狀對象。
glDrawArrays 是 用元素索引為 first 到 first + count - 1的元素指定的頂點繪制mode對應的圖元。
void glDrawArrays(Glenum mode,GLint first, GLsizei count)mode : 三角行、直線、點精靈對應的7種模式 first : 繪制的第一個頂點的索引 count : 一共繪制的頂點數量 void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) void glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices)mode : 三角行、直線、點精靈對應的7種模式 start : 指定indices最小的數組索引 end : 指定indices最大 的數組索引 count : 指定要繪制的索引數量 type : GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT、GL_UNSIGNED_INT indices : 指向元素索引儲存位置的指針繪制立方體,如果是一系列順序元素索引描述的圖元,用glDrawArrays ,否則用glDrawElements。
- glDrawArrays#version 300 es #define VERTEX_POS_INDX 0 #define NUM_FACES 6GLfloat vertices[] = {...}; // 頂點坐標 glEnableVertexAttribArray(VERTEX_POS_INDX); glVertexAttribPointer(VERTEX_POS_INDX, 3, GL_FLOAT, GL_FLASE, 0, vertices); for(int i = 0; i < NUM_FACES; i++){glDrawArrays(GL_TRIANGLES, i * 4, 4); }
- glDrawElements #version 300 es#define VERTEX_POS_INDX 0GLfloat vertices[] = {...}; // 頂點坐標GLubyte indices[36] = {0, 1, 2, 0, 2, 30, 3, 4, 0, 4, 5,0, 5, 6, 0, 6, 1,7, 1, 6, 7, 2, 1,7, 5, 4, 7, 6, 5,7, 3, 2, 7, 4, 3 };glEnableVertexAttribArray(VERTEX_POS_INDX);glVertexAttribPointer(VERTEX_POS_INDX, 3, GL_FLOAT, GL_FLASE, 0, vertices);glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);
圖元重啟
使用圖元重啟 可以 在一次繪圖調用中渲染多個不相連的圖元,這對調用繪圖API的開銷來說是有利的。
圖元重啟還有一個相對復雜的方法就是 生成退化三角形.
使用圖元重啟,可以 通過在索引列表中插入一個特殊索引來重啟一個用于索引繪圖調用(glDraw***)的圖元,這個 特殊索引 就是該索引類型的 最大可能索引。
例如:假設三個 三角形條帶(GL_TRIANGLE_STRIP)分別有元素索引(0,1,2,3)和(8,9,10,11),如果想用圖元重啟來一次調用繪制兩個條帶,索引類型為GL_UNSIGNED_BYTE,則組合的索引列表為(1,2,3,4,255,8,9,10,11)。
可以通過如下代碼 啟用或者禁用 圖元重啟。
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); ... glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);驅動頂點
如果沒有限定符,那么頂點著色器的輸出值在圖元中使用線性插值。但是使用 平面著色 時沒有發生插值,所以片段著色器中只有一個頂點值可以用。
以下時驅動頂點選擇的規則:
| GL_POINTS | i |
| GL_LINES | 2i |
| GL_LINE_LOOP | 如果i < n,為 n+1;如果i = n,為 1 |
| GL_LINE_STRIP | i + 1 |
| GL_TRIANGLES | 3i |
| GL_TRIANGLE_STRIP | i + 2 |
| GL_TRIANGEL_FAN | i + 2 |
幾何形狀實例化
幾何形狀實例化很高效,可以用一次API調用多次渲染具有不同屬性的一個對象,在渲染大量類似對象時很有用,例如對人群的渲染。
幾何形狀實例化降低了向OpenGL ES引擎發送許多API調用的CPU處理開銷。
可以使用以下命令,用幾何形狀實例化繪圖調用渲染:
void glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) void glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instanceCount)mode : 三角形、直線、點精靈對應的七種模式 first : 啟用的點點數組中的起始頂點索引 count : 繪制的索引數量 type : 指定保存在indices中的元素索引類型(GL_UNSIGNED_BYTE,GL_UNSIGNED_SHORT,GL_UNSIGNED_INT) indices : 元素索引儲存位置的一個指針 instaceCount : 繪制的圖元實例數量可以使用兩種方法訪問每個實例的數據。
- 用如下命令指示OpenGL ES 對每個實例讀取一次或者多次頂點屬性:void glVertexAttribDivisor(GLuint index,GLuint divisior)index : 通用頂點屬性索引 dicisior : index位置的通用屬性更新之間傳遞的實例數量 默認情況下,如果沒有指定glVertexAttribDivisor 或者頂點屬性的 divisior = 0,對每個頂點將讀取一次頂點屬性。如果 divisior = 1,則每個圖元實例讀取一次頂點屬性。
- 使用內建輸入變量 gl_InstanceID作為頂帶著色器中的緩沖區索引,以訪問每個實例的數據。如果繪制API時,gl_InstanceID將保存當前圖元實例的索引。使用非實例化繪圖調用時,gl_InstanceID將返回0。
下面兩個代碼片說明如何用一次實例化繪圖調用繪制多個幾何形狀,其中每個實例的顏色不同。
#include "esUtil.h" #include<stdlib.h> #include<math.h>#ifdef _WIN32 #define srandom srand #define random rand #endif // _WIN32#define NUM_INSTANCES 100 #define POSITION_LOC 0 #define COLOR_LOC 1 #define MVP_LOC 2typedef struct {//著色器程序GLuint programObject;//頂點緩沖區對象GLuint positionVBO;GLuint colorVBO;GLuint mvpVBO;GLuint indicesIBO;//索引數量int numIndices;//旋轉角度GLfloat angle[NUM_INSTANCES];} UserData;int _Init(ESContext *esContext) {GLfloat *positions;GLuint *indices;UserData *userData = esContext->userData;//頂點著色器源代碼const char vShaderStr[] = "#version 300 es \n""layout(location = 0) in vec4 a_position; \n""layout(location = 1) in vec4 a_color; \n""layout(location = 2) in mat4 a_mvpMatix; \n""out vec4 v_color; \n""void main() \n""{ \n"" v_color = a_color; \n"" gl_Postion = a_postion * a_mvpMatrix; \n""} \n";const char fShaderStr[] = "#version 300 es \n""precision mediump float; \n""in vec4 v_color; \n""layout(location = 0) out vec4 outColor; \n""void main() \n""{ \n"" outColot = v_color; \n""}";//編譯著色器代碼并鏈接到著色器程序userData->programObject = esLoadProgram(vShaderStr, fShaderStr);//生成數組數據userData->numIndices = esGenCube(0.1f, &positions, NULL, NULL, &indices);//索引緩沖區對象glGenBuffers(1, userData->indicesIBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->indicesIBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * userData->numIndices, indices, GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);free(indices);//位置緩沖區對象glGenBuffers(1, userData->positionVBO);glBindBuffer(GL_ARRAY_BUFFER, userData->positionVBO);glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(GLfloat) * 3, positions, GL_STATIC_DRAW);free(positions);//對每個實例生成隨機顏色{GLubyte colors[NUM_INSTANCES][4];int instace;srand(0);for (instace = 0; instace < NUM_INSTANCES; instace++){colors[instace][0] = random() % 255;colors[instace][1] = random() % 255;colors[instace][2] = random() % 255;colors[instace][3] = 0;}glGenBuffers(1, userData->colorVBO);glBindBuffer(GL_ARRAY_BUFFER, userData->colorVBO);glBufferData(GL_ARRAY_BUFFER, NUM_INSTANCES * 4, colors, GL_STATIC_DRAW);}//分配儲存空間保存每個 變換矩陣 實例{int instace;for (instace = 0; instace < NUM_INSTANCES; instace++){userData->angle[instace] = (float)(random() % 32768) / 32767.0f * 360.0f;}glGenBuffers(1, userData->mvpVBO);glBindBuffer(GL_ARRAY_BUFFER, userData->mvpVBO);glBufferData(GL_ARRAY_BUFFER, NUM_INSTANCES * sizeof(ESMatrix), NULL, GL_DYNAMIC_DRAW);}glBindBuffer(GL_ARRAY_BUFFER, 0);glClearColor(1.0f, 1.0f, 1.0f, 1.0f);return GL_TRUE; }//根據時間增量更新 變換矩陣 void Update(ESContext *esContext, float deltaTime) {UserData *userData = esContext->userData;ESMatrix *matrixBuf;ESMatrix perspective;float aspect;int instance = 0;int numRows;int numColumn;//計算窗口的寬高比aspect = (GLfloat)esContext->width / (GLfloat)esContext->height;esMatrixLoadIdentity(&perspective);esPerspective(&perspective, 60.0f, aspect, 1.0f, 20.0f);glBindBuffer(GL_ARRAY_BUFFER, userData->mvpVBO);matrixBuf = (ESMatrix *)glMapBufferRange(GL_ARRAY_BUFFER, 0, sizeof(ESMatrix) * NUM_INSTANCES, GL_MAP_WRITE_BIT);numRows = (int)sqrtf(NUM_INSTANCES);numColumn = numRows;for (instance = 0; instance < NUM_INSTANCES; instance++){ESMatrix modelview;float translateX = ((float)(instance % numRows) / (float)numRows)*2.0f - 1.0f;float translateY = ((float)(instance / numColumn) / (float)numColumn) * 2.0f - 1.0f;esMatrixLoadIdentity(&modelview);esTranslate(&modelview, translateX, translateY, -2.0f);userData->angle[instance] += (deltaTime * 40.0f);if (userData->angle[instance] >= 360.0f){userData->angle[instance] -= 360.0f;}//旋轉立方體esRotate(&modelview, userData->angle[instance], 1.0, 0.0, 1.0);esMatrixMultiply(&matrixBuf[instance], &modelview, &perspective);}glUnmapBuffer(GL_ARRAY_BUFFER); }void Draw(ESContext *esContext) {UserData *userData = esContext->userData;//設置窗口glViewport(0, 0, esContext->width, esContext->height);//清空顏色glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//鏈接著色器程序glUseProgram(userData->programObject);//加載頂點坐標glBindBuffer(GL_ARRAY_BUFFER, userData->positionVBO);glVertexAttribPointer(POSITION_LOC, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (const void *)NULL);glEnableVertexAttribArray(POSITION_LOC);//加載實例顏色緩沖區glBindBuffer(GL_ARRAY_BUFFER, userData->colorVBO);glVertexAttribPointer(COLOR_LOC, 4, GL_UNSIGNED_BYTE, GL_TRUE, 4 * sizeof(GLubyte), (const void *)NULL);glEnableVertexAttribArray(COLOR_LOC);glVertexAttribDivisor(COLOR_LOC, 1);//加載實例 變換矩陣 緩沖區glBindBuffer(GL_ARRAY_BUFFER, userData->mvpVBO);//加載矩陣的每一行glVertexAttribPointer(MVP_LOC + 0, 4, GL_FLOAT, GL_FALSE, sizeof(ESMatrix), (const void *)NULL);glVertexAttribPointer(MVP_LOC + 1, 4, GL_FLOAT, GL_FALSE, sizeof(ESMatrix), (const void *)(sizeof(GLfloat) * 4));glVertexAttribPointer(MVP_LOC + 1, 4, GL_FLOAT, GL_FALSE, sizeof(ESMatrix), (const void *)(sizeof(GLfloat) * 8));glVertexAttribPointer(MVP_LOC + 1, 4, GL_FLOAT, GL_FALSE, sizeof(ESMatrix), (const void *)(sizeof(GLfloat) * 12));glEnableVertexAttribArray(MVP_LOC + 0);glEnableVertexAttribArray(MVP_LOC + 1);glEnableVertexAttribArray(MVP_LOC + 2);glEnableVertexAttribArray(MVP_LOC + 3);glVertexAttribDivisor(MVP_LOC + 0, 1);glVertexAttribDivisor(MVP_LOC + 1, 1);glVertexAttribDivisor(MVP_LOC + 2, 1);glVertexAttribDivisor(MVP_LOC + 3, 1);//綁定索引緩沖數據glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->indicesIBO);//繪制立方體glDrawElementsInstanced(GL_TRIANGLES, userData->numIndices, GL_UNSIGNED_INT, (const void *)NULL, NUM_INSTANCES); }void Shutdown(ESContext *esContext) {UserData *userData = esContext->userData;glDeleteBuffers(1, userData->positionVBO);glDeleteBuffers(1, userData->colorVBO);glDeleteBuffers(1, userData->mvpVBO);glDeleteBuffers(1, userData->indicesIBO);//刪除著色器程序glDeleteProgram(userData->programObject); }int esMain(ESContext *esContext) {esContext->userData = malloc(sizeof(UserData));esCreateWindow(esContext, "Instancing", 640, 480, ES_WINDOW_RGB | ES_WINDOW_DEPTH);if (!_Init(esContext)){return GL_FALSE;}esRegisterShutdownFunc(esContext, Shutdown);esRegisterUpdateFunc(esContext, Update);esRegisterDrawFunc(esContext, Draw);return GL_TRUE; }運行參考 將 Instancing 設為啟動項目,運行報錯,看報錯提示,筆者是提示 Init 函數名的問題,所以修改為 _Init。
性能提示
應用程序應該用 盡可能大的圖元尺寸 調用 glDrawElements 和 glDrawElementsInstanced。
如果繪制帶有 三角形條帶(GL_TRIANGLE_STRIP)或者 扇形(GL_TRIANGLE_FAN)的網格,則可以啟用 圖元重啟 將這些網格連接在一起,而不是單獨調用glDrawElements。
當無法用 圖元重啟 將網格連接在一起時,可以添加造成退化三角形的元素索引,代價時使用更多的索引。
退化三角形 是指 兩個頂點或者更多頂點相同 的三角形。
為了連接不同網格而添加的 元素索引(或者退化三角形)數量取決與每個網格是三角扇形還是三角形條帶以及每個條帶中定義的索引數量。
三角形條帶網格的索引數量很重要,因為我們必須保留從跨越連接起來的不同網格的條帶的一個三角形到下一個三角形的彎曲順序。
連接不同的三角形條帶時,我們需要檢查兩個相互連接的條帶的最后一個三角形和第一個三角形的順序。
有以下兩種情況需要處理:
- 第一個三角形條帶的奇數編號的三角形 連接到 第二個三角形條帶的第一個(因而是偶數編號的)三角形。
- 第一個三角形條帶的偶數編號的三角形 連接到 第二個三角形條帶的第一個(因而是偶數編號的)三角形。
下圖為兩種情況下的三角形條帶。
對于上圖 相反的頂點順序,如果我們調用glDrawElements*** 繪制兩個條帶,
組合的元素索引列表為(0,1,2,3,3,8,8,9,10,10),粗體的表示組合元素索引添加的新索引。
將繪制(0,1,2)、(2,1,3)、(2,3,3)、(3,3,8)、(3,8,8)、(8,8,9)、(8,9,10)、(10,9,11)這些三角形,粗體的表示退化三角形。
對于 相同頂點順序,如果我們調用glDrawElements*** 繪制兩個條帶,
組合的元素索引列表為(0,1,2,3,4,4,8,8,9,10,10),粗體的表示組合元素索引添加的新索引。
將繪制(0,1,2)、(2,1,3)、(2,3,4)、(4,3,4)、(4,4,4)、(4,4,8)、(4,8,8)、(8,8,9)、(8,9,10)、(10,9,11)這些三角形,粗體的表示退化三角形。
添加的新索引數量 和 生成退化三角形的數量 取決于 第一個三角形條帶的 頂點數量。必須保留下一個連接條帶的彎曲順序。
圖元裝配
通過 glDraw*** 提供的頂點由頂點著色器執行,頂點著色器變換的每個頂點包括描述頂點(x,y,z,w)值的頂點位置。圖元類型和頂點確定將被渲染的單獨圖元,對于每個單獨圖元及對應的頂點將執行下圖的操作。
下圖展示了 圖元裝配階段。
坐標系統
下圖展示了頂點通過頂點著色器和圖元裝配階段時的坐標系統。
頂點以物體或者本地坐標空間 輸入到OpenGL ES,在頂點著色器執行后,頂點位置被認定為在裁剪坐標空間內。
頂點位置從本地坐標系統到裁剪坐標的變換通過加載執行這一轉換的對應矩陣來完成。
-
裁剪
避免處理可視景體之外的圖元,圖元被裁剪到裁剪空間。在裁剪空間定義的頂點坐標根據 視景體(或稱 裁剪體)裁剪,裁剪體由6個裁剪平面定義。
裁剪操作:- 裁剪三角形——全部在內不裁剪,全部在外則拋棄,部分在內則根據裁剪平面裁剪三角形,裁剪之后生成新的頂點成為三角扇形的平面。
- 裁剪直線——全部在內不裁剪,全部在外則拋棄,部分在內裁剪之后生成新的頂點。
- 裁剪點精靈——如果點位置在近或者遠裁剪平面之外,或者點精靈的正方形在裁剪體之外,裁剪階段則拋棄點精靈,否則將通過不做變化通過該階段,點精靈將在其從裁剪體內部移動外部時裁剪,反之亦然。
在圖元根據六個裁剪平面進行裁剪時,頂點坐標經歷 透視分割,從而成為規范化的設備坐標,范圍為[-1.0,1.0].
-
視口變換
void glViewport(GLint x, GLint y, GLsizei w, GLsizei h)x,y : 指定視口左下角的窗口坐標,以像素數表示 w,h : 指定視口的寬度和高度,值必須大于0
視口是一個二維矩形窗口區域,是OpenGL ES 渲染操作最終顯示的地方。從規范化設備坐標轉換到窗口坐標用如下變換:
[XwYwZw]=[(w/2)Xd+Ox(h/2)Yd+Oy((f?n)/2)Zd+(n+f)/2]\left[ \begin{matrix} Xw\\ Yw\\ Zw \end{matrix} \right] = \left[ \begin{matrix} (w / 2)Xd + Ox\\ (h / 2)Yd + Oy \\ ((f - n) / 2)Zd + (n+ f) / 2 \end{matrix} \right] ???XwYwZw????=???(w/2)Xd+Ox(h/2)Yd+Oy((f?n)/2)Zd+(n+f)/2????深度范圍值n和f可以用如下API調用設置:
void glDepthRangef(GLclampf n, GLclampf f)n,f 指定所需的深度范圍。 n,f的默認值為 0.0 和 1.0,兩值的范圍為`[0.0 ,1.0]`。
光柵化
剔除
在三角新被光柵化之前,我們需要確定它們是正面(面向觀看者)還是背面(背向觀看者)。
剔除操作就是 拋棄背向觀看者的三角形。
如何確定三角形的方向:看對應三角形一詞的頂點方向是 順時針(CW)還是逆時針(CCW)。
三角形的方向通過以窗口坐標表示的有符號的三角形的面積來計算。
API如下:
可以通過以下API確定要剔除的三角形
void glCullFace(GLenum mode)mode : 指定要被剔除的三角形的面。 有效值為GL_FRONT,GL_BACK、GL_FRONT_AND_BACK,默認為GL_BACK。最后,可以通過以下API確認剔除操作是否應該執行,如果GL_CULL_FACE被啟用,剔除則執行。
void glEnable(GLenum cap) void glDisable(GLenum cap)cap : 設置為GL_CULL_FACE,默認情況下剔除被禁用所以,要剔除合適的三角形,需要:
- 調用glEnable(GL_CULL_FACE)啟用剔除。
- 調用glCullFace設置相應的剔除面。
- 調用glFrontFace設置正面三角形方向。
多邊形偏移
考慮到相互重疊的多邊形的情況,你可能注意到偽像,如被稱為 深度偽像 的是因為三角形 光柵化的精度有限 而發生的,這種精度可能影響到 逐片段操作 生成的深度值的精度,造成偽像。
以下展示了不使用多邊形偏移繪制這兩個共面多邊形的代碼。
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//設置頂點屬性狀態 ...glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glDepthFunc(GL_LEQUAL);//設置頂點屬性狀態 ...glDrawArrays(GL_TRIANGLE_FAN, 0, 4);為了避免偽像,我們需要執行 深度測試 和 深度值寫入深度緩沖區 之前,在計算出來的深度值上添加一個偏移量。 所以 如果通過深度測試,原始的深度值 將被保存到 深度緩沖區 中,而不是 深度值+偏移 。
可通過如下API設置偏移量,也可以通過glEnable(GL_POLYGON_OFFSET_FILL)和glDisable(GL_POLYGON_OFFSET_FILL)啟用或者禁用多邊形偏移
void glPolygonOffset(GLfloat factor, GLfloat units)計算偏移的公式是: 深度偏移 = m * 因數 + r * 單位數
m : 三角形的最大深度斜率 。
r : OpenGL ES 實現定義的常量。
以下是啟用多邊形偏移渲染三角形的代碼
const float polygonOffsetFactor = -1.0f; const float polygonOffsetUnits = -2.0f;glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //加載頂點著色器 ...glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glDepthFunc(GL_LEQUAL);glEnable(GL_POLYGON_OFFSET_FILL);glPolygonOffset(polygonOffsetFactor, polygonOffsetUnits);glDrawArrays(GL_TRIANFLE_FAN,0, 4);遮擋查詢
用來查詢對象來跟蹤通過深度測試的任何片段或者樣本。
遮擋查詢分別在 GL_ANY_SAMPLES_PASSED或GL_ANY_SAMPLES_PASSED_CONSERVATIVE目標上用 glBeginQuery 和 glEndQuery 開始和結束。
小結
- 學習了OpenGL ES支持的圖元類型
- 了解了如何用常規的非實例化和實例化繪圖調用高效的繪制它們
- 在頂點上執行坐標轉換的方法
- 光柵化相關的知識
總結
- 上一篇: 74位图灵奖得主背景显示:大多数没有主修
- 下一篇: 小型直播系统系列-乐聊TV的开发(一)