Andriod OpenGL 教程 02 - 第一个多边形

来源:互联网 发布:香港有淘宝网吗 编辑:程序博客网 时间:2024/03/28 19:26

关键字: android OpenGL 移动开发 教程

        在第一课的基础上,我们添加了一个三角形和一个四边形,在这里我们使用glDrawElements方法来绘制我们的第一个三角形和使用glDrawArrays来绘制我们的第一个四边形,来演示在OpenGL ES中怎样绘制最基本的图元。

        在OpenGL ES中不支持glVertex方法,因此在绘制三角形和四边形的方法和NeHe教程中的方法有所不同。为了是程序条理清楚,我们分别实现MyTriangleMySquare来绘制我们的一个三角形和四边形。

        现在假设MyTriangl MySquare已经实现好,在后面详细叙述这两个类的实现。在MyGLRenderonDrawFrame中的代码如下:

public void onDrawFrame(GL10 gl){// 清除屏幕和深度缓存gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);// 重置当前的模型观察矩阵gl.glLoadIdentity();// 左移 1.5 单位,纵深向里移动 6.0gl.glTranslatef(-1.5f,0.0f,-6.0f);// 画三角形triangle.draw(gl);// 右移3单位gl.glTranslatef(3.0f,0.0f,0.0f);// 画四边形quad.draw(gl);}

        当我们调用glLoadIdentity ()之后,实际上将当前点移到了屏幕中心,X坐标轴从左至右,Y坐标轴从下至上,Z坐标轴从里至外。OpenGL屏幕中心的坐标值是XY轴上的0.0f点。中心左面的坐标值是负值,右面是正值。移向屏幕顶端是正值,移向屏幕底端是负值。移入屏幕深处是负值,移出屏幕则是正值。

        glTranslatef(x, y, z)沿着 X, Y Z轴移动。根据前面的次序,下面的代码沿着X轴左移1.5个单位,Y轴不动(0.0f),最后移入屏幕6.0f个单位。注意在glTranslatef(x, y, z)中移动的时候,它并不是相对屏幕中心移动,而是相对与当前所在的屏幕位置。

        现在我们已经移到了屏幕的左半部分,并且将视图推入屏幕背后足够的距离以便我们可以看见全部的场景-创建三角形。triangle.draw(gl)来完成我们的第一个三角形绘制。

         在屏幕的左半部分画完三角形后,我们要移到右半部分来画正方形。为此要再次使用glTranslate。这次右移,所以X坐标值为正值。因为前面左移了1.5个单位,这次要先向右移回屏幕中心(1.5个单位),再向右移动1.5个单位。总共要向右移3.0个单位。quad.draw(gl)来完成我们的第一四边形的绘制。

MyTriangle.java:

package wintop.gllesson02;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import javax.microedition.khronos.opengles.GL10;//  一个三角形包含三个顶点public class MyTriangle {private FloatBuffer vertexBuffer;// 顶点数组缓冲区private ByteBuffer  indexBuffer;// 顶点索引缓冲区private float[] vertices = {// 三角形的顶点 0.0f,  1.0f, 0.0f,// 0. 顶-1.0f, -1.0f, 0.0f,// 1. 左下角 1.0f, -1.0f, 0.0f// 2. 右下角};private byte[] indices = {0, 1, 2};// 顶点索引(逆时针方向 CCW)// 构造函数 - 设置顶点数组public MyTriangle(){// 设置顶点数组,顶点数据为浮点数据类型。一个浮点类型的数据长度为四个字节ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);vbb.order(ByteOrder.nativeOrder());// 使用原生字节顺序vertexBuffer = vbb.asFloatBuffer();// 将字节类型缓冲区转换成浮点类型vertexBuffer.put(vertices);// 将数据复制进缓冲区vertexBuffer.position(0);// 定位到初始位置// 设置索引数组,索引数据位字节类型indexBuffer = ByteBuffer.allocateDirect(indices.length);indexBuffer.put(indices);indexBuffer.position(0);}// 渲染三角形public void draw(GL10 gl) {// 使能顶点数据并指定顶点数据缓冲区gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);// 通过索引数组绘制图元gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);}}


 

        然后我们分配一个顶点数组缓冲区,并将数据传送到缓冲区中。在这里我们使用nio类型的缓冲区,这是因为这种类型的缓冲区位于原生堆中,不会使用垃圾收集机制。

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

        vbb.order(ByteOrder.nativeOrder());   // 使用原生字节顺序

        vertexBuffer = vbb.asFloatBuffer();   //将字节类型缓冲区转换成浮点类型

        vertexBuffer.put(vertices);       //将数据复制进缓冲区

        vertexBuffer.position(0);         //定位到初始位置

        为了使用顶点数组渲染方式,我们必须使能client-state vertex-array

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

       我们可以直接使用glDrawArrays()方法来直接渲染顶点数组,或者使用glDrawElements()方法通过索引数组来渲染。

       在这里我们使用了索引数组,顶点按逆时针方向(CCW)进行索引,法向为屏幕向外(Z轴方向)

      //设置索引数组,索引数据位字节类型

      indexBuffer = ByteBuffer.allocateDirect(indices.length);

      indexBuffer.put(indices);

      indexBuffer.position(0);

      在draw()方法中实现我们第一个三角形的渲染。

      首先,我们使能client-state vertex-array

      gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

      然后,我们通过缓冲区指定位置:

      gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);  

      // gl*Pointer(int size, int type, int stride, Buffer pointer)

      // size: 每个顶点的坐标数目 (必须为 2, 3, or 4).

     // type: 顶点坐标数据类型, GL_BYTE, GL_SHORT, GL_FIXED, or GL_FLOAT

     // stride: 两个连续顶点间偏移的字节数.

     最后我们使用glDrawElements()来绘制三角形。该方法使用索引数组来引用顶点和颜色值。

    gl.glDrawElements(GL10.GL_TRIANGLES, numIndices, GL10.GL_UNSIGNED_BYTE, indexBuffer);

    // glDrawElements(int mode, int count, int type, Buffer indices)

    // mode: GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, or GL_TRIANGLES

 // count: 要渲染的顶点数目.

// type: 索引数据类型(必须为 GL_UNSIGNED_BYTE GL_UNSIGNED_SHORT).

// indices: 索引数组指针.

gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

 

MySquare.java

package wintop.gllesson02;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import javax.microedition.khronos.opengles.GL10;// 使用三角形带(TRIANGLE_STRIP)绘制一个正方形public class MySquare {private FloatBuffer vertexBuffer;// 顶点数组缓冲区private float[] vertices = {// 正方形的顶点数据-1.0f, -1.0f, 0.0f,// 0.左下角 1.0f, -1.0f, 0.0f,// 1.右下角-1.0f,  1.0f, 0.0f,// 2.左上角 1.0f,  1.0f, 0.0f,// 3.右上角};// 构造函数  - 设置顶点缓冲区public MySquare() {// 设置顶点数组,顶点数据为浮点数据类型。一个浮点类型的数据长度为四个字节ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);vbb.order(ByteOrder.nativeOrder());// 使用原生字节顺序vertexBuffer = vbb.asFloatBuffer();// 将字节类型缓冲区转换成浮点类型vertexBuffer.put(vertices);// 将数据复制进缓冲区vertexBuffer.position(0);// 定位到初始位置}// 渲染正方形public void draw(GL10 gl){// 使能顶点数据并指定顶点数据缓冲区gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);// 通过顶点数组直接绘制图元序列gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length/3);gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);}}


       OpenGL ES中四边形不是图元,因为我们需要用两个三角形来实现绘制四边形。我们使用TRIANGLE_STRIP,按逆时针方向组合两个三角形V0V1V2V2V1V3。如下图所示

      最后运行结果如图所示:

 

源代码下载地址:http://download.csdn.net/detail/seniorwizard/4460814

原创粉丝点击