安卓中绘制2D、3D图形

时间:2023-02-06 21:28:10

一、概述

偶然看到一个游戏的人物动画,联想到在安卓中绘制3D图形,因为基本在平时的开发中基本都是用canvas绘制自定义View,很少使用这些图形的绘制,因此借此机会练练基本操作,国际惯例看下运行效果

安卓中绘制2D、3D图形
这个gif有BUG,开始我以为没录上,所以期动后愣了一会才反应过来,所以有一些卡顿,凑活看吧。。。。

二、OpenGL与OpenGL ES

OpenGl的全称 Open Graphics Library即开放的图形接口,它定义了一个跨编程语言、跨平台的编程接口规范,它主要用于三维图形的绘制,但在手机等手持终端上运行OpenGl有些不太合适,因此安卓系统内置的是OpenGL ES。

三、2D图形的绘制

先来点简单的部分,万一直接来复杂的部分,吓跑同学怎么办。。。
在Activity中使用:

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        GLSurfaceView glSurfaceView = new GLSurfaceView(this);
        MyRenderer renderer = new MyRenderer();
        glSurfaceView.setRenderer(renderer);
        setContentView(glSurfaceView);
    }

代码很简单,仔细看代码,就可以看出来里面除了创建GLSurfaceView的对象外,只有MyRenderer,一看便知道基本代码中以My开头的类,都是自己实现的子类,所以2D图形绘制也一样,最主要的就是提供一个Renderer;

public class MyRenderer implements GLSurfaceView.Renderer {


    public MyRenderer() {
       triangleDataBuffer = floatBufferUtil(triangleData);
        rectDataBuffer = floatBufferUtil(rectData);
        rectDataBuffer2 = floatBufferUtil(rectData2);
        pentacleBuffer = floatBufferUtil(pentacle);
        triangleColorBuffer = intBufferUtil(triangleColor);
        rectColorBuffer = intBufferUtil(rectColor);

    }

    @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) {
        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.32f,0.35f,-1.2f);
        //设置定点数据
        gl.glVertexPointer(3, GL10.GL_FLOAT,0,triangleDataBuffer);
        //设置颜色数据
        gl.glColorPointer(4, GL10.GL_FIXED,0,triangleColorBuffer);
        //绘制图形
        gl.glDrawArrays(GL10.GL_TRIANGLES,0,3);

        gl.glLoadIdentity();
        gl.glTranslatef(0.6f,0.8f,-1.5f);
        gl.glRotatef(rotate,0f,0f,0.1f);
        gl.glVertexPointer(3, GL10.GL_FLOAT,0,rectDataBuffer);
        gl.glColorPointer(4, GL10.GL_FIXED,0,rectColorBuffer);
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);

        gl.glLoadIdentity();
        gl.glTranslatef(-0.4f,-0.5f,-1.5f);
        gl.glRotatef(rotate,0f,0.2f,0f);
        gl.glVertexPointer(3, GL10.GL_FLOAT,0,rectDataBuffer2);
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);

        gl.glLoadIdentity();
        gl.glTranslatef(0.4f,-0.5f,-1.5f);
        gl.glVertexPointer(3, GL10.GL_FLOAT,0,pentacleBuffer);

        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,5);

        gl.glFinish();
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

        rotate +=1;

    }

创建MyRenderer实现Renderer,重写

  • onDrawFrame(GL10 gl) ;Renderer对象调用该方法绘制GLSurfaceView当前帧
  • onSurfaceChanged();当GLSurfaceView的大小改变时回调该方法
  • onSurfaceCreated();当GLSurfaceView创建时调用

    具体每个方法详情请参考上面代码中的注释,这里偷个懒不想一一解释了,另外里面定义两个方法intBufferUtil()和floatBufferUtil()将矩阵转换为Buffer:

  private IntBuffer intBufferUtil(int[] ints){
        IntBuffer mBuffer;
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(ints.length*4);
        byteBuffer.order(ByteOrder.nativeOrder());
        mBuffer = byteBuffer.asIntBuffer();
        mBuffer.put(ints);
        mBuffer.position(0);
        return  mBuffer;
    }

   private FloatBuffer floatBufferUtil(float[] floats){
        FloatBuffer mBuffer;
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(floats.length*4);
        byteBuffer.order(ByteOrder.nativeOrder());
        mBuffer = byteBuffer.asFloatBuffer();
        mBuffer.put(floats);
        mBuffer.position(0);
        return  mBuffer;
    }

到此为止2D图形绘制完成,离最终目标只差一步,就是让图形旋转起来,其实很简单就是一个旋转属性

 gl.glRotatef(rotate,0f,0.2f,0f);

四、3D图形绘制

只需修改Renderer,其余像2D图形绘制一样,如果我们按前面的过程绘制出3D效果,那么如何按顺序组织三维空间的每个顶点,为了解决此方法,安卓提供了glDrawElements(int mode, int count ,int type, Buffer indices),参数:

  • mode; 绘制图形的类型,GL10.GL_TRIANGLE_STRIP或GL10.GL_TRIANGLE
  • count ;顶点数量
  • indices;顶点坐标数据源,注意的是一维数组,每三个数字代表一个顶点

其余都参照2D,这里只贴出不一样的部分:

 //重置当前的模型试图矩阵
        gl.glLoadIdentity();
        //控制图形中心位置
        gl.glTranslatef(-0.6f,0.0f,-1.5f);
        gl.glRotatef(rotate,0f,0.2f,0f);
        //设置定点数据
        gl.glVertexPointer(3, GL10.GL_FLOAT,0,taperVerticesBuffer);
        //设置颜色数据
        gl.glColorPointer(4, GL10.GL_FIXED,0,taperColorBuffer);
        //绘制图形
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP,taperFacetsBuffer.remaining(), GL10.GL_UNSIGNED_BYTE,taperFacetsBuffer);

到此大功告成,代码很简单只做一个简单的演示;

点击下载源码