九、OpenGL ES - 綜合練習

音視頻開發(fā):OpenGL + OpenGL ES + Metal 系列文章匯總

通過GLSL實現(xiàn)金字塔旋轉(zhuǎn)案例,了解索引數(shù)組的使用,以及GLSL實現(xiàn)圖形變換

主要內(nèi)容:

索引數(shù)組的了解
旋轉(zhuǎn)金字塔案例

1、索引數(shù)組的了解

索引繪圖技巧就是指將圖形中的肉眼可見的頂點,通過索引的方式表示頂點之間的連接,將重復頂點復用進行圖形繪制的一種技巧

比如說一個金字塔,共有5個面,我們會將其分成6個三角形(底部有兩個三角形)
這樣我們會創(chuàng)建6個三角形,需要存儲18個頂點。但是金字塔本身其實只有5個頂點,每個頂點都會重復使用。這樣就造成了頂點在內(nèi)存/顯存中重復存儲。
通過索引數(shù)組就可以實現(xiàn)頂點的復用。

圖示:


金字塔.png

可以寫一個數(shù)組存儲其三角形的連接方式
比如:

GLuint indices[] =
{
    0, 3, 2,
    0, 1, 3,
    0, 2, 4,
    0, 4, 1,
    2, 3, 4,
    1, 4, 3,
};

2、金字塔案例

案例地址: 三角形變換案例

效果:

金字塔.gif

2.1 簡單介紹

實現(xiàn)功能:

  1. 繪制金字塔
  2. 金字塔設置顏色
  3. 金字塔旋轉(zhuǎn)

分析如何實現(xiàn):

  1. 繪制金字塔 -- 通過索引數(shù)組組織頂點以構(gòu)建金字塔
  2. 設置顏色 -- 需要傳入色值到片元著色器中
  3. 金字塔旋轉(zhuǎn) -- 傳入視圖模型矩陣和投影矩陣到頂點著色器,在著色器中進行計算。

主要學習:

  1. 索引數(shù)組的使用
  2. 矩陣的使用

實現(xiàn)思路:

具體的GLSL的渲染流程在八、OpenGL ES - GLSL的使用已經(jīng)有足夠詳細的講解
因此本案例只講述新的功能實現(xiàn),重復的內(nèi)容不再說明。

  1. 初始化
    1. 創(chuàng)建圖層
    2. 創(chuàng)建上下文環(huán)境
    3. 清空緩存區(qū)
    4. 設置RenderBuffer、FrameBuffer
  2. 著色器的使用
    1. 著色器程序的編寫
    2. 著色器的編譯
    3. 鏈接到程序?qū)ο笾?/li>
    4. 程序?qū)ο蟮倪B接
    5. 程序?qū)ο蟮拈_啟
  3. 頂點/紋理坐標數(shù)據(jù)的傳遞
    1. 獲取數(shù)據(jù)
    2. 在顯存中創(chuàng)建緩存區(qū)并拷貝數(shù)據(jù)
    3. 獲取傳遞數(shù)據(jù)的通道的ID
    4. 開啟通道ID
    5. 設置數(shù)據(jù)傳遞的方式(也就是獲取緩存區(qū)中的哪部分數(shù)據(jù)來進行傳遞)
  4. 色值的傳遞(新增)
    1. 設置色值
    2. 傳遞色值
  5. 矩陣的傳遞(新增)
    1. 矩陣獲取
    2. 傳遞到頂點著色器
    3. 矩陣計算
  6. 繪圖并渲染上屏
    1. 使用索引繪圖(新增)
    2. 渲染上屏

2.2 色值傳遞

定義色值

//(1)頂點數(shù)組 前3頂點值(x,y,z),后3位顏色值(RGB)
    GLfloat attrArr[] =
    {
        -0.5f, 0.5f, 0.0f,      1.0f, 0.0f, 1.0f, //左上0
        0.5f, 0.5f, 0.0f,       1.0f, 0.0f, 1.0f, //右上1
        -0.5f, -0.5f, 0.0f,     1.0f, 1.0f, 1.0f, //左下2
        
        0.5f, -0.5f, 0.0f,      1.0f, 1.0f, 1.0f, //右下3
        0.0f, 0.0f, 1.0f,       0.0f, 1.0f, 0.0f, //頂點4
    };

色值傳遞:

可以看到設置方式與頂點數(shù)組一毛一樣。

//10.--------處理頂點顏色值-------
    //(1).glGetAttribLocation,用來獲取vertex attribute的入口的.
    //注意:第二參數(shù)字符串必須和shaderv.glsl中的輸入變量:positionColor保持一致
    GLuint positionColor = glGetAttribLocation(self.myProgram, "positionColor");
   
    //(2).設置合適的格式從buffer里面讀取數(shù)據(jù)
    glEnableVertexAttribArray(positionColor);
    
    //(3).設置讀取方式
    //參數(shù)1:index,頂點數(shù)據(jù)的索引
    //參數(shù)2:size,每個頂點屬性的組件數(shù)量,1,2,3,或者4.默認初始值是4.
    //參數(shù)3:type,數(shù)據(jù)中的每個組件的類型,常用的有GL_FLOAT,GL_BYTE,GL_SHORT。默認初始值為GL_FLOAT
    //參數(shù)4:normalized,固定點數(shù)據(jù)值是否應該歸一化,或者直接轉(zhuǎn)換為固定值。(GL_FALSE)
    //參數(shù)5:stride,連續(xù)頂點屬性之間的偏移量,默認為0;
    //參數(shù)6:指定一個指針,指向數(shù)組中的第一個頂點屬性的第一個組件。默認為0
    glVertexAttribPointer(positionColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (float *)NULL + 3);

4.3 矩陣

矩陣計算過程與OpenGL中所學的矩陣的計算一樣,只是這里用到了第三方庫的API。
因此API不需要專門記憶,只要知道過程即可。

通過矩陣對視圖進行變換的過程以及實現(xiàn)可以查看之前的博客 四、OpenGL - 圖形變換

矩陣計算過程

代碼:

float width = self.frame.size.width;
    float height = self.frame.size.height;
    
    //12.創(chuàng)建4 * 4投影矩陣
    KSMatrix4 _projectionMatrix;
    //(1)獲取單元矩陣
    ksMatrixLoadIdentity(&_projectionMatrix);
    //(2)計算縱橫比例 = 長/寬
    float aspect = width / height; //長寬比
    //(3)獲取透視矩陣
    /*
     參數(shù)1:矩陣
     參數(shù)2:視角,度數(shù)為單位
     參數(shù)3:縱橫比
     參數(shù)4:近平面距離
     參數(shù)5:遠平面距離
     參考PPT
     */
    ksPerspective(&_projectionMatrix, 30.0, aspect, 5.0f, 20.0f); //透視變換,視角30°

    //13.創(chuàng)建一個4 * 4 矩陣,模型視圖矩陣
    KSMatrix4 _modelViewMatrix;
    //(1)獲取單元矩陣
    ksMatrixLoadIdentity(&_modelViewMatrix);
    //(2)平移,z軸平移-10
    ksTranslate(&_modelViewMatrix, 0.0, 0.0, -10.0);
    //(3)創(chuàng)建一個4 * 4 矩陣,旋轉(zhuǎn)矩陣
    KSMatrix4 _rotationMatrix;
    //(4)初始化為單元矩陣
    ksMatrixLoadIdentity(&_rotationMatrix);
    //(5)旋轉(zhuǎn)
    ksRotate(&_rotationMatrix, xDegree, 1.0, 0.0, 0.0); //繞X軸
    ksRotate(&_rotationMatrix, yDegree, 0.0, 1.0, 0.0); //繞Y軸
    ksRotate(&_rotationMatrix, zDegree, 0.0, 0.0, 1.0); //繞Z軸
    //(6)把變換矩陣相乘.將_modelViewMatrix矩陣與_rotationMatrix矩陣相乘,結(jié)合到模型視圖
     ksMatrixMultiply(&_modelViewMatrix, &_rotationMatrix, &_modelViewMatrix);

計算過程:

  1. 投影矩陣的創(chuàng)建(參數(shù)也一樣)
  2. 模型視圖的創(chuàng)建,將模式視圖矩陣沿z軸平移-10個距離,這是將觀察者遠離屏幕10個單位距離
  3. 旋轉(zhuǎn)矩陣的創(chuàng)建,并進行旋轉(zhuǎn)
  4. 將模型視圖矩陣叉乘上旋轉(zhuǎn)矩陣得到模型視圖矩陣

上面四步就是為了得到投影矩陣和模型視圖矩陣,而模型視圖矩陣做了兩件事1)將觀察者遠離屏幕10個單位;2)模型視圖矩陣叉乘旋轉(zhuǎn)矩陣。

矩陣傳遞:


//11.找到myProgram中的projectionMatrix、modelViewMatrix 2個矩陣的地址。如果找到則返回地址,否則返回-1,表示沒有找到2個對象。
    GLuint projectionMatrixSlot = glGetUniformLocation(self.myProgram, "projectionMatrix");
    GLuint modelViewMatrixSlot = glGetUniformLocation(self.myProgram, "modelViewMatrix");

//(4)將投影矩陣傳遞到頂點著色器
    /*
     void glUniformMatrix4fv(GLint location,  GLsizei count,  GLboolean transpose,  const GLfloat *value);
     參數(shù)列表:
     location:指要更改的uniform變量的位置
     count:更改矩陣的個數(shù)
     transpose:是否要轉(zhuǎn)置矩陣,并將它作為uniform變量的值。必須為GL_FALSE
     value:執(zhí)行count個元素的指針,用來更新指定uniform變量
     */
    glUniformMatrix4fv(projectionMatrixSlot, 1, GL_FALSE, (GLfloat*)&_projectionMatrix.m[0][0]);
    
    
    //(7)將模型視圖矩陣傳遞到頂點著色器
    /*
     void glUniformMatrix4fv(GLint location,  GLsizei count,  GLboolean transpose,  const GLfloat *value);
     參數(shù)列表:
     location:指要更改的uniform變量的位置
     count:更改矩陣的個數(shù)
     transpose:是否要轉(zhuǎn)置矩陣,并將它作為uniform變量的值。必須為GL_FALSE
     value:執(zhí)行count個元素的指針,用來更新指定uniform變量
     */
    glUniformMatrix4fv(modelViewMatrixSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);

過程:

  1. 先獲取通道ID,注意此時的通道名稱必須要與頂點著色器中的作為通道的字符串變量保持一致。
  2. 使用glUniformMatrix4fv方法傳遞數(shù)據(jù)到著色器中

重要API:

傳遞矩陣到頂點著色器
void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);

參數(shù)列表:
location:指要更改的uniform變量的位置
count:更改矩陣的個數(shù)
transpose:是否要轉(zhuǎn)置矩陣,并將它作為uniform變量的值。必須為GL_FALSE
value:執(zhí)行count個元素的指針,用來更新指定uniform變量

4.4 索引繪圖

索引數(shù)組:
這里的數(shù)組存儲了三角形的連接方式

//(2).索引數(shù)組
    GLuint indices[] =
    {
        0, 3, 2,
        0, 1, 3,
        0, 2, 4,
        0, 4, 1,
        2, 3, 4,
        1, 4, 3,
    };

索引繪圖:

這個API也要記住,用來進行索引繪圖的每個參數(shù)

/*
     void glDrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices);
     參數(shù)列表:
     mode:要呈現(xiàn)的畫圖的模型 
                GL_POINTS
                GL_LINES
                GL_LINE_LOOP
                GL_LINE_STRIP
                GL_TRIANGLES
                GL_TRIANGLE_STRIP
                GL_TRIANGLE_FAN
     count:繪圖個數(shù)
     type:類型
             GL_BYTE
             GL_UNSIGNED_BYTE
             GL_SHORT
             GL_UNSIGNED_SHORT
             GL_INT
             GL_UNSIGNED_INT
     indices:繪制索引數(shù)組

     */
    glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]), GL_UNSIGNED_INT, indices);

4.5 著色器的實現(xiàn)

4.5.1 頂點著色器
attribute vec4 position;//頂點數(shù)組
attribute vec4 positionColor;//顏色數(shù)組

uniform mat4 projectionMatrix;//投影矩陣
uniform mat4 modelViewMatrix;//模型視圖矩陣

varying lowp vec4 varyColor;//需要傳遞到片元著色器的顏色數(shù)組的接收者

void main()
{
    varyColor = positionColor;//賦值到片元著色器中
    
    vec4 vPos;
   
    // 矩陣計算 投影矩陣*模型視圖矩陣*頂點向量
    //4*4 * 4*4 * 4*1
    vPos = projectionMatrix * modelViewMatrix * position;
    gl_Position = vPos;
}

注意:

  1. 著色器中的其他內(nèi)容之前都已經(jīng)熟悉了,這里新增的就是對矩陣的計算。
  2. 在OpenGL中便知道,矩陣需要左乘。
矩陣計算公式.png
4.5.2 片元著色器

接收片元著色器中的色值

varying lowp vec4 varyColor;
void main()
{
    gl_FragColor = varyColor;
}
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容