Android OpenGLES使用示例
正多边形
//正多边形
public class Polygon {
//顶点着色器(顶点画笔)
public final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
//片着色器(内容填充色画笔)
public final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private FloatBuffer vertexBuffer;//顶点位置数据
float[] color = new float[4];//RGBA数据
private static final int COORDS_PER_VERTEX = 3;//x,y,z三维坐标系
private final int vertexStride = COORDS_PER_VERTEX * 4;
private int positionHandle;//顶点画笔
private int colorHandle;//片画笔
private int vPMatrixHandle;//矩阵
private float[] positions;//顶点数据
public Polygon(int n, float radius, @ColorInt int color) {
this.color[0] = Color.red(color);
this.color[1] = Color.green(color);
this.color[2] = Color.blue(color);
this.color[3] = Color.alpha(color);
positions = createPositions(n, radius);//获取顶点坐标
ByteBuffer bb = ByteBuffer.allocateDirect(positions.length * 4);//预处理(格式化)顶点数据
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(positions);
vertexBuffer.position(0);
}
public void init(int mProgram) {
//获取对应画笔
positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
colorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
vPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
}
ArrayList<Float> data = new ArrayList<>();
private float[] createPositions(int n, float radius) {
data.clear();
data.add(0.0f); //设置圆心坐标
data.add(0.0f);
data.add(0.0f);
float angDegSpan = 360f / n;
for (float i = 0; i <= 360; i += angDegSpan) {
data.add((float) (radius * Math.sin(i * Math.PI / 180f)));
data.add((float) (radius * Math.cos(i * Math.PI / 180f)));
data.add(0.0f);
}
float[] f = new float[data.size()];
for (int i = 0; i < f.length; i++) {
f[i] = data.get(i);
}
return f;
}
// GL 支持画点 线 面(三角形)
public void draw(int mProgram, float[] mvpMatrix) {
int vertexCount = positions.length / COORDS_PER_VERTEX;
GLES20.glUseProgram(mProgram);
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
GLES20.glUniform4fv(colorHandle, 1, color, 0);
GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, mvpMatrix, 0);
//绘制连续三角形
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, vertexCount);
//绘制连续线条
GLES20.glDrawArrays(GLES20.GL_LINE_LOOP, 0, vertexCount);
GLES20.glDisableVertexAttribArray(positionHandle);
}
}
矩阵操作
public class MatrixUtils {
private final float[] vPMatrix = new float[16];//相机投影结果矩阵
private final float[] projectionMatrix = new float[16];//投影矩阵
private final float[] viewMatrix = new float[16];//视图矩阵/相机矩阵
private float[] operateMatrix = {1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1};//操作矩阵
private final float[] resultMatrix = new float[16];//结果矩阵
private final Stack<float[]> stack = new Stack<>();
public void pushMatrix() {
stack.push(Arrays.copyOf(operateMatrix, 16));
}
public void popMatrix() {
operateMatrix = stack.pop();
}
/**
* 投影
*/
public void frustumM(float left, float right, float bottom, float top,
float near, float far) {
Matrix.frustumM(projectionMatrix, 0, left, right, bottom, top, near, far);
}
/**
* 设置相机
*/
public void setLookAtM(float eyeX,
float eyeY,
float eyeZ,
float centerX,
float centerY,
float centerZ,
float upX,
float upY,
float upZ) {
Matrix.setLookAtM(viewMatrix, 0, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
}
/**
* 平移
*/
public void translateM(float x, float y, float z) {
Matrix.translateM(operateMatrix, 0, x, y, z);
}
/**
* 旋转
*/
public void rotateM(float angle, float axisX, float axisY, float axisZ) {
Matrix.rotateM(operateMatrix, 0, angle, axisX, axisY, axisZ);
}
/**
* 缩放
*/
public void scaleM(float scaleX, float scaleY, float scaleZ) {
Matrix.scaleM(operateMatrix, 0, scaleX, scaleY, scaleY);
}
public void orthoM(float left, float right, float bottom, float top,
float near, float far) {
Matrix.orthoM(operateMatrix, 0, left, right, bottom, top, near, far);
}
public float[] getResultMatrix() {
Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
Matrix.multiplyMM(resultMatrix, 0, vPMatrix, 0, operateMatrix, 0);
return resultMatrix;
}
}
绘制示例
public class TestView extends GLSurfaceView {
private static final String TAG = "GLES20";
private BarrageRenderer renderer;
public TestView(Context context) {
this(context, null);
}
public TestView(Context context, AttributeSet attrs) {
super(context, attrs);
setEGLContextClientVersion(2);//设置OpenGL版本
renderer = new BarrageRenderer();//画布
setRenderer(renderer);//设置画布
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);//设置刷新模式
}
private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
private float previousX;
private float previousY;
@Override
public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = x - previousX;
float dy = y - previousY;
// reverse direction of rotation above the mid-line
if (y > getHeight() / 2) {
dx = dx * -1;
}
// reverse direction of rotation to left of the mid-line
if (x < getWidth() / 2) {
dy = dy * -1;
}
renderer.setAngle(
renderer.getAngle() +
((dx + dy) * TOUCH_SCALE_FACTOR));
requestRender();
}
previousX = x;
previousY = y;
return true;
}
private static class BarrageRenderer implements GLSurfaceView.Renderer {
private Polygon mPolygon;
private int mPolygonProgram;
public volatile float mAngle;
private MatrixUtils matrixUtils;
public float getAngle() {
return mAngle;
}
public void setAngle(float angle) {
mAngle = angle;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);//清屏 设置背景色
mPolygon = new Polygon(5, 0.5f, Color.GREEN);//初始化多边形(正五边形 支持直线->圆形)
mPolygonProgram = createProgram(mPolygon.vertexShaderCode, mPolygon.fragmentShaderCode);
mPolygon.init(mPolygonProgram);
matrixUtils = new MatrixUtils();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);//设置宽高
//计算宽高比
float ratio = (float) width / height;
//以下设置保证GL绘制的图像 在不同屏幕设备上的适配
matrixUtils.frustumM(-ratio, ratio, -1, 1, 3, 7);//设置投影
matrixUtils.setLookAtM(0, 0, 7.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);//设置相机
}
float x = 0.01f;
@Override
public void onDrawFrame(GL10 gl) {
//清屏
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT);
//旋转视图矩阵
matrixUtils.rotateM(mAngle, 0, 0, 1.0f);
//平移视图矩阵
matrixUtils.translateM(x, x, x);
//绘制图像
mPolygon.draw(mPolygonProgram, matrixUtils.getResultMatrix());
}
//获取着色器 编译多边形着色器代码
private int getShader(int shaderType, String sourceCode) {
int shader = GLES20.glCreateShader(shaderType); //创建着色器 必要
if (shader != 0) {
//着色器为已编译的二进制数据时可省以下步骤
GLES20.glShaderSource(shader, sourceCode); //添加着色器代码 必要
GLES20.glCompileShader(shader); //编译 必要
int[] status = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, status, 0);
if (status[0] == 0) {
Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
GLES20.glDeleteShader(shader);
return 0;
}
}
return shader;
}
//创建OpenGL绘制程序
private int createProgram(String vertexSource, String fragmentSource) {
int vertex = getShader(GLES20.GL_VERTEX_SHADER, vertexSource);
if (vertex == 0) {
return vertex;
}
int fragment = getShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
if (fragment == 0) {
return fragment;
}
int program = GLES20.glCreateProgram();//创建程序 必要
if (program != 0) {
GLES20.glAttachShader(program, vertex);//附加着色器 必要
GLES20.glAttachShader(program, fragment);
GLES20.glLinkProgram(program);//链接程序 必要
int[] status = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, status, 0);
if (status[0] == 0) {
Log.e(TAG, GLES20.glGetProgramInfoLog(program));
GLES20.glDeleteProgram(program);
}
}
return program;
}
}
}
class MainActivity : AppCompatActivity() {
private var barrageView: TestView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
barrageView = TestView(this).also {
it.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)
}
setContentView(barrageView)
}
override fun onResume() {
super.onResume()
barrageView?.onResume()
}
override fun onPause() {
barrageView?.onPause()
super.onPause()
}
}