您的位置:首页 > 运维架构

openGL对基本几何图形的定义

2017-09-05 23:10 274 查看
通常在二维空间中可以绘制点,线,多边形,圆弧,路径等。而OpenGL ES 支持的基本几何图形有三种: 点 、 线段、 三角形。 也就是在OpenGLEs中,任何其他的图形都可以通过这三种基本图形构造出来。比如通常来讲 复杂的3D图形,都需要将其分割成细小的三角形,然后构造出一个3d的基本模体,继而通过处理颜色,添加纹理,添加光照来构造出3d的图形效果。点,线,三角形都是通过顶点 (vertexs)来定义的,即顶点数组。在平面上,将多个孤立的点通过线段连接起来就可以构造出线段(line
segment)或者三角形(triangle)。

下面是几种openglES定义的几种模式:

GL_POINTS :绘制独立的点

GL_LINE_STRIP :绘制一系列线段。

GL_LINE_LOOP : 封闭曲线。

GL_LINES:顶点两两连接,为多条线段构成。

GL_TRIANGLES : 每隔三个顶点构成一个三角形,为多个三角形组成。

GL_TRIANGLE_STRIP :每相邻三个顶点组成一个三角形,为一系列相接三角形构成。

GL_TRIANGLE_FAN : 以一个点为三角形公共顶点,组成一系列相邻的三角形。

以上模式对应到 Android 渲染方法:

OpenGL ES 提供了两类方法来绘制一个空间几何图形:

public abstract void glDrawArrays(int mode, int first, int count) 

使用 VetexBuffer 来绘制,顶点的顺序由 vertexBuffer 中的顺序指定。下面是glDrawArrays() 方法的使用说明:

功能:由矩阵数据渲染图元。

详细

glDrawArrays通过很少的子程序调用指明多层几何图元。你可以设置独立的顶点、法线、颜色矩阵,以及纹理坐标,并仅需调用glDrawArrays就可以通过它们构建一系列图元。

当glDrawArrays被调用,它从被允许访问的矩阵中计算连续count个元素来构建一系列几何图元,从first元素开始。mode指明哪一种图元将被构建及矩阵元素怎样构建这些图元。如果GL_VERTEX_ARRAY没有启用,则不会有图元产生。

当glDrawArrays返回后,由glDrawArrays改变的顶点属性会得到一个未指明的值。举个例子,如果GL_COLOR_ARRAY被启用,则glDrawArrays执行后当前颜色的值是未定义的。未改变的属性仍然是已定义的。

错误

如果mode不是被允许的值,将会产生GL_INVALID_ENUM。

如果count是负数,将会产生GL_INVALID_VALUE。

参数

mode——指明渲染哪一种图元。允许的符号常量有GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN和GL_TRIANGLES。

first——指明在允许访问的矩阵中的起始索引。

count——指明要渲染的索引的数量。

抛出:

java.lang.ArrayIndexOutOfBoundsException——如果序列中任一索引first至first + count – 1,导致引用出界。这个序列包括当前顶点、颜色、法线、纹理坐标,点大小,矩阵索引,或加权矩阵。

publicabstract void glDrawElements(int mode, int count, int type, Buffer indices)
,可以重新定义顶点的顺序,顶点的顺序由 indices Buffer 指定。


功能:由矩阵数据渲染图元。

详细

glDrawElements用少量调用指明多重几何图元,你可以事先指明独立的顶点、法线、颜色和纹理坐标矩阵并且可以通过调用glDrawElements方法来使用它们创建序列图元。

当glDrawElements被调用,它会使用有序索引来查询可用矩阵中的元素,并以此创建序列几何图元,如果GL_VERTEX_ARRAY被禁用,则不会创建。

顶点属性由glDrawElements修改,glDrawElements在返回后会有一个未指明的值。举一个例子,如果GL_COLOR_ARRAY启用,当执行glDrawElements方法后,当前颜色的值是未定义的,属性不会维持它之前的值。

错误

如果mode的值不被允许,将产生GL_INVALID_ENUM。

如果type的值不被允许,将产生GL_INVALID_ENUM。

如果count是负数,将产生GL_INVALID_VALUE。

参数

mode——指明被渲染的是哪种图元,被允许的符号常量有GL_POINTS,GL_LINE_STRIP,GL_LINE_LOOP,GL_LINES,GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN和GL_TRIANGLES

count——指明被渲染的元素个数。

type——指明索引指的类型,不是GL_UNSIGNED_BYTE就是GL_UNSIGNED_SHORT。

indices——指明存储索引的位置指针。

抛出

java.lang.IllegalStateException——如果最近一次调用glBindBuffer方法以GL_ELEMENT_ARRAY_BUFFER为目标时,有一个非0缓冲区参数。

java.lang.IllegalArgumentException——如果索引为空。

java.lang.ArrayIndexOutOfBoundsException——如果索引序列中从0到count-1中任意索引超出现有索引或数据矩阵范围。

其中 mode 为上述解释顶点的模式,如下面定义三个顶点坐标,并把它们存放在 FloatBuffer
中:

float[] vertexArray = new float[]{

 -0.8f , -0.4f * 1.732f ,0.0f ,

 0.8f , -0.4f * 1.732f ,0.0f ,

 0.0f , 0.4f * 1.732f ,0.0f ,

 };

ByteBuffer vbb=ByteBuffer.allocateDirect(vertexArray.length*4);

vbb.order(ByteOrder.nativeOrder());

FloatBuffer vertex = vbb.asFloatBuffer();

vertex.put(vertexArray);

vertex.position(0); 

有了顶点的定义,下面就可以通过打开 OpenGL ES
管道(Pipeline)的相应开关将顶点参数传给 OpenGL
库:

打开顶点开关和关闭顶点开关的方法如下:

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

...

gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 

在打开顶点开关后,将顶点坐标传给 OpenGL 管道的方法为:glVertexPointer:

public void glVertexPointer(int size,int type,int stride,Bufferpointer)

·       size:每个顶点坐标维数,可以为2,3,4。

·       type:顶点的数据类型,可以为 GL_BYTE, GL_SHORT, GL_FIXED,或 GL_FLOAT,缺省为浮点类型 GL_FLOAT。

·       stride:每个相邻顶点之间在数组中的间隔(字节数),缺省为 0,表示顶点存储之间无间隔。

·       pointer:存储顶点的数组。

应用用上可以般顶点的颜色值存放在对应顶点后面,如下图,RGB 采用 4 字节表示,此时相邻顶点就不是连续存放的,stride 值为 4 。

对应顶点除了可以为其定义坐标外,还可以指定颜色,材质,法线(用于光照处理)等。

glEnableClientState 和 glDisableClientState
可以控制的 pipeline 开关可以有:GL_COLOR_ARRAY (颜色),GL_NORMAL_ARRAY (法线),GL_TEXTURE_COORD_ARRAY (材质),GL_VERTEX_ARRAY(顶点), GL_POINT_SIZE_ARRAY_OES等。

对应的传入颜色,顶点,材质,法线的方法如下:

glColorPointer(int size,int type,int stride,Buffer pointer)

glVertexPointer(int size, int type, int stride, Buffer pointer)

glTexCoordPointer(int size, int type, int stride, Bufferpointer)

glNormalPointer(int type, int stride, Buffer pointer)

如果需要使用三角形来构造复杂图形,可以使用 GL_TRIANGLE_STRIP 或 GL_TRIANGLE_FAN 模式,另外一种是通过定义顶点序列:

如下图定义了一个正方形:

对应的顶点和 buffer 定义代码:

private short[] indices = { 0, 1, 2, 0, 2, 3 };

//To gain some performance we also put this ones in a bytebuffer.

// short is 2 bytes, therefore we multiply the number ifvertices with 2.

ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);

ibb.order(ByteOrder.nativeOrder());

ShortBuffer indexBuffer = ibb.asShortBuffer();

indexBuffer.put(indices);

indexBuffer.position(0); 

定义三角形的顶点的顺序很重要在拼接曲面的时候,用来定义面的顶点的顺序非常重要,因为顶点的顺序定义了面的朝向(前向或是后向),为了获取绘制的高性能,一般情况不会绘制面的前面和后面,只绘制面的“前面”。虽然“前面”“后面”的定义可以应人而易,但一般为所有的“前面”定义统一的顶点顺序(顺时针或是逆时针方向)。

下面代码设置逆时针方法为面的“前面”:

gl.glFrontFace(GL10.GL_CCW); 

打开 忽略“后面”设置:

gl.glEnable(GL10.GL_CULL_FACE); 

明确指明“忽略“哪个面的代码如下:

gl.glCullFace(GL10.GL_BACK); 

 

看到这里,搞明白了一件事情,就是opengles 1.0 和 2.0 的区别,

其实是两种不同的实现。在android framework中,1.0的实现是javax.microedition.khronos.opengles 其中的主要类是GL10.

而2.0的实现是android.opengl.GLES20。

所以,到这里可以基本终止这次资源的学习了,因为目前在操作的是opengl es1.0 的api,和opengles 2.0 是完全不同的实现,也没有任何的集成兼容关系:)。

鸣谢:http://wiki.jikexueyuan.com/project/opengl-es-basics/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  opengl es