獲取示例代碼
前面幾篇文章介紹了基本的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í)的介紹睛驳。