學(xué)習(xí)OpenGL ES之繪制更多的圖形

本系列所有文章目錄

獲取示例代碼


前面幾篇文章介紹了基本的OpenGL ES繪制流程和Shader的基本語(yǔ)法二驰。本文主要擴(kuò)展一下繪制方面的知識(shí)扔罪,會(huì)介紹到繪制三角帶,三角扇形桶雀,直線矿酵,直線帶,直線環(huán)矗积,點(diǎn)全肮。和三角形一樣,它們的繪制都是通過(guò)調(diào)用glDrawArrays(幾何形狀類型, 0, 頂點(diǎn)數(shù));完成的棘捣,Shader屬性的激活和傳值也是一模一樣的辜腺,所以我把這些操作提取到一個(gè)新的方法里面。

- (void)bindAttribs:(GLfloat *)triangleData {
    // 啟用Shader中的兩個(gè)屬性
    // 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: 有幾個(gè)類型為type的數(shù)據(jù)乍恐,比如位置有x,y,z三個(gè)GLfloat元素评疗,值就為3
    // type: 一般就是數(shù)組里元素?cái)?shù)據(jù)的類型
    // normalized: 暫時(shí)用不上
    // stride: 每一個(gè)點(diǎn)包含幾個(gè)byte,本例中就是6個(gè)GLfloat茵烈,x,y,z,r,g,b
    // ptr: 數(shù)據(jù)開始的指針百匆,位置就是從頭開始,顏色則跳過(guò)3個(gè)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));
}

然后之前三角形的繪制就變成了這樣呜投。

- (void)drawTriangle {
    static GLfloat triangleData[36] = {
        0,      0.5f,  0,  1,  0,  0, // x, y, z, r, g, b,每一行存儲(chǔ)一個(gè)點(diǎn)的信息加匈,位置和顏色
        -0.5f,  0.0f,  0,  0,  1,  0,
        0.5f,   0.0f,  0,  0,  0,  1,
        0,      -0.5f,  0,  1,  0,  0,
        -0.5f,  0.0f,  0,  0,  1,  0,
        0.5f,   0.0f,  0,  0,  0,  1,
        
        
    };
    [self bindAttribs:triangleData];
    glDrawArrays(GL_TRIANGLES, 0, 6);
}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect里把[self drawXXX];替換成[self drawLines]寄症,[self drawTriangleFan]... 等中的任一方法即可繪制對(duì)應(yīng)的形狀。

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    // 清空之前的繪制
    glClearColor(1, 0.2, 0.2, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 使用fragment.glsl 和 vertex.glsl中的shader
    glUseProgram(self.shaderProgram);
    // 設(shè)置shader中的 uniform elapsedTime 的值
    GLuint elapsedTimeUniformLocation = glGetUniformLocation(self.shaderProgram, "elapsedTime");
    glUniform1f(elapsedTimeUniformLocation, (GLfloat)self.elapsedTime);
    
// 修改成drawLines矩动,drawTriangleFan ... 等中的任一方法即可
    [self drawXXX];
}

接下來(lái)我就逐一介紹上面說(shuō)到的那些形狀刽肠。

三角帶

對(duì)應(yīng)的OpenGL繪制類型GL_TRIANGLE_STRIP,繪制代碼如下。

- (void)drawTriangleStrip {
    static GLfloat triangleData[] = {
        0,      0.5f,  0,  1,  0,  0, // x, y, z, r, g, b,每一行存儲(chǔ)一個(gè)點(diǎn)的信息绒尊,位置和顏色
        -0.5f,  0.0f,  0,  0,  1,  0,
        0.5f,   0.0f,  0,  0,  0,  1,
        0,      -0.5f,  0,  1,  0,  0,
    };
    [self bindAttribs:triangleData];
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

效果如圖形娇。

例子中只給了4個(gè)點(diǎn),但是卻可以繪制出兩個(gè)三角形示姿,是怎么做到的呢甜橱?如圖,我們假設(shè)頂點(diǎn)為v1栈戳,v2岂傲,v3,v4子檀,那么三角帶的渲染方式就是先使用v1镊掖,v2, v3三個(gè)點(diǎn)繪制一個(gè)三角形,再使用v3褂痰,v2亩进, v4繪制另一個(gè)三角形,兩個(gè)三角形共享了v2和v3缩歪。所以三角帶的渲染方式適用于前一個(gè)三角形和后一個(gè)三角形共享一條邊的情況归薛。至于多于4個(gè)點(diǎn)的情況,讀者可以自己嘗試一下匪蝙。

三角扇形

對(duì)應(yīng)的OpenGL繪制類型GL_TRIANGLE_FAN,繪制代碼如下主籍。

- (void)drawTriangleFan {
    static GLfloat triangleData[] = {
        -0.5f,  0.0f,  0,  0,  1,  0,
        0,      0.5f,  0,  1,  0,  0,
        0.5f,   0.0f,  0,  0,  0,  1,
        0,      -0.5f,  0,  1,  0,  0,
    };
    [self bindAttribs:triangleData];
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}

它和三角帶的區(qū)別就是三角帶中的相鄰的三角形共享一條邊,而三角扇形中不僅相鄰三角形共享一條邊逛球,所有的三角形還共享一個(gè)頂點(diǎn)千元。

如圖,數(shù)組中的第一個(gè)點(diǎn)v1是所有三角形的共享點(diǎn)需忿,所以繪制出來(lái)的兩個(gè)三角形分別是v1诅炉,v2,v3和v1屋厘,v3涕烧,v4。如果我們?cè)僭黾右粋€(gè)頂點(diǎn)v5汗洒,那么就會(huì)再繪制出一個(gè)三角形v1议纯,v4,v5溢谤,讀者們可以自己動(dòng)手試一試瞻凤。別忘了glDrawArrays(GL_TRIANGLE_FAN, 0, 4);的最后一個(gè)參數(shù)4是頂點(diǎn)的個(gè)數(shù)憨攒,如果你增加了新的頂點(diǎn)請(qǐng)修改該值。當(dāng)然你也可以使用sizeof(triangleData) / (6 * sizeof(GLfloat))來(lái)動(dòng)態(tài)計(jì)算頂點(diǎn)的個(gè)數(shù)阀参。

直線

對(duì)應(yīng)的OpenGL繪制類型GL_LINES,繪制代碼如下肝集。

- (void)drawLines {
    static GLfloat lineData[] = {
        0.0f,  0.0f,  0,  0,  1,  0,
        0.5,   0.5f,  0,  1,  0,  0,
        0.0f,  0.0f,  0,  0,  0,  1,
        0.5,   -0.5f, 0,  1,  0,  0,
    };
    [self bindAttribs:lineData];
    glLineWidth(5);
    glDrawArrays(GL_LINES, 0, 4);
}

使用glLineWidth設(shè)置直線的寬度為5像素。繪制效果如下蛛壳。


v1和v2形成一條線杏瞻,v3和v4形成一條線。如果想繪制n條線段衙荐,那么必須提供2 * n個(gè)頂點(diǎn)捞挥。

直線帶

對(duì)應(yīng)的OpenGL繪制類型GL_LINE_STRIP,繪制代碼如下。

- (void)drawLinesStrip {
    static GLfloat lineData[] = {
        0.0f,  0.0f,  0,  0,  1,  0,
        0.5,   0.5f,  0,  1,  0,  0,
        0.5,   -0.5f, 0,  1,  0,  0,
    };
    [self bindAttribs:lineData];
    glLineWidth(5);
    glDrawArrays(GL_LINE_STRIP, 0, 3);
}

同樣是繪制兩條線忧吟,但是頂點(diǎn)比GL_LINES少了一個(gè)砌函。因?yàn)?br> GL_LINE_STRIP的做法是每?jī)蓚€(gè)相鄰線段共享一個(gè)頂點(diǎn),其實(shí)就是三角帶的做法溜族。具體效果讀者可以自己編譯運(yùn)行看一看讹俊。

直線環(huán)

對(duì)應(yīng)的OpenGL繪制類型GL_LINE_LOOP,繪制代碼如下。

- (void)drawLinesStrip {
    static GLfloat lineData[] = {
        0.0f,  0.0f,  0,  0,  1,  0,
        0.5,   0.5f,  0,  1,  0,  0,
        0.5,   -0.5f, 0,  1,  0,  0,
    };
    [self bindAttribs:lineData];
    glLineWidth(5);
    glDrawArrays(GL_LINE_LOOP, 0, 3);
}

和直線帶唯一不同的就是斩祭,OpenGL會(huì)把開始點(diǎn)和終結(jié)點(diǎn)連接起來(lái)劣像,形成封閉的形狀。

點(diǎn)

對(duì)應(yīng)的OpenGL繪制類型GL_POINTS,繪制代碼如下摧玫。

- (void)drawPoints {
    static GLfloat lineData[] = {
        0.0f,  0.0f,  0,  0,  1,  0,
        0.5,   0.5f,  0,  1,  0,  0,
        0.5,   -0.5f, 0,  1,  0,  0,
    };
    [self bindAttribs:lineData];
    glDrawArrays(GL_POINTS, 0, 3);
}

想要設(shè)置點(diǎn)的大小,需要在Vertex Shader中指定绑青。

attribute vec4 position;
attribute vec4 color;

uniform float elapsedTime;

varying vec4 fragColor;

void main(void) {
    fragColor = color;
    float angle = elapsedTime * 1.0;
    float xPos = position.x * cos(angle) - position.y * sin(angle);
    float yPos = position.x * sin(angle) + position.y * cos(angle);
    gl_Position = position;//vec4(xPos, yPos, position.z, 1.0);
    gl_PointSize = 25.0;
}

gl_PointSize = 25.0就是對(duì)點(diǎn)大小的賦值诬像。OpenGL會(huì)為每個(gè)頂點(diǎn)數(shù)據(jù)繪制一個(gè)矩形。效果如下闸婴。

為了方便觀察頂點(diǎn)的位置坏挠,本文的例子中我暫時(shí)把旋轉(zhuǎn)動(dòng)畫給注釋掉了,直接把position賦值給了gl_Position邪乍。

到此降狠,所有基本圖形的繪制差不多就介紹完了,以后無(wú)論繪制多么復(fù)雜的3D模型和效果都離不開這些基本圖形元素庇楞。

前面幾篇文章包括這篇介紹的都只是2D環(huán)境下的一些渲染榜配,從下一篇開始就要慢慢進(jìn)入3D渲染的世界了,先從基本的三維變換矩陣開始吕晌,再到投影矩陣蛋褥,攝像機(jī)等概念。最后以一個(gè)渲染帶貼圖的3D正方體的經(jīng)典例子結(jié)束OpenGL ES基本知識(shí)的介紹睛驳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末烙心,一起剝皮案震驚了整個(gè)濱河市膜廊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淫茵,老刑警劉巖爪瓜,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異匙瘪,居然都是意外死亡铆铆,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門辆苔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)算灸,“玉大人,你說(shuō)我怎么就攤上這事驻啤》坡浚” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵骑冗,是天一觀的道長(zhǎng)赊瞬。 經(jīng)常有香客問(wèn)我,道長(zhǎng)贼涩,這世上最難降的妖魔是什么巧涧? 我笑而不...
    開封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮遥倦,結(jié)果婚禮上谤绳,老公的妹妹穿的比我還像新娘。我一直安慰自己袒哥,他們只是感情好缩筛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著堡称,像睡著了一般瞎抛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上却紧,一...
    開封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天桐臊,我揣著相機(jī)與錄音,去河邊找鬼晓殊。 笑死断凶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的挺物。 我是一名探鬼主播懒浮,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了砚著?” 一聲冷哼從身側(cè)響起次伶,我...
    開封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎稽穆,沒(méi)想到半個(gè)月后冠王,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舌镶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年柱彻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片餐胀。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡哟楷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出否灾,到底是詐尸還是另有隱情卖擅,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布墨技,位于F島的核電站惩阶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏扣汪。R本人自食惡果不足惜断楷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望崭别。 院中可真熱鬧冬筒,春花似錦、人聲如沸茅主。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)暗膜。三九已至,卻和暖如春鞭衩,著一層夾襖步出監(jiān)牢的瞬間学搜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工论衍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瑞佩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓坯台,卻偏偏與公主長(zhǎng)得像炬丸,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

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