學(xué)習(xí)OpenGL ES之繪制三角形

本系列所有文章目錄

獲取示例代碼


- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    ...

    // 使用fragment.glsl 和 vertex.glsl中的shader
    glUseProgram(self.shaderProgram);
    [self drawTriangle];
}

- (void)drawTriangle {
    static GLfloat triangleData[18] = {
        0,      0.5f,  0,  1,  0,  0, // x, y, z, r, g, b,每一行存儲一個點的信息皿渗,位置和顏色
        -0.5f, -0.5f,  0,  0,  1,  0,
        0.5f,  -0.5f,  0,  0,  0,  1,
    };
    
    // 啟用Shader中的兩個屬性
    // attribute vec4 position;
    // attribute vec4 color;
    GLuint positionAttribLocation = glGetAttribLocation(self.shaderProgram, "position");
    glEnableVertexAttribArray(positionAttribLocation);
    GLuint colorAttribLocation = glGetAttribLocation(self.shaderProgram, "color");
    glEnableVertexAttribArray(colorAttribLocation);
    
    // 為shader中的position和color賦值
    // glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
    // indx: 上面Get到的Location
    // size: 有幾個類型為type的數(shù)據(jù),比如位置有x,y,z三個GLfloat元素粥航,值就為3
    // type: 一般就是數(shù)組里元素數(shù)據(jù)的類型
    // normalized: 暫時用不上
    // stride: 每一個點包含幾個byte仙逻,本例中就是6個GLfloat竟宋,x,y,z,r,g,b
    // ptr: 數(shù)據(jù)開始的指針逻卖,位置就是從頭開始,顏色則跳過3個GLFloat的大小
    glVertexAttribPointer(positionAttribLocation, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (char *)triangleData);
    glVertexAttribPointer(colorAttribLocation, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (char *)triangleData + 3 * sizeof(GLfloat));
    
    glDrawArrays(GL_TRIANGLES, 0, 3);
}

在上篇文章的基礎(chǔ)上我們增加了- (void)drawTriangle欺缘。效果如下

在解釋代碼之前我們先來了解一下OpenGL渲染的基本流程栋豫。


從圖中可以看出,最開始的輸入是頂點數(shù)據(jù)谚殊。比如三角形丧鸯,就是三個點。每個頂點數(shù)據(jù)可以包含任意數(shù)量的信息嫩絮,最基本的有位置丛肢,顏色。后面介紹貼圖時還會包含UV信息剿干。經(jīng)過各種處理蜂怎,最終放入FrameBuffer,就是上一篇文章說的緩沖區(qū)置尔。接下來我們按照這個流程解釋繪制的代碼杠步。

第一步,提供 Vertex Data

 static GLfloat triangleData[18] = {
        0,      0.5f,  0,  1,  0,  0, // x, y, z, r, g, b,每一行存儲一個點的信息,位置和顏色
        -0.5f, -0.5f,  0,  0,  1,  0,
        0.5f,  -0.5f,  0,  0,  0,  1,
    };

我們要繪制的是一個三角形幽歼,三角形有3個點朵锣,每個點我希望包含位置信息和顏色信息,至于兩點之間的顏色如何甸私,我們不關(guān)心诚些,OpenGL ES會處理。綜上皇型,我們?yōu)槊恳粋€點分配6個GLfloat大小的空間诬烹,前三個存儲位置x,y,z,后三個存儲顏色r,g,b弃鸦。三個點就是18個GLfloat的數(shù)組绞吁。

使用GLfloat而不是float是為了跨平臺,保證不同平臺的GLfloat占用的字節(jié)數(shù)都是一致的寡键。從而規(guī)范化了傳遞給Shader的數(shù)據(jù)的格式和大小掀泳。

第二步,調(diào)用Vertex Shader

attribute vec4 position;
attribute vec4 color;

varying vec4 fragColor;

void main(void) {
    fragColor = color;
    gl_Position = position;
}

這是本例使用的Vertex Shader西轩,他只做了兩件事,將頂點數(shù)據(jù)里的顏色傳遞給了Fragment Shader脑沿,將位置傳遞給了OpenGL ES藕畔。更詳細(xì)的解釋會再下一篇介紹。

第三步庄拇,Primitive Assembly

 glDrawArrays(GL_TRIANGLES, 0, 3);

這一步注服,以形狀為單位匯總渲染指令,為下一步柵格化顏色插值做準(zhǔn)備措近。本例中只繪制了三角形溶弟,還可以通過glDrawArrays繪制直線,點等瞭郑。

第四步辜御,Rasterization

這一步會柵格化繪制的形狀。第一步我們說過只需傳遞頂點的顏色屈张,兩點中間的顏色OpenGL會幫我們處理擒权。OpenGL將會計算出每一個像素對應(yīng)的屬性,比如顏色阁谆,這些值都是根據(jù)頂點的屬性值以及形狀計算而來的碳抄。


這是例子渲染出來的三角形,由圖可以看出场绿,三角形內(nèi)部的每個像素的顏色都是根據(jù)像素點與三個點的距離計算出來的剖效。離紅色點越近像素的紅色成分越多。

第五步,F(xiàn)ragment Shader

經(jīng)過柵格化之后璧尸,每一個像素都要經(jīng)過Fragment Shader處理一遍劝贸。下面就是本例使用的Fragment Shader。

varying lowp vec4 fragColor;

void main(void) {
    gl_FragColor = fragColor;
}

本例使用的Fragment Shader什么也沒做逗宁,就是把OpenGL計算出來的顏色直接遞交回給OpenGL映九。

第五步,Per-Fragment Operations

這里主要處理OpenGL對像素的一些固定操作瞎颗。比如深度測試件甥,剪裁測試等。通過OpenGL的API進行配置哼拔。

第六步引有,F(xiàn)ramebuffer

最終寫入Framebuffer,交換緩沖區(qū)后顯示在窗口上倦逐。


最后再介紹兩個重要的點譬正。

坐標(biāo)系

 static GLfloat triangleData[18] = {
        0,      0.5f,  0,  1,  0,  0, // x, y, z, r, g, b,每一行存儲一個點的信息,位置和顏色
        -0.5f, -0.5f,  0,  0,  1,  0,
        0.5f,  -0.5f,  0,  0,  0,  1,
    };

中間點是0,0點檬姥。x,y,z的生長方向如圖曾我,Z軸是由內(nèi)向外。屏幕長寬都是2健民。

如何將頂點數(shù)據(jù)傳遞給Shader

上面解釋步驟時抒巢,從第一步到第二步如何傳遞頂點數(shù)據(jù)沒有介紹。它的代碼實現(xiàn)如下秉犹。

    // 啟用Shader中的兩個屬性
    // attribute vec4 position;
    // attribute vec4 color;
    GLuint positionAttribLocation = glGetAttribLocation(self.shaderProgram, "position");
    glEnableVertexAttribArray(positionAttribLocation);
    GLuint colorAttribLocation = glGetAttribLocation(self.shaderProgram, "color");
    glEnableVertexAttribArray(colorAttribLocation);
    
    // 為shader中的position和color賦值
    // glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
    // indx: 上面Get到的Location
    // size: 有幾個類型為type的數(shù)據(jù)蛉谜,比如位置有x,y,z三個GLfloat元素,值就為3
    // type: 一般就是數(shù)組里元素數(shù)據(jù)的類型
    // normalized: 暫時用不上
    // stride: 每一個點包含幾個byte崇堵,本例中就是6個GLfloat型诚,x,y,z,r,g,b
    // ptr: 數(shù)據(jù)開始的指針,位置就是從頭開始鸳劳,顏色則跳過3個GLFloat的大小
    glVertexAttribPointer(positionAttribLocation, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (char *)triangleData);
    glVertexAttribPointer(colorAttribLocation, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (char *)triangleData + 3 * sizeof(GLfloat));

首先通過glEnableVertexAttribArray激活shader中的兩個屬性狰贯。glGetAttribLocation是為了獲取shader中某個屬性的位置。這是shader與OpenGL約定的數(shù)據(jù)互通方式

GLuint positionAttribLocation = glGetAttribLocation(self.shaderProgram, "position");
glEnableVertexAttribArray(positionAttribLocation);
GLuint colorAttribLocation = glGetAttribLocation(self.shaderProgram, "color");
glEnableVertexAttribArray(colorAttribLocation);

Shader中的屬性

attribute vec4 position;
attribute vec4 color;

頂點數(shù)據(jù)只會傳遞給Vertex Shader棍辕,所以不能把attribute vec4 position;寫到Fragment Shader里暮现,從上面的流程圖也可以看出來。激活Vertex Shader中的屬性后就可以傳值給它了楚昭,下面是傳值代碼栖袋。

glVertexAttribPointer(positionAttribLocation, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (char *)triangleData);
glVertexAttribPointer(colorAttribLocation, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (char *)triangleData + 3 * sizeof(GLfloat));

上面第一行代碼就是告訴Vertex Shader,向位置屬性傳遞的數(shù)據(jù)大小是3個GLfloat抚太,每個頂點數(shù)據(jù)有6個GLfloat塘幅,位置數(shù)據(jù)起始的指針是(char *)triangleData昔案。OpenGL讀取完第一個位置數(shù)據(jù)后,就會將指針增加6個GLfloat的大小电媳,訪問下一個頂點位置踏揣。顏色也是相同的道理。

本篇主要介紹了繪制三角形需要用到哪些API以及繪制流程匾乓。下一篇會重點介紹Shader的相關(guān)知識捞稿。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拼缝,隨后出現(xiàn)的幾起案子娱局,更是在濱河造成了極大的恐慌,老刑警劉巖咧七,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衰齐,死亡現(xiàn)場離奇詭異,居然都是意外死亡继阻,警方通過查閱死者的電腦和手機耻涛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瘟檩,“玉大人抹缕,你說我怎么就攤上這事∶⑴粒” “怎么了歉嗓?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長背蟆。 經(jīng)常有香客問我,道長哮幢,這世上最難降的妖魔是什么带膀? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮橙垢,結(jié)果婚禮上垛叨,老公的妹妹穿的比我還像新娘。我一直安慰自己柜某,他們只是感情好嗽元,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著喂击,像睡著了一般剂癌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翰绊,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天佩谷,我揣著相機與錄音旁壮,去河邊找鬼。 笑死谐檀,一個胖子當(dāng)著我的面吹牛抡谐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播桐猬,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼麦撵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了溃肪?” 一聲冷哼從身側(cè)響起免胃,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乍惊,沒想到半個月后杜秸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡润绎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年撬碟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莉撇。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡呢蛤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出棍郎,到底是詐尸還是另有隱情其障,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布涂佃,位于F島的核電站励翼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏辜荠。R本人自食惡果不足惜汽抚,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伯病。 院中可真熱鬧造烁,春花似錦、人聲如沸午笛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽药磺。三九已至告组,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間与涡,已是汗流浹背惹谐。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工持偏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人氨肌。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓鸿秆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親怎囚。 傳聞我的和親對象是個殘疾皇子卿叽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容