irpas技术客

Android APP OpenGL ES应用(01)GLSurfaceView 2D/3D绘图基础_图王大胜_glsurfaceview 绘制图片

irpas 8227

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 相同,这里不再重复。


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #glsurfaceview #绘制图片 #1 #Android