今天我们将在OpenGL路上前进一步,了解一下其绘制方式。OpenGL ES 2.0能绘制的基本图元为:点、线和三角形,当然在OpenGL中能支持更多的图元,在此则不再赘述。我们将以绘制三角形的方式来详细讲解各种绘制方式。
首先来了解一下有哪些绘制方式?(姑且把它们放在一起来说)
1.画点:GL_POINTS。
2.画线:GL_LINES、GL_LINE_STRIP、GL_LINE_LOOP。
3.画三角形:GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN。
4.顶点法绘制:glDrawArrays。
5.顶点索引法绘制:glDrawElements。
下面我们通过绘制正方形来讲解图元三角形的绘制方式以及顶点法和顶点索引法绘制图形的方式。首先看一下三角形的三种绘制方式图解:
图2.1
1.GL_TRIANGLES方式:这种方式从下面可以很明显的看出有很多重复的点,所以效率不是很高,但是如今的设备应该能承受的住。但其优点十分明显,就是一看明了,画了多少个三角形。这种绘制方式容易理解。
首先定义顶点数组并赋值:
//正方形边长 public static float STEP = 0.8f; //顶点数组 float[] mVertex1 = new float[]{//x,y,z -STEP,STEP,0, //0 -STEP,-STEP,0, //1 STEP,-STEP,0, //2 -STEP,STEP,0, //3(0) STEP,-STEP,0, //4(2) STEP,STEP,0 //5(3) }; //顶点数 mCount1 = mVertex1.length/3; //顶点数组缓冲 mVertexBuffer1 = BufferUtils.getFloatBuffer(mVertex1.length*4); mVertexBuffer1.put(mVertex1).position(0);
然后使用顶点法来绘制图形:
//使用顶点法绘制 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mCount1);
定义顶点索引数组并赋值:OpenGL ES 2.0 只支持byte和short类型。索引其实就是按照一定方式给顶点编号,从0开始。
//顶点索引数组(一般顶点很多时候,用这种索引,方便,不会出错。) byte[] mIndex1 = new byte[mCount1]; for(int i=0;i<mCount1;i++){ mIndex1[i] = (byte) i; } /** * FIXME:这种索引方式是错误的,具体原因没弄明白,但我猜测是 * 上面给顶点数组赋的值造成的。若是定义正方形的四个顶点,再 * 使用这种方式就是正确的,见第二种方式绘制。 */ // byte[] mIndex1 = new byte[]{ // 0,1,2, // 0,2,3 // }; //顶点索引缓冲 mIndexBuffer1 = BufferUtils.getByteBuffer(mIndex1.length); mIndexBuffer1.put(mIndex1).position(0);
使用顶点索引法来绘制图形:
//使用顶点索引绘画,第三个参数type必须为GL_UNSIGNED_BYTE或者GL_UNSIGNED_SHORT。这也是上面定义索引类型的原因。 GLES20.glDrawElements(GLES20.GL_TRIANGLES, mCount1, GLES20.GL_UNSIGNED_BYTE, mIndexBuffer1);
2.GL_TRIANGLE_STRIP方式:三角带方式,应该是效率最高的一种绘制方式,同一图形它定义的顶点数据最少。但当顶点数一多,人工难以确定顶点位置和顺序。
首先定义顶点数组并赋值:
/** * 如果当前顶点n是奇数: * 组成三角形的顶点排列顺序:T = [n-1, n-2, n] * 如果当前顶点n是偶数: * 组成三角形的顶点排列顺序:T = [n-2,n-1,n] * 绘画顺序为:0,1,2, 2,1,3 */ float[] mVertex2 = new float[]{//x,y,z -STEP,STEP,0, //0 -STEP,-STEP,0, //1 STEP,STEP,0, //2 STEP,-STEP,0 //3 }; mCount2 = mVertex2.length/3; mVertexBuffer2 = BufferUtils.getFloatBuffer(mVertex2.length*4); mVertexBuffer2.put(mVertex2).position(0);
下面定义顶点索引数组并赋值:
//顶点索引数组 byte[] mIndex2 = new byte[mCount2]; for(int i=0;i<mCount2;i++){ mIndex2[i]=(byte)i; } //采用GL_TRIANGLES方式绘制,mCount2=6 // byte[] mIndex2 = new byte[]{ // 0,1,2, // 2,1,3 // }; //顶点索引缓冲 mIndexBuffer2 = BufferUtils.getByteBuffer(mIndex2.length); mIndexBuffer2.put(mIndex2).position(0);
使用顶点法来绘制:
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, mCount2);
使用顶点索引法来绘制:
GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, mCount2, GLES20.GL_UNSIGNED_BYTE,mIndexBuffer2);
3.GL_TRIANGLE_FAN方式:效率居中。
首先定义顶点数组并赋值:
/** * 0,1,2, 0,2,3, 0,3,4, 0,4,5(1) */ float[] mVertex3 = new float[]{//x,y,z 0,0,0, //0 -STEP,-STEP,0, //1 STEP,-STEP,0, //2 STEP,STEP,0, //3 -STEP,STEP,0, //4 -STEP,-STEP,0 //5(1) }; mCount3 = mVertex3.length/3; mVertexBuffer3 = BufferUtils.getFloatBuffer(mVertex3.length*4); mVertexBuffer3.put(mVertex3).position(0);
定义顶点索引数组并赋值:
//顶点索引数组,采用的是GL_TRIANGLE_FAN方式来绘制。 // byte[] mIndex3 = new byte[mCount3]; // for(int i=0;i<mCount3;i++){ // mIndex3[i]=(byte)i; // } //采用的是GL_TRIANGLE_FAN方式来绘制。[第五个点就是第一个点] byte[] mIndex3 = new byte[]{ 0,1,2,3,4,1 }; //下面这种索引mCount = 12,采用的是GL_TRIANGLES方式绘制 // byte[] mIndex3= new byte[]{ // 0,1,2, 0,2,3, 0,3,4, 0,4,1 // }; //顶点索引缓冲 mIndexBuffer3 = BufferUtils.getByteBuffer(mIndex3.length); mIndexBuffer3.put(mIndex3).position(0);
使用顶点法来绘制:
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, mCount3);
使用顶点索引法来绘制:
GLES20.glDrawElements(GLES20.GL_TRIANGLE_FAN, mCount3, GLES20.GL_UNSIGNED_BYTE, mIndexBuffer3);
请小伙伴们仔细体悟顶点数组里面所取顶点顺序,还要注意一点:使用同一的绘画顺序的,逆时针或者顺时针。
本节到此结束。
源码:http://git.oschina.net/zzero.pj/SGLAndroid01
下图为GL_TRIANGLES效果图:
参考资料:
讲解GL_TRIANGLE_STRIP:http://blog.csdn.net/xiajun07061225/article/details/7455283