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的代码实现如下所示:文章来源:https://www.toymoban.com/news/detail-419716.html
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 相同,这里不再重复。文章来源地址https://www.toymoban.com/news/detail-419716.html
到了这里,关于Android APP OpenGL ES应用(01)GLSurfaceView 2D/3D绘图基础的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!