Android OpenGL ES 示例教程:打造你的第一个 3D 应用
本教程将引导你一步步创建一个简单的 Android OpenGL ES 应用,绘制一个旋转的彩色三角形。我们将涵盖 OpenGL ES 的基础知识,包括着色器、缓冲区、变换等概念,并结合代码示例进行详细讲解。
一、设置开发环境
确保你的 Android Studio 已安装并配置了必要的 SDK 和 NDK。创建一个新的 Android 项目,选择 “Empty Activity” 模板。
二、添加 OpenGL ES 依赖
在 app/build.gradle
文件中添加以下依赖:
gradle
dependencies {
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}
三、创建 GLSurfaceView
GLSurfaceView
是用于渲染 OpenGL ES 图形的视图。在你的布局文件中添加一个 GLSurfaceView
:
xml
<android.opengl.GLSurfaceView
android:id="@+id/glSurfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
四、创建 Renderer
Renderer
接口负责绘制 OpenGL ES 图形。创建一个名为 TriangleRenderer
的类,实现 GLSurfaceView.Renderer
接口:
“`java
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class TriangleRenderer implements GLSurfaceView.Renderer {
private Triangle mTriangle;
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private final float[] mRotationMatrix = new float[16];
private float mAngle;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 设置背景颜色
mTriangle = new Triangle();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height); // 设置视口
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); // 清除屏幕
// 设置相机位置
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// 计算变换矩阵
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
// 创建旋转变换
float[] scratch = new float[16];
Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
// 绘制三角形
mTriangle.draw(scratch);
mAngle += 0.5f; // 旋转角度递增
}
}
“`
五、创建 Triangle 类
Triangle
类负责存储三角形的顶点数据和绘制逻辑。
“`java
import android.opengl.GLES20;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public class Triangle {
private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
private FloatBuffer vertexBuffer;
private final int COORDS_PER_VERTEX = 3;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
static float triangleCoords[] = { // in counterclockwise order:
0.0f, 0.622008459f, 0.0f, // top
-0.5f, -0.311004243f, 0.0f, // bottom left
0.5f, -0.311004243f, 0.0f // bottom right
};
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
public Triangle() {
ByteBuffer bb = ByteBuffer.allocateDirect(triangleCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(triangleCoords);
vertexBuffer.position(0);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glLinkProgram(mProgram);
}
public void draw(float[] mvpMatrix) {
GLES20.glUseProgram(mProgram);
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, triangleCoords.length / COORDS_PER_VERTEX);
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
public static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
“`
六、在 Activity 中初始化
在你的 Activity
中,获取 GLSurfaceView
并设置渲染器:
“`java
import android.opengl.GLSurfaceView;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView glSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
glSurfaceView = new GLSurfaceView(this);
//设置OpenGL ES版本
glSurfaceView.setEGLContextClientVersion(2);
glSurfaceView.setRenderer(new TriangleRenderer());
setContentView(glSurfaceView);
}
@Override
protected void onPause(){
super.onPause();
glSurfaceView.onPause();
}
@Override
protected void onResume(){
super.onResume();
glSurfaceView.onResume();
}
}
“`
七、运行应用
现在你可以运行你的应用,应该会看到一个绕 Z 轴旋转的彩色三角形。
八、进阶学习
- 纹理映射:学习如何将图像应用于 3D 对象。
- 光照:学习如何模拟光照效果,使 3D 场景更加逼真。
- 模型加载:学习如何加载复杂的 3D 模型。
- 更复杂的着色器:学习如何编写更高级的着色器,实现更丰富的视觉效果.
本教程提供了一个简单的 OpenGL ES 入门示例,希望能帮助你开启 Android 3D 图形编程之旅。 通过不断学习和实践,你可以创建更复杂、更精美的 3D 应用。 记住,理解 OpenGL ES 的核心概念是关键,这将帮助你更好地掌握 3D 图形编程技巧。 不断探索和尝试,你将能够创造出令人惊叹的视觉效果。