OpenGL ES入門10-多實例渲染

前言

本文是關(guān)于OpenGL ES的系統(tǒng)性學習過程澳盐,記錄了自己在學習OpenGL ES時的收獲泌神。
這篇文章的目標是用OpenGL ES實現(xiàn)多實例渲染坑匠,在2.0版本中蘋果是以擴展的形式來提供相關(guān)支持的后室,在接下來也會講到2.0版本中的相關(guān)API尔店。
環(huán)境是Xcode8.1+OpenGL ES 3.0
目前代碼已經(jīng)放到github上面,OpenGL ES入門10-Instance技術(shù)

歡迎關(guān)注我的 OpenGL ES入門專題

概述

實例化(instancing)或者多實例渲染(instancd rendering)是一種連續(xù)執(zhí)行多條相同渲染命令的方法副编。并且每個命令的所產(chǎn)生的渲染結(jié)果都會有輕微的差異秒拔。是一種非常有效的,實用少量api調(diào)用來渲染大量幾何體的方法串塑。OpenGL提供多種機制,允許著色器對不同渲染實例賦予不同的頂點屬性。

實現(xiàn)效果

多實例渲染實例
渲染命令
  • 多實例渲染命令
    glDrawArraysInstanced函數(shù)是glDrawArrays()的多實例版本枉证,參數(shù)完全等價,只是多了個instancecount移必,該參數(shù)用于設(shè)置渲染實例個數(shù)室谚。
void glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount)

參數(shù) mode :繪制方式,例如:GL_POINTS崔泵、GL_LINES秒赤。
參數(shù) first :從數(shù)組緩存中的哪一位開始繪制,一般為0憎瘸。
參數(shù) count :數(shù)組中頂點的數(shù)量入篮。
參數(shù) instancecount :該參數(shù)用于設(shè)置渲染實例個數(shù)。

glDrawElementsInstanced是glDrawElements()的多實例版本含思,同樣只是多了個instancecount參數(shù)而已崎弃,同樣是用于設(shè)置渲染實例個數(shù)甘晤。

void glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instancecount)

參數(shù) mode :指定繪制圖元的類型。例如:GL_POINTS饲做、GL_LINES线婚。
參數(shù) count :為繪制圖元的數(shù)量乘上一個圖元的頂點數(shù)。
參數(shù) type :為索引值的類型盆均,只能是下列值之一:GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT塞弊。
參數(shù) indices :指向索引存貯位置的指針。
參數(shù) instancecount :該參數(shù)用于設(shè)置渲染實例個數(shù)泪姨。

  • 多實例渲染頂點屬性控制:
    多實例的頂點屬性與正規(guī)的頂點屬性是類似的游沿。它們可以通過glGetAttribLocation查詢,通過glVertexAttribPointer來設(shè)置肮砾。通過glEnableVertexAttribArray和glDisableVertexAttribArray進行啟用和禁用诀黍。
void glVertexAttribDivisor (GLuint index, GLuint divisor) 

參數(shù) index : 對應(yīng)著色器中的索引。
參數(shù) divisor :表示頂點屬性的更新頻率仗处,每隔多少個實例將重新設(shè)置實例的該屬性眯勾,例如設(shè)置為1,那么每個實例的屬性都不一樣婆誓,設(shè)置為2則每兩個實例相同吃环,3則每三個實例改變屬性。

實現(xiàn)步驟
  • 創(chuàng)建著色器洋幻。在片元著色器中我們增加一個偏移量的屬性(attribute vec3 offset)郁轻,在每次繪制之后它的值會發(fā)生偏移。通過glVertexAttribDivisor來設(shè)置如何偏移文留。
precision mediump float;

uniform sampler2D image;

varying vec2 vTexcoord;

void main()
{
    gl_FragColor = texture2D(image, vTexcoord);
}
attribute vec3 position;
attribute vec3 offset; //偏移量
attribute vec2 texcoord;

varying vec2 vTexcoord;

void main()
{
    gl_Position = vec4(position+offset, 1.0);
    vTexcoord = texcoord;
}

  • 設(shè)置頂點屬性好唯。設(shè)置頂點屬性方便我們進行紋理貼圖。
- (void)setupVBO
{
    _vertCount = 6;
    
    GLfloat vertices[] = {
        -0.5f,  1.0f, 0.0f, 1.0f, 0.0f,   // 右上
        -0.5f,  0.5f, 0.0f, 1.0f, 1.0f,   // 右下
        -1.0f,  0.5f, 0.0f, 0.0f, 1.0f,  // 左下
        -1.0f,  0.5f, 0.0f, 0.0f, 1.0f,  // 左下
        -1.0f,  1.0f, 0.0f, 0.0f, 0.0f,  // 左上
        -0.5f,  1.0f, 0.0f, 1.0f, 0.0f,   // 右上
    };
    
    // 創(chuàng)建VBO
    _vbo = createVBO(GL_ARRAY_BUFFER, GL_STATIC_DRAW, sizeof(vertices), vertices);
    
    glEnableVertexAttribArray(glGetAttribLocation(_program, "position"));
    glVertexAttribPointer(glGetAttribLocation(_program, "position"), 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, NULL);
    
    glEnableVertexAttribArray(glGetAttribLocation(_program, "texcoord"));
    glVertexAttribPointer(glGetAttribLocation(_program, "texcoord"), 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, NULL+sizeof(GL_FLOAT)*3);
}
  • 設(shè)置紋理厂庇。通過讀取紋理圖片渠啊,生成紋理緩存對象。
- (void)setupTexure
{
    NSString *path = [[NSBundle mainBundle] pathForResource:@"wood" ofType:@"jpg"];
    
    unsigned char *data;
    int size;
    int width;
    int height;
    
    // 加載紋理
    if (read_jpeg_file(path.UTF8String, &data, &size, &width, &height) < 0) {
        printf("%s\n", "decode fail");
    }
    
    // 創(chuàng)建紋理
    _texture = createTexture2D(GL_RGB, width, height, data);
    
    if (data) {
        free(data);
        data = NULL;
    }
}
  • 設(shè)置偏移量权旷。偏移量和普通的頂點數(shù)據(jù)一樣可以使用VBO來存儲替蛉。我們希望每次繪制頂點數(shù)組都發(fā)生一定的偏移,總共發(fā)生三次偏移(gl_Position = vec4(position+offset, 1.0))拄氯。這樣我們總共需要9個GLfloat的空間來存儲偏移數(shù)據(jù)躲查。
- (void)setupOffset
{
    GLfloat vertices[] = {
        0.1f, -0.1f, 0.0f,
        0.7f, -0.7f, 0.0f,
        1.3f, -1.3f, 0.0f,
    };
    
    // 創(chuàng)建VBO
    _offsetVBO = createVBO(GL_ARRAY_BUFFER, GL_STATIC_DRAW, sizeof(vertices), vertices);
    
    glEnableVertexAttribArray(glGetAttribLocation(_program, "offset"));
    glVertexAttribPointer(glGetAttribLocation(_program, "offset"), 3, GL_FLOAT, GL_FALSE, 0, NULL);
}
  • 繪制。
- (void)render
{
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glLineWidth(2.0);
    
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);
    
    // 激活紋理
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, _texture);
    glUniform1i(glGetUniformLocation(_program, "image"), 0);
    
    // 每次繪制之后译柏,對offset進行1個偏移
    glVertexAttribDivisor(glGetAttribLocation(_program, "offset"), 1);
    
    glDrawArraysInstanced(GL_TRIANGLES, 0, _vertCount, 3);
    
    //將指定 renderbuffer 呈現(xiàn)在屏幕上镣煮,在這里我們指定的是前面已經(jīng)綁定為當前 renderbuffer 的那個,在 renderbuffer 可以被呈現(xiàn)之前鄙麦,必須調(diào)用renderbufferStorage:fromDrawable: 為之分配存儲空間典唇。
    [_context presentRenderbuffer:GL_RENDERBUFFER];
}

最后

由于上述API都是OpenGL ES 3.0的相關(guān)API镊折,因此如果在OpenGL ES 2.0想實現(xiàn)相同的效果,我們可以用蘋果的OpenGL ES 2.0的擴展API介衔。OpenGL ES 2.0的擴展都在glext.h中恨胚,區(qū)別就是API加了EXT、APPLE炎咖、OES等后綴赃泡。比如多實例渲染OpenGL ES 2.0的擴展API為 glVertexAttribDivisorEXT、 glDrawArraysInstancedEXT乘盼、glDrawElementsInstancedEXT

參考鏈接

OpenGL-Refpages

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末升熊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子绸栅,更是在濱河造成了極大的恐慌级野,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阴幌,死亡現(xiàn)場離奇詭異勺阐,居然都是意外死亡,警方通過查閱死者的電腦和手機矛双,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蟆豫,“玉大人议忽,你說我怎么就攤上這事∈酰” “怎么了栈幸?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長帮辟。 經(jīng)常有香客問我速址,道長,這世上最難降的妖魔是什么由驹? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任芍锚,我火速辦了婚禮,結(jié)果婚禮上蔓榄,老公的妹妹穿的比我還像新娘并炮。我一直安慰自己,他們只是感情好甥郑,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布逃魄。 她就那樣靜靜地躺著,像睡著了一般澜搅。 火紅的嫁衣襯著肌膚如雪伍俘。 梳的紋絲不亂的頭發(fā)上邪锌,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音癌瘾,去河邊找鬼觅丰。 笑死,一個胖子當著我的面吹牛柳弄,可吹牛的內(nèi)容都是我干的舶胀。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼碧注,長吁一口氣:“原來是場噩夢啊……” “哼嚣伐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起萍丐,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤轩端,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后逝变,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體基茵,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年壳影,在試婚紗的時候發(fā)現(xiàn)自己被綠了拱层。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡宴咧,死狀恐怖根灯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情掺栅,我是刑警寧澤烙肺,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站氧卧,受9級特大地震影響桃笙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沙绝,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一搏明、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宿饱,春花似錦熏瞄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至为黎,卻和暖如春邮丰,著一層夾襖步出監(jiān)牢的瞬間行您,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工剪廉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留娃循,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓斗蒋,卻偏偏與公主長得像捌斧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子泉沾,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

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