利⽤EGL在android上使⽤CC++写OpenGLES程序
很多教程都是在C/C++写的OpenGL的代码,其中有很多优秀的框架,除了前⾯提过的库外,还有很强⼤的库,从另外⼀个⾓度来看,在学习EGL的时候,很多的资料都是C语⾔的代码,我在android上写OpenGL ES的代码似乎从来没见过那些代码,不使⽤⼀下总觉得缺少点什么。
事实上,Android在native层构建OpenGL环境的步骤就如同前⾯博客中讲过的这样,在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;
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
android学习教程// 0 sinx cosx 0
// 0 0 0 1
// cosy 0 siny 0
// 0 1 0 0
// Ry =-siny 0 cosy 0
// 0 0 0 1
//
// cosz -sinz 0 0
// Rz= sinz cosz 0 0
// 0 0 1 0
/
/ 0 0 0 1
//refer to lignumcad.sourceforge/doc/en/HTML/SOHTML/TechnicalReference.html //for detailed info
void rotate_matrix(float angle, float x, float y, float z, float *M) {
double radians, c, s, c1, u[3], length;
int i, j;
radians = (angle * MYPI) / 180.0;
c = cos(radians);
s = sin(radians);
c1 = 1.0 - cos(radians);
length = sqrt(x * x + y * y + z * z);
u[0] = x / length;
u[1] = y / length;
u[2] = z / length;
for (i = 0; i < 16; i++) {
M[i] = 0.0;
}
M[15] = 1.0;
for (i = 0; i < 3; i++) {
M[i * 4 + (i + 1) % 3] = u[(i + 2) % 3] * s;
M[i * 4 + (i + 1) % 3] = u[(i + 2) % 3] * s;
M[i * 4 + (i + 2) % 3] = -u[(i + 1) % 3] * s;
}
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
M[i * 4 + j] += c1 * u[i] * u[j] + (i == j ? c : 0.0);
}
}
}
/* simulate gluPerspectiveMatrix
* //return perspective projection matrix
* cot(fovy/2) / aspect 0 0 0
* 0 cot(fovy/2) 0 0
* 0 0 (znear+zfar)/(znear-zfar) 2*znear*zfa/(znear-zfar)
* 0 0 -1 0
*/
void perspective_matrix(float fovy, float aspect, float znear, float zfar, float *M) {
int i;
double f;
load_identity(M);
f = 1.0/tan(fovy * 0.5);
M[0] = f / aspect;
M[5] = f;
M[10] = (znear + zfar) / (znear - zfar);
M[11] = -1.0;
M[14] = (2.0 * znear * zfar) / (znear - zfar);
M[15] = 0.0;
}
//Multiplies A by B and output to C, a tmp buffer is used to support in-place multiplication
void multiply_matrix(float *A, float *B, float *C) {
int i, j, k;
float tmpM[16];
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
tmpM[j * 4 + i] = 0.0;
for (k = 0; k < 4; k++) {
tmpM[j * 4 + i] += A[k * 4 + i] * B[j * 4 + k];
}
}
}
for (i = 0; i < 16; i++) {
C[i] = tmpM[i];
}
}
不过我觉得这都是不必要的⼯作,很浪费时间,事实上有⼀个⾮常强⼤的数学库glm(
)主要还体现在它是为OpenGL开发⼈员量⾝定做的,和使⽤着⾊器语⾔⼀样,使⽤很⽅便。我在这个Demo中主要⽤了它的设置摄像机矩阵、投影矩阵。
#include "glm/mat4x4.hpp"
#include "glm/ext.hpp"
glm::mat4 projection;
glm::mat4 view;
//glm::mat4 module;
projection = glm::ortho(-1.0f, 1.0f, -(float) height / width, (float) height / width, 5.0f,
7.0f);
view = glm::lookAt(glm::vec3(0.0f, 0.0f, 6.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f));
// 矩阵相乘太⽅便
glm::mat4 mvpMatrix = projection * view/* * module*/;
/
/ 装换成数组形式
float *mvp = (float *) glm::value_ptr(mvpMatrix);
mShape.draw(mvp);
在Java层使⽤EGL
其实在这篇博客中已经接触到了Java层的EGL使⽤了,GLSurfaceView继承⾃SurfaceView,我们⽤它来写OpenGL代码很⽅便,就是因为它已经封装好了创建EGL环境的部分了,如果看GLSurfaceView的代码必然可以看到前⾯讲EGL部分的时候创建EGL环境的相关函数调⽤。
不过由于GLSurfaceView代码⽐较多,下⾯是我⾃⼰写的⼀个类似GLSurfaceView的类,写的很简略,⽤其来替代系统的GLSurfaceView即可。显然这样做⽤来了解Java层EGL的使⽤是⾜够的。
⾥⾯有部分代码我是参考GLSurfaceView的源码的。
ample.opengles_circle;
import f.WeakReference;
import javax.l.EGL10;
import javax.l.EGLConfig;
import javax.l.EGLContext;
import javax.l.EGLDisplay;
import javax.l.EGLSurface;
t.Context;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MyGLSurfaceView extends SurfaceView implements SurfaceHolder.Callback{
public SurfaceHolder mHolder;
public Renderer mRenderer;
private final WeakReference<MyGLSurfaceView> mThisWeakRef = new WeakReference<MyGLSurfaceView>(this);
Object mLock = new Object();
private GLThread mThread;
public MyGLSurfaceView(Context context) {
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
}
public void setRenderer(Renderer renderer) {
mRenderer = renderer;
mThread = new GLThread(mThisWeakRef);
mThread.start();
}
public void surfaceCreated(SurfaceHolder holder) {
mThread.surfaceCreated();
}
public void surfaceDestroyed(SurfaceHolder holder) {
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论