返回
点亮Android OpenGL ES
Android
2024-01-10 08:39:44
OpenGL ES是一个跨平台的图形库,它提供了对图形硬件的访问,允许开发人员创建交互式的、硬件加速的2D和3D图形。Android从2.0开始支持OpenGL ES,并提供了许多API来帮助开发人员使用OpenGL ES。
在本教程中,我们将创建一个使用OpenGL ES绘制三角形的应用程序。我们将使用NDK来构建这个应用程序,因为NDK允许我们使用C/C++来编写Android应用程序。
首先,我们需要创建一个新的Android项目。可以在Android Studio中创建一个新的项目,并选择“Empty Activity”作为模板。
接下来,我们需要添加NDK支持。可以在项目的build.gradle文件中添加以下代码:
android {
...
externalNativeBuild {
ndkBuild {
path "src/main/jni/Android.mk"
}
}
}
然后,我们需要创建一个新的JNI模块。可以在项目的src/main目录下创建一个名为jni的目录,并在其中创建一个名为Android.mk的文件。Android.mk文件的内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := native-lib
LOCAL_SRC_FILES := native-lib.cpp
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
接下来,我们需要创建一个名为native-lib.cpp的文件,并将其放在src/main/jni目录下。native-lib.cpp文件的内容如下:
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jni.h>
// Vertex shader code
const char *vertexShaderCode =
"attribute vec4 vPosition;"
"attribute vec2 vTexCoord;"
"varying vec2 texCoord;"
"void main() {"
" gl_Position = vPosition;"
" texCoord = vTexCoord;"
"}";
// Fragment shader code
const char *fragmentShaderCode =
"precision mediump float;"
"uniform sampler2D tex;"
"varying vec2 texCoord;"
"void main() {"
" gl_FragColor = texture2D(tex, texCoord);"
"}";
// Create a shader program
GLuint createShaderProgram() {
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderCode, NULL);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderCode, NULL);
glCompileShader(fragmentShader);
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus != GL_TRUE) {
GLchar infoLog[512];
glGetProgramInfoLog(program, sizeof(infoLog), NULL, infoLog);
printf("Error linking program: %s\n", infoLog);
return 0;
}
return program;
}
// Create a texture from a raw image file
GLuint createTextureFromRawImage(const char *filename) {
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
FILE *file = fopen(filename, "rb");
if (file == NULL) {
printf("Error opening file: %s\n", filename);
return 0;
}
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
unsigned char *buffer = (unsigned char *)malloc(fileSize);
fread(buffer, 1, fileSize, file);
fclose(file);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
glGenerateMipmap(GL_TEXTURE_2D);
free(buffer);
return texture;
}
// Create a vertex buffer object
GLuint createVertexBufferObject(const GLfloat *vertices, GLsizeiptr size) {
GLuint vertexBufferObject;
glGenBuffers(1, &vertexBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
return vertexBufferObject;
}
// Create a vertex array object
GLuint createVertexArrayObject(GLuint vertexBufferObject) {
GLuint vertexArrayObject;
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
// Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid *)0);
glEnableVertexAttribArray(0);
// TexCoord attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid *)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
return vertexArrayObject;
}
// Initialize the OpenGL ES context
void initOpenGL() {
// Create a shader program
GLuint program = createShaderProgram();
glUseProgram(program);
// Create a texture from a raw image file
GLuint texture = createTextureFromRawImage("res/raw/image.raw");
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
// Create a vertex buffer object
GLfloat vertices[] = {
// Position // TexCoord
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // Bottom left
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // Bottom right
0.0f, 0.5f, 0.0f, 0.5f, 1.0f, // Top
};
GLuint vertexBufferObject = createVertexBufferObject(vertices, sizeof(vertices));
// Create a vertex array object
GLuint vertexArrayObject = createVertexArrayObject(vertexBufferObject);
// Set the clear color
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
// Render a frame
void renderFrame() {
// Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT);
// Bind the vertex array object
glBindVertexArray(vertexArrayObject);
// Draw the triangle
glDrawArrays(GL_TRIANGLES, 0, 3);
// Unbind the vertex array object
glBindVertexArray(0);
}
// JNI function to initialize the OpenGL ES context
JNIEXPORT void JNICALL Java_com_example_opengles_MainActivity_initOpenGL(JNIEnv *env, jobject obj) {
initOpenGL();
}
// JNI function to render a frame
JNIEXPORT void JNICALL Java_com_example_opengles_MainActivity_renderFrame(JNIEnv *env, jobject obj) {
renderFrame();
}
接下来,我们需要在MainActivity.java文件中添加以下代码:
package com.example.opengles;
import android.app.Activity;
import android.graphics.SurfaceTexture;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
public class MainActivity extends Activity implements SurfaceTexture.OnFrameAvailableListener {
private GLSurfaceView glSurfaceView;
private MyRenderer renderer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
glSurfaceView = new GLSurfaceView(this);
renderer = new MyRenderer();
glSurfaceView.setEGLContextClientVersion(2);
glSurfaceView.setRenderer(renderer);
glSurfaceView.setOnFrameAvailableListener(this);
setContentView(glSurfaceView);
}
@Override
protected void onPause() {
super.onPause();
glSurfaceView.onPause();
}
@Override
protected void onResume() {
super.onResume();
glSurfaceView.onResume