學(xué)習(xí)OpenGL ES之頂點索引

本系列所有文章目錄

獲取示例代碼


本文主要講解OpenGL中另一個優(yōu)化技巧付燥,使用頂點索引渲染物體。上一篇文章的例子中渲染正方體需要一個包含36個頂點的數(shù)組愈犹。

本文修改的頂點數(shù)據(jù)都在Cube.m中键科。

- (GLfloat *)cubeData {
    static GLfloat cubeData[] = {
        // X軸0.5處的平面
        0.5,  -0.5,    0.5f, 1,  0,  0, 0, 0,   // VertexA
        0.5,  -0.5f,  -0.5f, 1,  0,  0, 0, 1,   // VertexB
        0.5,  0.5f,   -0.5f, 1,  0,  0, 1, 1,   // VertexC
        0.5,  0.5,    -0.5f, 1,  0,  0, 1, 1,   // VertexC
        0.5,  0.5f,    0.5f, 1,  0,  0, 1, 0,   // VertexD
        0.5,  -0.5f,   0.5f, 1,  0,  0, 0, 0,   // VertexA
        // X軸-0.5處的平面
        -0.5,  -0.5,    0.5f, -1,  0,  0, 0, 0, // VertexE
        -0.5,  -0.5f,  -0.5f, -1,  0,  0, 0, 1, // VertexF
        -0.5,  0.5f,   -0.5f, -1,  0,  0, 1, 1, // VertexG
        -0.5,  0.5,    -0.5f, -1,  0,  0, 1, 1, // VertexG
        -0.5,  0.5f,    0.5f, -1,  0,  0, 1, 0, // VertexH
        -0.5,  -0.5f,   0.5f, -1,  0,  0, 0, 0, // VertexE
        
        -0.5,  0.5,  0.5f, 0,  1,  0, 0, 0,     // VertexH
        -0.5f, 0.5, -0.5f, 0,  1,  0, 0, 1,     // VertexG
        0.5f, 0.5,  -0.5f, 0,  1,  0, 1, 1,     // VertexC
        0.5,  0.5,  -0.5f, 0,  1,  0, 1, 1,     // VertexC
        0.5f, 0.5,   0.5f, 0,  1,  0, 1, 0,     // VertexD
        -0.5f, 0.5,  0.5f, 0,  1,  0, 0, 0,     // VertexH
        -0.5, -0.5,   0.5f, 0,  -1,  0, 0, 0,   // VertexE
        -0.5f, -0.5, -0.5f, 0,  -1,  0, 0, 1,   // VertexF
        0.5f, -0.5,  -0.5f, 0,  -1,  0, 1, 1,   // VertexB
        0.5,  -0.5,  -0.5f, 0,  -1,  0, 1, 1,   // VertexB
        0.5f, -0.5,   0.5f, 0,  -1,  0, 1, 0,   // VertexA
        -0.5f, -0.5,  0.5f, 0,  -1,  0, 0, 0,   // VertexE
        
        -0.5,   0.5f,  0.5,   0,  0,  1, 0, 0,  // VertexH
        -0.5f,  -0.5f,  0.5,  0,  0,  1, 0, 1,  // VertexE
        0.5f,   -0.5f,  0.5,  0,  0,  1, 1, 1,  // VertexA
        0.5,    -0.5f, 0.5,   0,  0,  1, 1, 1,  // VertexA
        0.5f,  0.5f,  0.5,    0,  0,  1, 1, 0,  // VertexD
        -0.5f,   0.5f,  0.5,  0,  0,  1, 0, 0,  // VertexH
        -0.5,   0.5f,  -0.5,   0,  0,  -1, 0, 0,    // VertexG
        -0.5f,  -0.5f,  -0.5,  0,  0,  -1, 0, 1,    // VertexF
        0.5f,   -0.5f,  -0.5,  0,  0,  -1, 1, 1,    // VertexB
        0.5,    -0.5f, -0.5,   0,  0,  -1, 1, 1,    // VertexB
        0.5f,  0.5f,  -0.5,    0,  0,  -1, 1, 0,    // VertexC
        -0.5f,   0.5f,  -0.5,  0,  0,  -1, 0, 0,    // VertexG
    };
    return cubeData;
}

我在每個頂點后做了注釋,大家可以發(fā)現(xiàn)漩怎,其實一共就8個位置不一樣的頂點勋颖,其他都是重復(fù)的。完全可以替換成下面的表現(xiàn)形式勋锤。cubeVertex是正方體的8個頂點饭玲,cubeVertexIndicecubeData中的頂點對應(yīng)的索引數(shù)組,使用索引即可在cubeVertex中取到對應(yīng)的頂點數(shù)據(jù)叁执。這樣一來大大減少了需要傳遞給GPU的數(shù)據(jù)量咱枉。

- (GLfloat *)cubeVertex {
    static GLfloat cubeData[] = {
        0.5,  -0.5,    0.5f, 0.5773502691896258, -0.5773502691896258, 0.5773502691896258, 0, 0,   // VertexA
        0.5,  -0.5f,  -0.5f, 0.5773502691896258, -0.5773502691896258, -0.5773502691896258, 0, 1,   // VertexB
        0.5,  0.5f,   -0.5f, 0.5773502691896258, 0.5773502691896258, -0.5773502691896258, 1, 1,   // VertexC
        0.5,  0.5f,    0.5f, 0.5773502691896258, 0.5773502691896258, 0.5773502691896258, 1, 0,   // VertexD
        -0.5,  -0.5,    0.5f, -0.5773502691896258, -0.5773502691896258, 0.5773502691896258, 0, 0, // VertexE
        -0.5,  -0.5f,  -0.5f, -0.5773502691896258, -0.5773502691896258, -0.5773502691896258, 0, 1, // VertexF
        -0.5,  0.5f,   -0.5f, -0.5773502691896258, 0.5773502691896258, -0.5773502691896258, 1, 1, // VertexG
        -0.5,  0.5f,    0.5f, -0.5773502691896258, 0.5773502691896258, 0.5773502691896258, 1, 0, // VertexH
    };
    return cubeData;
}

- (GLushort *)cubeVertexIndice {
    static GLushort cubeDataIndice[] = {
        0,      // VertexA
        1,      // VertexB
        2,      // VertexC
        2,      // VertexC
        3,      // VertexD
        0,      // VertexA
        
        4,      // VertexE
        5,      // VertexF
        6,      // VertexG
        6,      // VertexG
        7,      // VertexH
        4,      // VertexE
        
        7,      // VertexH
        6,      // VertexG
        2,      // VertexC
        2,      // VertexC
        3,      // VertexD
        7,      // VertexH
        4,      // VertexE
        5,      // VertexF
        1,      // VertexB
        1,      // VertexB
        0,      // VertexA
        4,      // VertexE
        
        7,      // VertexH
        4,      // VertexE
        0,      // VertexA
        0,      // VertexA
        3,      // VertexD
        7,      // VertexH
        6,      // VertexG
        5,      // VertexF
        1,      // VertexB
        1,      // VertexB
        2,      // VertexC
        6,      // VertexG
    };
    return cubeDataIndice;
}

那么,現(xiàn)在問題來了徒恋,怎么渲染這種形式的數(shù)據(jù)呢蚕断?這就是下面要介紹的內(nèi)容。

創(chuàng)建索引數(shù)組IBO

在前文中我們?yōu)轫旤c數(shù)據(jù)創(chuàng)建了VBO入挣,同樣我們也可以為索引數(shù)據(jù)創(chuàng)建IBO(Index Buffer Object)亿乳。

- (void)genIndiceVBO {
    glGenBuffers(1, &indiceVbo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indiceVbo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 36 * sizeof(GLushort), [self cubeVertexIndice], GL_STATIC_DRAW);
}

和創(chuàng)建VBO唯一不同的就是GL_ELEMENT_ARRAY_BUFFER,創(chuàng)建VBO是這里的值是GL_ARRAY_BUFFER径筏。然后我們在生成VAO的地方增加綁定IBO的代碼葛假。

- (void)genVAO {
    glGenVertexArraysOES(1, &vao);
    glBindVertexArrayOES(vao);
    
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indiceVbo);
    [self.context bindAttribs:NULL];
    
    glBindVertexArrayOES(0);
}

這里的vbo綁定的數(shù)據(jù)已經(jīng)修改為cubeVertex里的數(shù)據(jù)了。

- (void)genVBO {
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, 8 * 8 * sizeof(GLfloat), [self cubeVertex], GL_STATIC_DRAW);
}

最后就是繪制部分的修改了滋恬,我在GLContext中增加了一個方法聊训。

- (void)drawTrianglesWithIndicedVAO:(GLuint)vao vertexCount:(GLint)vertexCount {
    glBindVertexArrayOES(vao);
    glDrawElements(GL_TRIANGLES, vertexCount, GL_UNSIGNED_SHORT, (void *)0);
}

主要就是使用了glDrawElements繪制帶索引的頂點數(shù)組。其中GL_UNSIGNED_SHORT指的是索引數(shù)組中每個元素的類型恢氯。這里索引數(shù)組用的是static GLushort cubeDataIndice[]带斑,所以使用GL_UNSIGNED_SHORT。除了這個值外勋拟,還能用的值為GL_UNSIGNED_BYTE勋磕,GL_UNSIGNED_INT。下面是glDrawElements的man文檔敢靡。


到此就可以渲染出正方體了挂滓。

看到這奇怪的渲染效果,很明顯啸胧,事情還沒有結(jié)束赶站。如果你有看基本光照這一篇文章幔虏,應(yīng)該會知道法線可以有下面兩種表現(xiàn)方式。


前者是每個三角形的每個頂點都有一個法線數(shù)據(jù)贝椿,對應(yīng)不使用索引時的情況所计。后者是每個頂點有一個法線數(shù)據(jù),共享的點的法線是這個點在各個三角形上的法線之和歸一化后的結(jié)果团秽。

- (GLfloat *)cubeVertex {
    static GLfloat cubeData[] = {
        0.5,  -0.5,    0.5f, 0.5773502691896258, -0.5773502691896258, 0.5773502691896258, 0, 0,   // VertexA
        0.5,  -0.5f,  -0.5f, 0.5773502691896258, -0.5773502691896258, -0.5773502691896258, 0, 1,   // VertexB
        0.5,  0.5f,   -0.5f, 0.5773502691896258, 0.5773502691896258, -0.5773502691896258, 1, 1,   // VertexC
        0.5,  0.5f,    0.5f, 0.5773502691896258, 0.5773502691896258, 0.5773502691896258, 1, 0,   // VertexD
        -0.5,  -0.5,    0.5f, -0.5773502691896258, -0.5773502691896258, 0.5773502691896258, 0, 0, // VertexE
        -0.5,  -0.5f,  -0.5f, -0.5773502691896258, -0.5773502691896258, -0.5773502691896258, 0, 1, // VertexF
        -0.5,  0.5f,   -0.5f, -0.5773502691896258, 0.5773502691896258, -0.5773502691896258, 1, 1, // VertexG
        -0.5,  0.5f,    0.5f, -0.5773502691896258, 0.5773502691896258, 0.5773502691896258, 1, 0, // VertexH
    };
    return cubeData;
}

cubeVertex里面的法線數(shù)據(jù)就是我手動計算的結(jié)果主胧。這樣產(chǎn)生的法線會讓表面過渡平滑。除了法線习勤,UV也會面臨同樣的問題踪栋,所以渲染出來的貼圖才會不正確。

如果為每個頂點屬性指定不同的VBO和IBO是可以解決這個問題的图毕,這個方案將會在后面介紹加載wavefront 3D模型時詳細(xì)介紹夷都。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市予颤,隨后出現(xiàn)的幾起案子囤官,更是在濱河造成了極大的恐慌,老刑警劉巖蛤虐,帶你破解...
    沈念sama閱讀 221,331評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件党饮,死亡現(xiàn)場離奇詭異,居然都是意外死亡驳庭,警方通過查閱死者的電腦和手機(jī)刑顺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,372評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饲常,“玉大人蹲堂,你說我怎么就攤上這事”从伲” “怎么了柒竞?”我有些...
    開封第一講書人閱讀 167,755評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長播聪。 經(jīng)常有香客問我朽基,道長,這世上最難降的妖魔是什么犬耻? 我笑而不...
    開封第一講書人閱讀 59,528評論 1 296
  • 正文 為了忘掉前任踩晶,我火速辦了婚禮执泰,結(jié)果婚禮上枕磁,老公的妹妹穿的比我還像新娘。我一直安慰自己术吝,他們只是感情好计济,可當(dāng)我...
    茶點故事閱讀 68,526評論 6 397
  • 文/花漫 我一把揭開白布茸苇。 她就那樣靜靜地躺著,像睡著了一般沦寂。 火紅的嫁衣襯著肌膚如雪学密。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,166評論 1 308
  • 那天传藏,我揣著相機(jī)與錄音腻暮,去河邊找鬼。 笑死毯侦,一個胖子當(dāng)著我的面吹牛哭靖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播侈离,決...
    沈念sama閱讀 40,768評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼试幽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了卦碾?” 一聲冷哼從身側(cè)響起铺坞,我...
    開封第一講書人閱讀 39,664評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎洲胖,沒想到半個月后济榨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,205評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡绿映,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,290評論 3 340
  • 正文 我和宋清朗相戀三年腿短,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绘梦。...
    茶點故事閱讀 40,435評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡橘忱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卸奉,到底是詐尸還是另有隱情钝诚,我是刑警寧澤,帶...
    沈念sama閱讀 36,126評論 5 349
  • 正文 年R本政府宣布榄棵,位于F島的核電站凝颇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏疹鳄。R本人自食惡果不足惜拧略,卻給世界環(huán)境...
    茶點故事閱讀 41,804評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瘪弓。 院中可真熱鬧垫蛆,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,276評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至虑乖,卻和暖如春懦趋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背疹味。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工仅叫, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人糙捺。 一個月前我還...
    沈念sama閱讀 48,818評論 3 376
  • 正文 我出身青樓惑芭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親继找。 傳聞我的和親對象是個殘疾皇子遂跟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,442評論 2 359

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