关于几何图形的描述:
文章的代码是程序在程序的代码中找的到。
3D模型由一些更小的元素(点,线,面, 多边形)组成。
(1)顶点(Vertex)
在android中,我们需要定义一个浮点型的数组来保存顶点位置,并且这个浮点型数组转换位数组(这样可以提高性能)。
//四边形的顶点坐标,这四个顶点按照 0,1,2,3的次序来排列,次序为了画图用,在第三部分讲解画几何图形的时候,会用到这个次序
private float vertices[] = {
-1.0f, 1.0f, 0.0f, // 0, Top Left
-1.0f, -1.0f, 0.0f, // 1, Bottom Left
1.0f, -1.0f, 0.0f, // 2, Bottom Right
1.0f, 1.0f, 0.0f, // 3, Top Right
}
//将顶点浮点型数组转换为位数组
private FloatBuffer vertexBuffer;
ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
vertexBuffer = byteBuf.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
/* Opengl ES 有一些提供渲染的功能,这些功能大部分情况下,不能使用,如果你想使用,
* 你必须记得打开这些函数功能,你也可能需要告诉这些功能需要和什么对象配合使用。
* 下面的两行代码的意思是,在渲染过程中,能写或者使用顶点数组,并且指明这些顶点数组的位置。
*/
//指明这些顶点数组的位置
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
//能写和使用顶点数组
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
(2)面(Face)
Face是一个三角形,也就是三个点和三个边围起来的面积。
设置Face的旋转方向是很重要的,因为选择不同的旋转方向意味这选择那一面为前面,那一面为后面。为什么这是重要的那?因为在一个由完全不透明的表面组成的场景中,多边形的后面部分是绝不可能看到的,有时候为了提升性能,需要只描绘正面,而后面的图形就省略部描绘,可以通过为函数 glEnable(GL_CULL_FACE) 和 glDisable(GL_CULL_FACE)来决定是否省略描绘后面部分的图形。可以通过函数glFrontFace来改变方向从而决定多边形的那一面为正面。
glFrontFace: 常量参数GL_CCW表示逆时针,GL_CW表示顺时针。默认情况下,逆时针的多边形坐标顺序是多边形是正面。例如对于三角形:
vertices[] ={
0, 1, 0,
-1, -1, 0,
1, -1, 0
}
如果添加glEnable(GL_CULL_FACE)功能,逆时针可以正常显示图形,顺时针无法显示图形。
glCullFace:函数决定绘制多边形的背面还是正面。
(3)多变形(Polygon)
在前面已经介绍了四边行的四个顶点,次序也在数组vertices中排列好了,即第一个顶点的序号为0({-1.0f, 1.0f, 0.0f}),第二个顶点序号为1({-1.0f, -1.0f, 0.0f})等。
现在说如何画这个四边型,前面已经设定Face的旋转为逆时针,数组vertices组成的是一个四边型,四边型由两个Face(也就是三角形)组成,按照逆时针画两个三角形,即组成一个四边行,第一个三角形的顶点顺序为 0、1、2,即vertices中的前三个顶点组成的三角形, 0、2、3 三个顶点按照逆时针的顺序组成第二个三角形。这个过程组成了一个顺序数组如下:
private short[] indices = { 0, 1, 2, 0, 2, 3 };
为了提高性能,将数组转换为位数组,代码如下:
// short is 2 bytes, therefore we multiply the number if vertices with 2.
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
ShortBuffer indexBuffer = bb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(0);
(4)渲染(Render)
函数glDrawArrays和glDrawElements用来将上面的设置画在屏幕上。这两个函数的有一个相同的参数mode,接受GL_POINTS、GL_LINE_STRIP、GL_LINE_LOOP、GL_LINES、GL_TRIANGLES等常量。下面简单介绍一个常量的意思,
GL_POINTS:表示只画顶点;
GL_LINE_STRIP:从第一个顶点画到最后一个点;
GL_LINE_LOOP:和GL_LINE_STRIP相似,只是最后一点和第一个点链接,形成一个环路;
GL_LINES:每两个点画一条直线;
GL_TRIANGLES: 没三个点为一组画成一个个的三角形;
GL_TRIANGLE_STRIP:按一定的顺序画一系列三角形如按照顶点v0, v1, v2, 然后 v2, v1, v3 (注意顺序), 最后 v2, v3, v4 ,确定这些三角形能正确的形成一个多边形;
GL_TRIANGLE_FAN: 相似GL_TRIANGLE_STRIP,但是顺序是v0, v1, v2, 然后 v0, v2, v3, 最后 v0, v3, v4, 注意和GL_TRIANGLE_STRIP顺序区别;
public abstract void glDrawArrays(int mode, int first, int count):按照前面verticesBuffer数组的顶点来画图形。
public abstract void glDrawElements(int mode, int count, int type, Buffer indices):需要知道顶点的顺序,才能画图行。在第三部分关于多边形的内容中,指定了顶点的顺序。type类型的含义是指明indices数组的类型,比如GL10.GL_UNSIGNED_SHORT,表示indices是short类型的数组。
参考的网站:
http://insanitydesign.com/wp/projects/nehe-android-ports/