Android为例编写⼀个OpenGLES3.0实例,NativeJava两种实现⼀、简介
通过这个 Sample,你将了解到 Android 中是怎么使⽤ OpenGL ES
通过绘制⼀个简单的静态三⾓形,来简单⼊门和了解它⼤致的流程(类似于 HelloWorld ⼯程)
介绍使⽤ Native 层 和 Java 层 两种⽅式来分别实现
本⽂暂不介绍具体的语法,但会给⽐较详细的注释和解释,帮助你理解
如果你还不了解 OpenGL ES 3.0 的渲染管线流程,建议你先了解⼀下。
传送门:
⼆、Native 实现
1. 头⽂件
由于我们使⽤的是 OpenGL ES 3.0,所以主要使⽤此头⽂件:<GLES3/gl3.h>
2. Activity
最终还是要显⽰在 Activity 上的,所以我们先准备这样⼀个 Activity,它直接使⽤ GLSurfaceView 作为 contentView。
public class SampleActivity extends AppCompatActivity {
private static final String TAG ="SampleActivity";
public static final String TYPE_NAME ="type";
public static final int TYPE_NATIVE =0;
public static final int TYPE_JAVA =1;
private GLSurfaceView mGlSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState){
if(!checkOpenGLES30()){
Log.e(TAG,"con't support OpenGL ES 3.0!");
finish();
}
mGlSurfaceView =new GLSurfaceView(this);
mGlSurfaceView.setEGLContextClientVersion(3);
mGlSurfaceView.setRenderer(getRenderer());
mGlSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
setContentView(mGlSurfaceView);
}
private GLSurfaceView.Renderer getRenderer(){
Intent intent =getIntent();
int type = IntExtra(TYPE_NAME, TYPE_NATIVE);
Log.d(TAG,"type: "+ type);
GLSurfaceView.Renderer renderer;
if(type == TYPE_NATIVE){
renderer =new NativeRenderer(this);
}else{
renderer =new JavaRenderer(this);
}
return renderer;
}
private boolean checkOpenGLES30(){
ActivityManager am =(ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); ConfigurationInfo info = am.getDeviceConfigurationInfo();
qGlEsVersion >=0x30000);
}
@Override
protected void onPause(){
}
@Override
protected void onResume(){
}
}
3. Renderer
我们先介绍 NativeRenderer 的实现,如下:
public class NativeRenderer implements GLSurfaceView.Renderer {
private Context mContext;
static{
System.loadLibrary("native-renderer");
}
public NativeRenderer(Context context){
mContext = context;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config){
Assets());
glInit();
}
@Override
public void onSurfaceChanged(GL10 gl,int width,int height){
glResize(width, height);
}
@Override
public void onDrawFrame(GL10 gl){
glDraw();
}
public native void registerAssetManager(AssetManager assetManager);
public native void glInit();
public native void glResize(int width,int height);
public native void glDraw();
}
主要定义了4个 native 的⽅法,需要我们在 native 层实现。
4. ShaderUtils
说实现之前,我们先写⼀个⼯具类,负责加载和创建。⼯具类的作⽤就是可以重复使⽤的:
#include"ShaderUtils.h"
#include<stdlib.h>
#include"LogUtils.h"
GLuint LoadShader(GLenum type,const char*shaderSource){
// 1. create shader
GLuint shader =glCreateShader(type);
if(shader == GL_NONE){
LOGE("create shader failed! type: %d", type);
return GL_NONE;
}
/
/ 2. load shader source
glShaderSource(shader,1,&shaderSource,NULL);
// 3. compile shared source
glCompileShader(shader);
// 4. check compile status
GLint compiled;
glGetShaderiv(shader, GL_COMPILE_STATUS,&compiled);
if(compiled ==0){// compile failed
GLint len =0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH,&len);
if(len >1){
char*log =static_cast<char*>(malloc(sizeof(char)* len));
glGetShaderInfoLog(shader, len,NULL, log);
LOGE("Error compiling shader: %s", log);
free(log);
free(log);
}
glDeleteShader(shader);// delete shader
return0;
}
return shader;
}
GLuint CreateProgram(const char*vertexSource,const char*fragmentSource){
// 1. load shader
GLuint vertexShader =LoadShader(GL_VERTEX_SHADER, vertexSource);
if(vertexShader ==0){
LOGE("load vertex shader failed! ");
return0;
}
GLuint fragmentShader =LoadShader(GL_FRAGMENT_SHADER, fragmentSource); if(vertexShader ==0){
LOGE("load fragment shader failed! ");
return0;
}
// 2. create gl program
GLuint program =glCreateProgram();
安卓开发实例入门if(program ==0){
LOGE("create program failed! ");
return0;
}
// 3. attach shader
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
// we can delete shader after attach
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// 4. link program
glLinkProgram(program);
// 5. check link status
GLint linked;
glGetProgramiv(program, GL_LINK_STATUS,&linked);
if(linked ==0){// link failed
GLint len =0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH,&len);
if(len >1){
char*log =static_cast<char*>(malloc(sizeof(char)* len));
glGetProgramInfoLog(program, len,NULL, log);
LOGE("Error link program: %s", log);
free(log);
}
glDeleteProgram(program);// delete program
return0;
}
return program;
}
char*readAssetFile(const char*filename, AAssetManager *mgr){
if(mgr ==NULL){
LOGE("pAssetManager is null!");
return NULL;
}
AAsset *pAsset =AAssetManager_open(mgr, filename, AASSET_MODE_UNKNOWN); off_t len =AAsset_getLength(pAsset);
char*pBuffer =(char*)malloc(len +1);
pBuffer[len]='\0';
int numByte =AAsset_read(pAsset, pBuffer, len);
LOGD("numByte: %d, len: %d", numByte, len);
AAsset_close(pAsset);
return pBuffer;
}
}
5. NativeRenderer.cpp
终于到了我们的渲染实现了,主要就是实现之前定义的那⼏个 native ⽅法:
#include"com_afei_openglsample_NativeRenderer.h"
#include<android/asset_manager_jni.h>
#include<GLES3/gl3.h>
#include"LogUtils.h"
#include"ShaderUtils.h"
GLuint g_program;
GLint g_position_handle;
AAssetManager *g_pAssetManager =NULL;
JNIEXPORT void JNICALL Java_com_afei_openglsample_NativeRenderer_glInit (JNIEnv *env, jobject instance){
char*vertexShaderSource =readAssetFile("vertex.vsh", g_pAssetManager);
char*fragmentShaderSource =readAssetFile("fragment.fsh", g_pAssetManager);
g_program =CreateProgram(vertexShaderSource, fragmentShaderSource);
if(g_program == GL_NONE){
LOGE("gl init failed!");
}
// vPosition 是在 'vertex.vsh' ⽂件中定义的
GLint g_position_handle =glGetAttribLocation(g_program,"vPosition");
LOGD("g_position_handle: %d", g_position_handle);
glClearColor(0.0f,0.0f,0.0f,1.0f);// 背景颜⾊设置为⿊⾊ RGBA (range: 0.0 ~ 1.0)
}
JNIEXPORT void JNICALL Java_com_afei_openglsample_NativeRenderer_glResize (JNIEnv *env, jobject instance, jint width, jint height){
glViewport(0,0, width, height);// 设置视距窗⼝
}
JNIEXPORT void JNICALL Java_com_afei_openglsample_NativeRenderer_glDraw (JNIEnv *env, jobject instance){
GLint vertexCount =3;
// OpenGL的世界坐标系是 [-1, -1, 1, 1]
GLfloat vertices[]={
0.0f,0.5f,0.0f,// 第⼀个点(x, y, z)
-0.5f,-0.5f,0.0f,// 第⼆个点(x, y, z)
0.5f,-0.5f,0.0f// 第三个点(x, y, z)
};
glClear(GL_COLOR_BUFFER_BIT);// clear color buffer
// 1. 选择使⽤的程序
glUseProgram(g_program);
// 2. 加载顶点数据
glVertexAttribPointer(g_position_handle, vertexCount, GL_FLOAT, GL_FALSE,3*4, vertices); glEnableVertexAttribArray(g_position_handle);
// 3. 绘制
glDrawArrays(GL_TRIANGLES,0, vertexCount);
}
JNIEXPORT void JNICALL Java_com_afei_openglsample_NativeRenderer_registerAssetManager (JNIEnv *env, jobject instance, jobject assetManager){
if(assetManager){
g_pAssetManager =AAssetManager_fromJava(env, assetManager);
}else{
LOGE("assetManager is null!")
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论