资料来源:java
OpenGL ES3.0编程指南android
在opengl es中,图元能够用glDrawArrays()
,glDrawElements()
,glDrawRangeElements()
等命令绘制几何图像。图元有一组表示顶点位置的顶点描述。git
图元总共三部分:github
支持的三角形图元有GL_TRIANGLES
,GL_TRIANGLE_STRIP
,GL_TRIANGLE_FAN
三种。现根据opengl官方的wiki整理以下:编程
- GL_TRIANGLES: Vertices 0, 1, and 2 form a triangle. Vertices 3, 4, and 5 form a triangle. And so on.
- GL_TRIANGLE_STRIP: Every group of 3 adjacent vertices forms a triangle. The face direction of the strip is determined by the winding of the first triangle. Each successive triangle will have its effective face order reversed, so the system compensates for that by testing it in the opposite way. A vertex stream of n length will generate n-2 triangles.
- GL_TRIANGLE_FAN: The first vertex is always held fixed. From there on, every group of 2 adjacent vertices form a triangle with the first. So with a vertex stream, you get a list of triangles like so: (0, 1, 2) (0, 2, 3), (0, 3, 4), etc. A vertex stream of n length will generate n-2 triangles.
GL_TRIANGLES
而言,就是直接绘制一系列的单独的三角形,以以下图形举例,顶点V0,V1,V2组成一个三角形,顶点V3,V4,V5组成一个三角形。经过顶点数组能够组成三角形的数目为数组长度/3api
在Anroid中代码:数组
Demo地址https://github.com/JerryChan123/LearnOEL/tree/gl30 查看test for gl_triangle的提交学习
static float triangleCoords[] = { // in counterclockwise order: 0.0f, 0.622008459f, 0.0f, // top -0.5f, 0f, 0.0f, // bottom left 0.5f, 0f, 0.0f, // bottom right 0.5f, 0f, 0.0f, -0.5f, 0f, 0.0f, 0.0f, -0.622008459f, 0.0f, }; float color[] = { 1.0f, 0.0f, 0.0f,1f, 1.0f, 0.0f, 0.0f,1f, 1.0f, 0.0f, 0.0f,1f, 0f, 1.0f, 0.0f,1f, 0f, 1.0f, 0.0f,1f, 0f, 1.0f, 0.0f,1f}; public void onDraw() { // Add program to OpenGL ES environment GLES30.glUseProgram(mProgram); // get handle to vertex shader's vPosition member mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition"); // createVertextBuffer(); //注意,这里注释掉了VBO,是由于打开后有Bug,具体是什么问题有待发现 // Enable a handle to th、e triangle vertices GLES30.glEnableVertexAttribArray(mPositionHandle); // Prepare the triangle coordinate data GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES30.GL_FLOAT, false, 0, vertexBuffer); // get handle to fragment shader's vColor member mColorHandle = GLES30.glGetAttribLocation(mProgram, "aColor"); // Set color for drawing the triangle // GLES30.glVertexAttrib4fv(mColorHandle, color, 0); GLES30.glEnableVertexAttribArray(mColorHandle); GLES30.glVertexAttribPointer(mColorHandle, 4, GLES30.GL_FLOAT, false, 0, colorBuffer); // Draw the triangle GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexCount); // Disable vertex array GLES30.glDisableVertexAttribArray(mPositionHandle); }
效果图以下:翻译
GL_TRIANGLE_STRIP
而言,英文翻译过来就是每一个小组的三个临近的顶点组成一个三角形,一以下图形举例:
看见英文一大堆就晕了,其实简单的就是V0,V1,V2组成一个三角形,V1,V2,V3组成一个三角形,V2,V3,V4组成一个三角形,以此类推。经过顶点数组能够组成三角形的数目为数组长度-2
Android代码使用以下:
static float triangleCoords[] = { // in counterclockwise order: 0.0f, 0.622008459f, 0.0f, // top -0.5f, 0f, 0.0f, // bottom left 0.5f, 0f, 0.0f, // bottom right 0.0f, -0.622008459f, 0.0f, }; private final int mProgram; // Set color with red, green, blue and alpha (opacity) values float color[] = { 1.0f, 0.0f, 0.0f,1f, 0f, 1.0f, 0.0f,1f, 0f, 0f, 1.0f,1f, 0f, 0.0f, 0.0f,1f}; public void onDraw() { ... GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, vertexCount); // Disable vertex array GLES30.glDisableVertexAttribArray(mPositionHandle); }
与上面代码的区别主要是在GL_TRIANGLE_STRIP参数的设置以及顶点数组数目的改变。实现效果以下所示:
GL_TRIANGLE_FAN
而言,表示一个扇形的三角形组成,看底下的图就能明白:
顶点V0为圆点,呈扇形画出,即V0,V1,V2一个三角形,V0,V2,V3一个三角形,以此类推。 Android代码示例:
static float triangleCoords[] = { // in counterclockwise order: -0.5f, 0f, 0.0f, // bottom left 0.0f, 0.622008459f, 0.0f, // top 0.5f, 0f, 0.0f, // bottom right 0.0f, -0.622008459f, 0.0f, }; private final int mProgram; // Set color with red, green, blue and alpha (opacity) values float color[] = { 1.0f, 0.0f, 0.0f,1f, 0f, 1.0f, 0.0f,1f, 0f, 0f, 1.0f,1f, 0f, 0.0f, 0.0f,1f}; public void onDraw() { .... GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, vertexCount); // Disable vertex array GLES30.glDisableVertexAttribArray(mPositionHandle); }
主要就是GL_TRIANGLE_FAN的设置以及数组位置的改变。实现效果与GL_TRIANGLE_STRIP相同。
opengl es中支持的直线有GL_LINES
,GL_LINE_STRIP
,GL_LINE_LOOP
三大类,三个变量的区别以下图所示:
n指的是直线顶点数组的长度
比较简单就不举例子了。
点精灵是针对顶点进行绘制。点精灵一般将粒子效果做为点而非正方形绘制,从而实现高效渲染。点精灵是指定位置和半径的屏幕对齐的正方形,位置描述正方形的中心,半径用于计算点精灵的四个角坐标。
注意opengles窗口的坐标范围是:从左下角(原点)到右上角。
而点精灵的原点是在左上角 坐标值 从0-1.
gl_PointSize()
是可用于在顶点着色器输出点半径的内建变量。与点图元相关的顶点着色器输出gl_PointSize很重要,不然,会被视为未定义,极可能会形成绘图错误。顶点着色器的输出gl_PointSize收到opengl es 3.0实现所支持的非平滑点尺寸范围的限制,能够用以下命令查询:
GLfloat pointSizeRange[2]; glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE,pointSizeRange); //android中的表示 GLES30.glGetFloatv();
gl_PointCoord
是只能在渲染图元为点精灵的时候用于片断着色器的内部建量。他用一个mediump精度限定符申明为一个vec2变量。gl_PointCoord属于区间[0,1],超出的则不显示。
图元总共有五个绘制方法:
在Android中只支持第一种跟第二种,Android native层有待考证支持的类型。
glDrawArrays用元素索引为first到first+count-1的元素指定的顶点绘制mode指定的图元。 查看上述使用GL_TRIANGLES
写Demo的例子中的使用:
static float triangleCoords[] = { // in counterclockwise order: 0.0f, 0.622008459f, 0.0f, // top -0.5f, 0f, 0.0f, // bottom left 0.5f, 0f, 0.0f, // bottom right 0.5f, 0f, 0.0f, -0.5f, 0f, 0.0f, 0.0f, -0.622008459f, 0.0f, }; GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexCount);//vertexCount=6
first等于0,first+count-1=5,因此取(0,1,2)和(3,4,5)做为两个三角形的顶点进行绘制。支持的model就是咱们上面锁讲述的一系列几何类型。
若是是一系列顺序元素索引描述的图元,且几何图形顶点不共享,那么glDrawArrays
是能支持的也很好用,可是游戏或者其余3D的应用程序的典型对象由多个三角形网格组成,其中元素不必定按照顺序,顶点一般在网格的三角形之间共享。使用glDrawElements能够比调用glDrawArrays更简单的将这些功能实现,并且内存消耗更小。
###图元装配
经过上述的glDraw*提供的顶点由顶点着色器执行,顶点着色器变换每一个顶点的顶点位置。图元类型和顶点索引肯定将被渲染的单独图元。对于每一个单独图元与其对应的顶点,装配过程如上图所示。
下图中展现了经过顶点着色器和图元装配后的坐标系统:
顶点以物体或者本地坐标空间输入到opengl es中,在顶点着色器执行完后,顶点位置是被认为执行在裁剪空间以内的。顶点位置从本地坐标系统到裁剪坐标的变换经过加载执行对应矩阵来完成。
关于opengl es中的坐标系统须要单独写一篇文章。下面只是记录书中的内容
####裁剪 裁剪坐标的意义在于将判断顶点是否落在裁剪坐标空间内。裁剪坐标是由(x,y,z,w)指定的同类坐标,在裁剪空间(x,y,z,w)中定义的顶点坐标根据视景体(又称裁剪体)裁剪。 视景体由六个平面组成而成,这些平面被称做远,近,左,右,上,下裁剪平面,在裁剪坐标中,裁剪体以下:
裁剪体以下所示:
####透视分割 透视分割取得裁剪坐标(x,y,z,w)指定的点,并将其投影到屏幕或者视口上。这个操做经过将(x,y,z)除以w进行,执行(x/w),(y/w),(z/w)操做以后,获得规范化的设备坐标(q,w,e),他们落在[-1.0,1.0]中,这些坐标会根据视口大小转换成真正的屏幕坐标。规范化的z坐标可使用glDepthRangf()
指定的near和far深度值转换成屏幕的z值,这些转换在视口变换时候进行。
####视口变换 视口是一个二维矩形窗口区域,是全部opengl es渲染最终显示的地方,可调用以下api进行设置:
void glViewport(GLint x,GLint y,GLsizei w,Glsizei h)
从规范化坐标(x,w,z)到窗口坐标(q,w,e)的转换变化以下:
上述变化中Ox=x+w/2,Oy=y+h/2,n和f表明所须要的深度范围,可以使用glDepthRangf()
设置。