3D图像的绘制使用的是 OpenGL ES,所以我们先介绍 OpenGL ES。
OpenGL 是一组跨平台的 3D 图像处理 API,OpenGL ES 是 OpenGL 的嵌入式版本,Android 系统从 Android 1.0 开始支持 OpenGL ES 1.0 和 1.1,自 Android 2.2(API Level 8)开始,Android 框架开始支持 OpenGL 2.0 API。
在这里仅介绍其使用方法。详细资料可以查询 Android SDK 的相关文档。
使用 OpenGL ES API 绘制 3D 图像有两个基础的相关类,一个是 GLSurfaceView 类,另一个是 GLSurfaceView.Renderer 接口。
GLSurfaceView 类是 SurfaceView 的子类,使用内嵌的 Surface 进行 OpenGL 绘图渲染。GLSurfaceView 提供以下功能:
GLSurfaceView.Renderer 接口定义了使用 OpenGL 绘图时所需的方法。该接口通过 GLSurfaceView.setRenderer() 与 GLSurfaceView 关联在一起。
该接口实现以下三个方法。
实例 OpenGLDemo 演示了在 Activity 中使用 GLSurfaceView 和 GLSurfaceView.Renderer 合作绘制三维图形的过程。
该实例绘制了一个不断旋转的立方体,运行效果如图 1 所示。
图 1 实例OpenGLDemo的运行效果
该立方体为 MyCube 类的对象。MyCube.java 的代码如下:
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import javax.microedition.khronos.opengles.GL10;
class MyCube {
private IntBuffer vertexBuffer;
private IntBuffer colorBuffer;
private ByteBuffer indexBuffer;
public MyCube() {
int one = 65536;
int vertex[] = {
-one, -one, -one, one, -one, -one,
one, one, -one,
-one, one, -one,
-one, -one, one,
one, -one, one,
one, one, one,
-one, one, one
};
int colors[] = {
0, 0, 0, one,
one, 0, 0, one,
one, one, 0, one,
0, one, 0, one,
0, 0, one, one,
one, 0, one, one,
one, one, one, one,
0, one, one, one
};
byte index[] = {
0, 4, 5, 0, 5, 1,
1, 5, 6, 1, 6, 2,
2, 6, 7, 2, 7, 3,
3, 7, 4, 3, 4, 0,
4, 7, 6, 4, 6, 5,
3, 0, 1, 3, 1, 2
};
ByteBuffer vbb = ByteBuffer.allocateDirect(vertex.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asIntBuffer();
vertexBuffer.put(vertex);
vertexBuffer.position(0);
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length);
cbb.order(ByteOrder.nativeOrder());
colorBuffer = cbb.asIntBuffer();
colorBuffer.put(colors);
colorBuffer.position(0);
indexBuffer = ByteBuffer.allocateDirect(index.length);
indexBuffer.put(index);
indexBuffer.position(0);
}
public void draw(GL10 gl) {
gl.glFrontFace(GL10.GL_CW);
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vertexBuffer);
gl.glColorPointer(4, GL10.GL_FIXED, 0, colorBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, indexBuffer);
}
}
该立方体被显示在 GLSurfaceView 对象中,由 GLSurfaceView.Renderer 接口绘制。GLSurfaceView 在主 Activity 的 onCreate() 方法中被创建,相关代码如下:
package introduction.android.openglDemo;
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
public class OpenGLDemoActivity extends Activity {
private GLSurfaceView myGLSurfaceView;
/**
* Called when the activity is first created.
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myGLSurfaceView = new GLSurfaceView(this);
myGLSurfaceView.setRenderer(new CubeRenderer());
setContentView(myGLSurfaceView);
}
@Override
protected void onResume() {
super.onResume();
myGLSurfaceView.onResume();
}
@Override
protected void onPause() {
super.onPause();
myGLSurfaceView.onPause();
}
}
其中:
指定了 GLSurfaceView 的渲染器为 CubeRenderer,由该渲染器控制图像绘制过程。渲染器被定义在 CubeRenderer.java 中,具体代码如下:
package introduction.android.openglDemo;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
class CubeRenderer implements GLSurfaceView.Renderer {
private MyCube myCube;
private float roate;
public CubeRenderer() {
myCube = new MyCube();
}
public void onDrawFrame(GL10 gl) {
//填充屏幕
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT)
//设置模型视景矩阵为当前操作矩阵
gl.glMatrixMode(GL10.GL_MODELVIEW);
//将坐标原点移动到屏幕中心
gl.glLoadIdentity();
//移动坐标系
gl.glTranslatef(0, 0, -3.0f);
//在Y轴方向旋转坐标系
gl.glRotatef(roate, 0, 1, 0);
//在X轴方向旋转坐标系
gl.glRotatef(roate * 0.25f, 1, 0, 0);
//开启顶点坐标
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//开启颜色
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
//绘制图形
myCube.draw(gl);
roate += 1.0f;
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
float ratio = (float) width / height;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glEnable(GL10.GL_CULL_FACE);
gl.glClearColor(0.5F, 0.5F, 0.5F, 1.0F);
}
}