原語組裝和光柵化

來源:互聯網
上載者:User

一、什麼是原語?

       原語就是可以用glDrawArrays和glDrawElements來進行畫圖的幾何對象。原語由一系列頂點來描述,每個頂點包含位置、顏色、法線和紋理座標。

       原語包括:點、線、三角行。

二、原語類型

1. 三角形原語類型

      1)GL_TRIANGLES:三角形頂點互不重用,如頂點{V0,V1,V2,V3,V4,V5},則描述了2個三角形,三角形頂點分別為:(V0,V1,V2)和(V3,V4,V5)。

      2)GL_TRIANGLE_STRIP:三角形頂點被重用,畫一系列串連的三角形,三角形的最後2個頂點為下一個三角形的前面2個頂點。如頂點{V0,V1,V2,V3,V4},則描述了3個三角形,三角形頂點分別為:(V0,V1,V2),(V2,V1,V3)<注意此順序,應該為逆時針方向> 和 (V2,V3,V4)。

      3)GL_TRIANGLE_FAN:三角形頂點被重用,畫一系列串連的三角形,前面三角形的第1和3個頂點,為後面三角形的第1和2個頂點。如頂點{V0,V1,V2,V3,V4},則描述了3個三角形,三角形頂點分別為:(V0,V1,V2), (V0,V2,V3)和(V0,V3,V4)。

2. 線原語類型

      1)GL_LINES:線的頂點互不重用。如頂點{V0,V1,V2,V3,V4,V5},則描述了3條線,線頂點分別為:(V0,V1),(V2,V3)和 (V4,V5)。

      2)GL_LINE_STRIP:線的頂點被重用,前麵線的最後一個頂點為下一條線的第一個頂點。如頂點{V0,V1,V2,V3},則描述了3條線,線頂點分別為:(V0,V1),(V1,V2)和 (V2,V3)。

      3)GL_LINE_LOOP:線的頂點被重用,與GL_LINE_STRIP類似,只是最後一條線的最後一個頂點與第一條線的第一個頂點相連。如頂點{V0,V1,V2,V3,V4},則描述了5條線,線頂點分別為:(V0,V1), (V1,V2), (V2,V3), (V3,V4)和 (V4,V0)。

      線的寬度可以通過函數“void glLineWidth(GLfloat width)”來設定。

3. 頂點原語

       GL_POINTS:對每個頂點進行畫圖。

       註:視窗座標(0,0)位於視窗左下角。而點的座標(0,0)位於視窗左上方。

       gl_PointSize是Vertex Shader中的一個內嵌變數,gl_PointCoord是Fragment Shader中的一個內嵌變數,其值取值範圍為:[0.0,1.0],並且從左至右或從上到下地增加。

三、畫圖原語

       OpenGL ES 2.0有以下兩個畫圖原語:

       1)glDrawArrays

       2)glDrawElements.

1. glDrawArrays

     void glDrawArrays(GLenum mode, GLint first, GLsizei count)
     • mode:指定要畫的原語類型,有效值如下:
                GL_POINTS
                GL_LINES
                GL_LINE_STRIP
                GL_LINE_LOOP
                GL_TRIANGLES
                GL_TRIANGLE_STRIP
                GL_TRIANGLE_FAN

     • first:起始頂點在enabled vertex arrays中的索引

     • count:將被用於畫圖的頂點個數

     舉例:glDrawArrays(GL_TRIANGLES, 0, 6)畫了兩個三角形,頂點的頂點數組索引分別為:(0, 1, 2)和(3, 4, 5)。

2. glDrawElements

    void glDrawElements(GLenum mode, GLsizei count,GLenum type, const GLvoid *indices)
    • mode:指定要畫的原語類型,有效值如下:
                GL_POINTS
                GL_LINES
                GL_LINE_STRIP
                GL_LINE_LOOP
                GL_TRIANGLES
                GL_TRIANGLE_STRIP
                GL_TRIANGLE_FAN

    • count:指示在*indices中的頂點索引個數

       • type:指示在*indices中元素資料類型,有效值如下:

                GL_UNSIGNED_BYTE
                GL_UNSIGNED_SHORT
                GL_UNSIGNED_INT(可選,只有OES_element_index_uint擴充被實現時,才可使用)

    • indices:儲存頂點索引的數組或指標

3. glDrawArrays &glDrawElements各自用武之地

        如果Enbaled Vertex Array中的頂點不被多個原語所共用,則使用glDrawArrays較高效,因為省去了頂點索引數組;否則使用glDrawElements高效,因為同一個頂點在Enabled Vertex Array中只有一份資料,不存在多個資料copy,節省了記憶體空間。

        舉例如下(畫一個立方體):

1) 使用glDrawArrays的代碼如下:

#define VERTEX_POS_INDX 0#define NUM_FACES 6GLfloat vertices[] = { … }; // (x, y, z) per vertexglEnableVertexAttribArray(VERTEX_POS_INDX);glVertexAttribPointer(VERTEX_POS_INDX, 3, GL_FLOAT, GL_FALSE,0, vertices);for (i=0; i<NUM_FACES; i++){    glDrawArrays(GL_TRIANGLE_FAN, first, 4);    first += 4;}//or glDrawArrays(GL_TRIANGLES, 0, 36);

註:總共8個頂點,卻儲存了24個頂點或36個頂點的資料。

2)使用glDrawElements的代碼如下:

#define VERTEX_POS_INDX 0GLfloat vertices[] = { … };// (x, y, z) per vertexGLubyte indices[36] = { 0, 1, 2, 0, 2, 3,                        0, 3, 4, 0, 4, 5,                        0, 5, 6, 0, 6, 1,                        7, 6, 1, 7, 1, 2,                        7, 4, 5, 7, 5, 6,                        7, 2, 3, 7, 3, 4 };glEnableVertexAttribArray(VERTEX_POS_INDX);glVertexAttribPointer(VERTEX_POS_INDX, 3, GL_FLOAT, GL_FALSE,0, vertices);glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(GLubyte),GL_UNSIGNED_BYTE, indices);

4. 總結

       只要有頂點重用,使用glDrawElements 的效能比glDrawArrays要好,因為不僅CPU與GPU之間傳遞資料的記憶體頻寬更小,且在GPU中佔用的記憶體也更少。

四、原語組裝(Primitive Assembly)

       OpenGL ES 2.0原語組裝階段如所示:

1. 座標系統

2. 裁剪體(clip volume)

    裁剪體由近、遠、左、右、上、下共6個裁剪面組成。如所示:

      在clipping階段,每個原語都被裁剪體進行裁剪。並對每種原語執行如下操作來進行裁剪:

      1)Clipping triangles

            • 如果全部在裁剪體內,什麼都不做

            • 如果全部不在裁剪體內,則丟棄

            • 如果部分在裁剪體內,則產生新的頂點並形成三角形FAN

      2)Clipping lines 

            • 如果全部在裁剪體內,什麼都不做

            • 如果全部不在裁剪體內,則丟棄

            • 如果部分在裁剪體內,則產生新的頂點並形成新的LINE

      3)Clipping point sprites

            • 如果全部在裁剪體內,什麼都不做

            • 如果全部不在裁剪體內,則丟棄

3. 透視除法(PerspectiveDivision) 

        它的目標是把裁剪座標變為歸一化裝置座標,其取值範圍為:[-1,1]。其實現方法為把座標的每個分量除以Wc。裁剪座標(Xc,Yc,Zc,Wc) 經過透視除法(Xc/Wc),(Yc/Wc),(Zc/Wc)則變成了歸一化裝置座標(Xd,Yd,Zd)。

4. 視口變換(Viewport Transformation)

        它把歸一化裝置座標(Xd,Yd,Zd)變換為視窗座標或螢幕座標(Xw,Yw,Zw)。

1)視口變換視口通過以下API設定:

        void glViewport(GLint x, GLint y, GLsizei w, GLsizei h)
        • x, y:指明視口左下角螢幕座標(以像素為單位)

        • w, h:指明視口的寬度和高度(以像素為單位)     

2)視口變換深度通過以下API設定:    

        void glDepthRange(GLclampf n, GLclampf f)
        • n, f:指明要求的深度範圍。預設值:n=0.0,f=1.0,值的範圍為[0.0,1.0]。         

3)視口變換方法為:

      Ox = (x + w)/2,Oy = (y + h)/2,n 和 f 表示要求的深度範圍。

  
五、光柵化(Rasterization)

        光柵化擷取每個原語(如:點、線、三角形),然後為這個原語產生合適的Fragment。一個Fragment表示在螢幕空間中的一個像素位置(x,y),且fragment資料將被Fragment Shader處理以產生一個Fragment Color。

 六、選擇(Culling)

        在三角形被光柵化之前,我需要確定哪些面對觀察者,哪些面背對觀察者。Culling操作丟棄哪些背對觀察者的面,從而光柵化這些看不見的三角形,從而節約了GPU的時間,並提高了GPU的效能。相關函數如下:   

        1)void glFrontFace(GLenum dir)
        • dir:指示面對觀察者的三角形的方向(GL_CW<順時針>或GL_CCW<逆時針>),預設值為:GL_CCW。

                  CW: Clockwise,CCW:Counter-Clockwise

        2)void glCullFace(GLenum mode)

        • mode:指示三角形的哪個面被選擇(GL_FRONT、GL_BACK、GL_FRONT_AND_BACK),預設值是GL_BACK。

        3)void glEnable(GLenum cap)
              void glDisable(GLenum cap)
        • cap:設定為GL_CULL_FACE,初始時,Culling被disabled掉了。

 

 

 

 

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.