很多教程都是在C/C++写的OpenGL的代码,其中有很多优秀的框架,除了前面提过的Assimp库外,还有很强大的库glm,从另外一个角度来看,在学习EGL的时候,很多的资料都是C语言的代码,我在android上写OpenGL ES的代码似乎从来没见过那些代码,不使用一下总觉得缺少点什么。
事实上,Android在native层构建OpenGL环境的步骤就如同前面博客OpenGL ES EGL介绍中讲过的这样,在Java层,与EGL相关的操作我们也看不到,其实都是由GLSurfaceView封装好了。
因此这篇博客就研究一下怎么使用Native代码写OpenGL ES代码和如何利用EGL自己创建OpenGL的环境。最终包含:
1.使用Native代码+GLSurfaceView写的六边形,这里会介绍到glm库。
2.Java代码自己写一个功能类似GLSurfaceView的类,主要是在java层使用EGL自己创建OpenGL的环境,思想上参考了GLSurfaceView的源码。
3.全部使用native代码写的六边形。Java层仅用了SurfaceView,余下的功能全部在native层实现。
先贴上效果图,这三幅图分别是上面描述的三个程序执行得到的结果。
第一幅图是第一篇写OpenGL入门的时候使用的Demo,我用本博客第二部分写的MySurfaceView替换了系统自带的GLSurfaceView执行的效果。
第一幅图和三幅图也是画一个六边形,只是没有旋转,大小并且都是用AndroidStudio创建的项目。
使用Native代码+GLSurfaceView
这种方式其实就是将GLSurfaceView.Renderer的几个回调函数在native层实现,算是体验C/C++写OpenGL代码的第一步吧。Render类大概就是下面的样子
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
String vetexShaderStr = LoadShaderStr(mContext, R.raw.vshader);
String fragmentShaderStr = LoadShaderStr(mContext, R.raw.fshader);
// native
nativeInit(vetexShaderStr, fragmentShaderStr);
}
@Override
public void onDrawFrame(GL10 gl) {
// native
nativeDraw(mAngleX, mAngleY);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// native
nativeSurfaceChanged(width, height);
}
public static native void nativeInit(String vertexShaderCode, String fragmentShaderCode);
private static native void nativeDraw(float angleX, float angleY);
private static native void nativeSurfaceChanged(int width, int height);
}
在native层要做的事情其实和前面用java语言写的代码是类似的,无外乎就是写一个六边形的类,函数名也是一致的,因此写起来很简单。
使用Java代码的时候在android.opengl包中有个很方便的类Matrix,里面封装了矩阵的相关操作,设置投影、摄像机矩阵、矩阵相乘等操作都被封装好了,在C/C++中可没有这个类,不过也不是难事。Android Native Development Kit Cookbook一书的作者就封装了相关操作。
#ifndef MATRIX_H
#define MATRIX_H
#include <math.h>
#define MYPI 3.14159265358979323846
void translate_matrix(float tx, float ty, float tz, float *M);
void scale_matrix(float xs, float ys, float zs, float *M);
void rotate_matrix(float angle, float x, float y, float z, float *M);
void perspective_matrix(float fovy, float aspect, float znear, float zfar, float *M);
void multiply_matrix(float *A, float *B, float *M);
#endif
#include "matrix.h"
//all matrix are in column-major order
//the 4x4 matrix are stored in an array as shown below
//0-15 indicates the array index
//0 4 8 12
//1 5 9 13
//2 6 10 14
//3 7 11 15
void load_identity(float *M) {
for (int i = 0; i < 16; ++i) {
M[i] = 0.0f;
}
M[0] = 1.0f;
M[5] = 1.0f;
M[10] = 1.0f;
M[15] = 1.0f;
}
//return translation matrix
// 1 0 0 tx
// 0 1 0 ty
// 0 0 1 tz
// 0 0 0 1
void translate_matrix(float tx, float ty, float tz, float *M) {
load_identity(M);
M[12] = tx;
M[13] = ty;
M[14] = tz;
}
//return scaling matrix
// sx 0 0 0
// 0 sy 0 0
// 0 0 sz 0
// 0 0 0 1
void scale_matrix(float sx, float sy, float sz, float *M) {
load_identity(M);
M[0] *= sx;
M[5] *= sy;
M[10] *= sz;
}
//return rotation matrix
//R = Rx*Ry*Rz
// 1 0 0 0
// Rx = 0 cosx -sinx 0
// 0 sinx cosx 0
// 0 0