zoukankan      html  css  js  c++  java
  • 使用OpenGL ES绘制3D图形

    如果应用定义的顶点不在同一个平面上,并且使用三角形把合适的顶点连接起来,就可以绘制出3D图形了。

    使用OpenGL  ES绘制3D图形的方法与绘制2D图形的步骤大致相同,只是绘制3D图形需要定义更多的顶点数据,而且3D图形需要绘制更多的三角形。

    使用glDrawArrays(int  mode , int  first  ,  int  count)方法绘制3D,还需要使用glDrawElements(int  mode  , int  count  , int  type , Buffer  indices)方法来组织三维空间上的多个顶点,根据indices指定的索引点来绘制三角形。该方法的第一个参数指定绘制的图形的类型,可设为GL10.GL_TRIANGLES或GL10.GL_TRIANGLE_STRIP;第二个参数指定一共包含多少个参数最重要,它包装了一个长度为3N的数组,比如让该参数包装{0,2,3,1,4,5}数组,这意味着告诉OpenGL  ES要绘制两个三角形,第一个三角形的三个顶点为0、2、3个顶点,第二个三角形的三个顶点为1、4、5个顶点。

    由此可见,如果希望在程序中使用glDrawElements(int  mode  , int  count  , int  type , Buffer   indices)方法来绘制3D图形,不仅需要指定每个3D的顶点位置信息,也需要指定3D图形的每个面由哪三个顶点组成。

    下面的程序使用glDrawElements(int  mode  , int  count  , int  type , Buffer   indices)方法绘制了两个简单的3D图形:三棱锥和立方体,该程序的Renderer实现类的代码:

    import java.nio.ByteBuffer;
    import java.nio.FloatBuffer;
    import java.nio.IntBuffer;

    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;

    import android.opengl.GLSurfaceView.Renderer;

    public class MyRenderer3 implements Renderer{
      //定义三棱锥的4个顶点
      float[] taperVertices = new float[]{
        0.0f,0.5f,0.0f,
        -0.5f,-0.5f,-0.2f,
        0.5f,-0.5f,-0.2f,
        0.0f,-0.2f,0.2f
      };
      //定义三棱锥的4个顶点的颜色
      int[] taperColors = new int[]{
        65535,0,0,0,//红色
        0,65535,0,0,//绿色
        0,0,65535,0,//蓝色
        65535,65535,0,0//黄色
      };
      //定义三棱锥的4个三角面
      private byte[] taperFacets = new byte[]{
        0,1,2,//0、1、2三个顶点组成一个面
        0,1,3,//0、1、3三个顶点组成一个面
        1,2,3,//1、2、3三个顶点组成一个面
        0,2,3//0、2、3三个顶点组成一个面
      };
      //定义立方体的8个顶点
      float[] cubeVertices = new float[]{
        //屏幕之外的正方形的四个顶点
        0.5f,0.5f,0.5f,
        0.5f,-0.5f,0.5f,
        -0.5f,-0.5f,0.5f,
        -0.5f,0.5f,0.5f,
        //屏幕之内的正方形的四个顶点
        0.5f,0.5f,-0.5f,
        0.5f,-0.5f,-0.5f,
        -0.5f,-0.5f,-0.5f,
        -0.5f,0.5f,-0.5f
      };
      //定义立方体所需要的6个面(一共是12个三角形所需的顶点)
      private byte[] cubeFacets = new byte[]{
        0,1,2,
        0,2,3,
        2,3,7,
        2,6,7,
        0,3,7,
        0,4,7,
        4,5,6,
        4,6,7,
        0,1,4,
        1,4,5,
        1,2,6,
        1,5,6
      };
      FloatBuffer taperVerticesBuffer;
      IntBuffer taperColorsBuffer;
      ByteBuffer taperFacetsBuffer;
      FloatBuffer cubeVerticesBuffer;
      ByteBuffer cubeFacetsBuffer;
      //控制旋转的角度
      private float rotate;
      public MyRenderer3(){
        //将三棱锥的顶点位置数据数组包装成FloatBuffer
        taperVerticesBuffer = FloatBuffer.wrap(taperVertices);
        //将三棱锥的四个面的数组包装成ByteBuffer
        taperFacetsBuffer = ByteBuffer.wrap(taperFacets);
        //将三棱锥的四个顶点的颜色数组包装成IntBuffer
        taperColorsBuffer = IntBuffer.wrap(taperColors);
        //将立方体的顶点位置数据数组包装成FloatBuffer
        cubeVerticesBuffer = FloatBuffer.wrap(cubeVertices);
        //将立方体的6个面(12个三角形)的数组包装成ByteBuffer
        cubeFacetsBuffer = ByteBuffer.wrap(cubeFacets);
      }

      @Override
      public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // 关闭抗抖动
        gl.glDisable(GL10.GL_DITHER);
        //设置系统对透视进行修正
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
        gl.glClearColor(0, 0, 0, 0);
        //设置阴影平滑模式
        gl.glShadeModel(GL10.GL_SMOOTH);
        //启用深度测试
        gl.glEnable(GL10.GL_DEPTH_TEST);
        //设置深度测试的类型
        gl.glDepthFunc(GL10.GL_LEQUAL);
      }

      @Override
      public void onSurfaceChanged(GL10 gl, int width, int height) {
        // 设置3D视窗的大小及位置
        gl.glViewport(0, 0, width, height);
        //将当前矩阵模式视为投影矩阵
        gl.glMatrixMode(GL10.GL_PROJECTION);
        //初始化单位矩阵
        gl.glLoadIdentity();
        //计算透视视窗的宽度、高度比
        float ratio = (float)width/height;
        //调用此方法设置透视视窗的空间大小
        gl.glFrustumf(-ratio,ratio, -1, 1, 1, 10);
      }

      @Override
      public void onDrawFrame(GL10 gl) {
        // 清除屏幕缓存和深度缓存
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
        //启用顶点坐标数据
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        //启用顶点颜色数据
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
        //设置当前矩阵模式为模型视图
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        //----------绘制第一个图形---------
        //重置当前的模型视图矩阵
        gl.glLoadIdentity();
        gl.glTranslatef(-0.6f, 0.0f, -1.5f);
        //沿着Y轴旋转
        gl.glRotatef(rotate, 0.0f, 0.2f, 0f);
        //设置顶点的位置数据
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, taperVerticesBuffer);
        //设置顶点的颜色数据
        gl.glColorPointer(4, GL10.GL_FIXED, 0, taperColorsBuffer);
        //按taperFacetsBuffer指定的面绘制三角形
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP,
        taperFacetsBuffer.remaining(), GL10.GL_UNSIGNED_BYTE,
        taperFacetsBuffer);

        //----------绘制第二个图形---------
        //重置当前的模型视图矩阵
        gl.glLoadIdentity();
        gl.glTranslatef(0.7f, 0.0f, -2.2f);
        //沿着Y轴旋转
        gl.glRotatef(rotate, 0f, 0.2f, 0f);
        //沿着X轴旋转
        gl.glRotatef(rotate, 1f, 0f, 0f);
        //设置顶点的位置数据
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeVerticesBuffer);
        //不设置顶点的颜色数据,还用以前的颜色数据
        //按cubeFacetsBuffer指定的面绘制三角形
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP,
        cubeFacetsBuffer.remaining(), GL10.GL_UNSIGNED_BYTE,
        cubeFacetsBuffer);
        //绘制结束
        gl.glFinish();
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        //旋转角度增加1
        rotate += 1;
      }

    }

    从上面的程序不难看出,绘制3D图形的步骤与绘制2D图形的步骤基本相似,区别只是绘制3D图形不仅需要定义各顶点位置的坐标,还需要定义3D图形的各个三角面由哪些顶点组成,

  • 相关阅读:
    初认识AngularJS
    (imcomplete) UVa 10127 Ones
    UVa 10061 How many zero's and how many digits?
    UVa 11728 Alternate Task
    UVa 11490 Just Another Problem
    UVa 10673 Play with Floor and Ceil
    JSON对象和字符串的收发(JS客户端用typeof()进行判断非常重要)
    HTML.ActionLink 和 Url.Action 的区别
    EASYUI TREE得到当前节点数据的GETDATA方法
    jqueery easyui tree把已选中的节点数据拼成json或者数组(非常重要)
  • 原文地址:https://www.cnblogs.com/jiww/p/5627226.html
Copyright © 2011-2022 走看看