栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

Android APP OpenGL ES应用(01)GLSurfaceView 2D/3D绘图基础

Android APP OpenGL ES应用(01)GLSurfaceView 2D/3D绘图基础

1 Android 3D图形基础简介 1.1 OpenGL ES简介

OpenGL本身是开放图形库的一种标准,定义了一个跨语言、跨平台的编程规范,主要用于3D图形编程。OpenGLES是OpenGL的裁剪版本,主要是针对嵌入式设备/移动设备(像手机、游戏机这种等等。。。)进行裁剪后的库。对于Android设备来说主要是用OpenGL ES。从初学者角度来讲 OpenGLES和OpenGL差别不大。

OpenGL主要使用GPU进行绘图,关于CPU和GPU的对比如下所示:

CPU:计算量小,适用于复杂逻辑运算场合,适合迭代计算,通用处理器。GPU :计算量大,适用于规模简单计算场合,适合并行运算,附属处理器。

关于OpenGL基础内容以及更多了解可关注 系列文章:专题分纲目录 OpenGL教程。

Android 中提供了GLSurfaceView组件来用于现显示2D和3D图形(注意:GLSurfaceView本身并不提供绘制3D图形的功能,而是由GLSurfaceView.Render来完成SurfaceView中3D图形的绘制)。

1.2 GLSurfaceView解读

GLSurfaceView主要用于显示,GLSurfaceView.Render主要用于渲染,GL10类主要用于OpenGLES的具体操作,操作的流程相对繁琐,需要对OpenGL本身有一定了解,因此建议先查看系列文章 专题分纲目录 OpenGL教程。再来研究GL10部分代码,相关文档梳理如下:

GLSurfaceView 官方文档:Android GLSurfaceView类 详细解读GLSurfaceView.Render 官方文档:Android GLSurfaceView.Render类 详细解读GLSurfaceView的中用于操作OpenGLES的关键类为GL10,在代码中使用最多,因此也做相关解读,GLSurfaceView关键类GL10官方文档:Android OpenGLES关键类GL10 详细解读

关于具体绘制说明:OpenGL ES只能绘制三角形组成的3D图形,而OpenGL可以绘制四边形和多边形组成的3D图形。

2 GLSurfaceView 2D实战 2.1 静态三角形

实现功能:使用GL10(OpenGLES的关键类)在屏幕上显示一个三角形。

关于该程序,自定义MyRender的代码实现如下所示:

class MyRender implements GLSurfaceView.Renderer {
    //定义顶点坐标,用于顶点着色器 Vertex Shader
    private float[] triangleData = new float[] {
            0.0f, 0.5f , 0.0f ,  //上顶点
            -0.5f, 0.0f , 0.0f , //左顶点
            0.5f, 0.0f , 0.0f    //右顶点
    };

    //定义颜色数组,用于片段着色器 Fragment Shader
    private int[] triangleColor = new int[] {
            0xffff,0x0,0x0,0x0, // 上顶点红色
            0x0,0xffff,0x0,0x0, // 左顶点绿色
            0x0,0x0,0xffff,0x0  // 右顶点蓝色
    };

    //用于数据转换
    private FloatBuffer triangleDataBuffer;
    private IntBuffer triangleColorBuffer;

    public MyRender(){
        //将Vertex Shader数据转换成FloatBuffer
        triangleDataBuffer = BufferUtil.floatBufferUtil(triangleData);
        //将Fragment Shader数据转换成IntBuffer
        triangleColorBuffer = BufferUtil.intBufferUtil(triangleColor);
    }

    @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); //设置3D视窗的大小及位置
        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);//启用vertex shader 数据
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);//启用fragment shader数据
        gl.glMatrixMode(GL10.GL_MODELVIEW);//设置当前矩阵堆栈为模型堆栈

        gl.glLoadIdentity();
        gl.glTranslatef(0.0f, 0.0f, -1.2f);  // 该平移方法用于把图形绘制到可视区域
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, triangleDataBuffer);//设置vertex shader 数据
        gl.glColorPointer(4, GL10.GL_FIXED, 0, triangleColorBuffer);//设置 fragment shader数据
        gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);//根据vertex shader 和 fragment shader数据来 绘制图形
        gl.glFinish();//绘制结束
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);//禁用fragment shader 数据
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);//禁用vertex shader 数据
    }
}

代码中涉及到的工具类 BufferUtil 它的实现如下所示:

public class BufferUtil {
    //将int[]数组转换为OpenGLES所需的IntBuffer
    public static IntBuffer intBufferUtil(int[] arr)
    {
        IntBuffer buffer;
        // 初始化ByteBuffer,长度为arr数组的长度*4,因为一个int占4字节
        ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);
        bb.order(ByteOrder.nativeOrder()); //数组排列用nativeOrder
        buffer = bb.asIntBuffer();
        buffer.put(arr);
        buffer.position(0);
        return buffer;
    }
    //将float[]数组转换为OpenGLES所需的FloatBuffer
    public static FloatBuffer floatBufferUtil(float[] arr)
    {
        FloatBuffer buffer;
        //初始化ByteBuffer,长度为arr数组的长度*4,因为一个float占4字节
        ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);
        bb.order(ByteOrder.nativeOrder());
        buffer = bb.asFloatBuffer();
        buffer.put(arr);
        buffer.position(0);
        return buffer;
    }
}

在MainActivity中实现代码为:

public class MainActivity extends AppCompatActivity  {
    private static String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        GLSurfaceView glSurfaceView = new GLSurfaceView(this);
        MyRender myRender = new MyRender();
        glSurfaceView.setRenderer(myRender);
        setContentView(glSurfaceView);
    }
}
2.2 旋转三角形

实现功能:效果如下所示(绕Z轴旋转):

在2.1的基础上添加如下代码,如下所示(关注+部分即可):

class MyRender implements GLSurfaceView.Renderer {
    //...
+   private float rotate = 0.0f;
    //...
    @Override
    public void onDrawframe(GL10 gl) {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);//启用vertex shader 数据
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);//启用fragment shader数据
        gl.glMatrixMode(GL10.GL_MODELVIEW);//设置当前矩阵堆栈为模型堆栈

        gl.glLoadIdentity();
        gl.glTranslatef(0.0f, 0.0f, -1.1f);  // 该平移方法用于把图形绘制到可视区域
+       gl.glRotatef(rotate,0.0f,0.0f,-1.1f);//沿着Z轴旋转
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, triangleDataBuffer);//设置vertex shader 数据
        gl.glColorPointer(4, GL10.GL_FIXED, 0, triangleColorBuffer);//设置 fragment shader数据
        gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);//根据vertex shader 和 fragment shader数据来 绘制图形
        gl.glFinish();//绘制结束
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
+       rotate++;
    }
    //...
}
3 GLSurfaceView 3D实战 旋转彩色立方体

实现功能:效果如下所示(绕(1,1)向量轴旋转):

关于该程序,自定义MyRender的代码实现如下所示:

class MyRender implements GLSurfaceView.Renderer {
    // 定义立方体的8个顶点
    float[] cubeVertices = new float[] {
            // 前面 正方形的4个顶点
            0.5f, 0.5f, 0.5f,
            0.5f, -0.5f, 0.5f,
            -0.5f, -0.5f, 0.5f,
            -0.5f, 0.5f, 0.5f,
            // 后面 正方形的4个顶点
            0.5f, 0.5f, -0.5f,
            0.5f, -0.5f, -0.5f,
            -0.5f, -0.5f, -0.5f,
            -0.5f, 0.5f, -0.5f
    };

    // 定义立方体的8个顶点的颜色,分别对应上面8个顶点
    int[] cubeColors = new int[]{
            0xffff,0x0,0x0,0x0,   //红色
            0x0,0xffff,0x0,0x0,   //绿色
            0x0,0x0,0xffff,0x0,   //蓝色
            0xffff,0xffff,0x0,0x0,//黄色
            0xffff,0x0,0x0,0x0,   //红色
            0x0,0xffff,0x0,0x0,   //绿色
            0x0,0x0,0xffff,0x0,   //蓝色
            0xffff,0xffff,0x0,0x0,//黄色
    };

    // 定义立方体 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,
    };

    // 定义Open GL ES绘制所需要的Buffer对象
    FloatBuffer cubeVerticesBuffer;
    ByteBuffer cubeFacetsBuffer;
    IntBuffer cubeColorsBuffer;
    private float rotate = 0.0f;

    public MyRender(){
        // 将立方体的顶点位置数据数组包装成FloatBuffer
        cubeVerticesBuffer = BufferUtil.floatBufferUtil(cubeVertices);
        // 将立方体的6个面(12个三角形)的数组包装成ByteBuffer
        cubeFacetsBuffer = ByteBuffer.wrap(cubeFacets);
        cubeColorsBuffer = BufferUtil.intBufferUtil(cubeColors);
    }

    @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); //设置3D视窗的大小及位置
        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);//启用vertex shader 数据
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);//启用fragment shader数据
        gl.glMatrixMode(GL10.GL_MODELVIEW);//设置当前矩阵堆栈为模型堆栈

        gl.glLoadIdentity();
        gl.glTranslatef(0.0f, 0.0f, -5f);
        gl.glRotatef(rotate, 1.0f, 1.0f, 0f);// 沿着(1,1)向量为轴的方向旋转
        // 设置顶点的位置数据
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeVerticesBuffer);
        // 设置顶点的颜色数据
        gl.glColorPointer(4, GL10.GL_FIXED, 0, cubeColorsBuffer);
        // 按cubeFacetsBuffer指定的面绘制三角形
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP,cubeFacetsBuffer.remaining(),GL10.GL_UNSIGNED_BYTE, cubeFacetsBuffer);

        gl.glFinish();//绘制结束
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        rotate++;
    }
}

代码中涉及到的工具类 BufferUtil  和 MainAciivity代码同2.1 相同,这里不再重复。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/734056.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号