opengles主要是看的<android游戏开发技术宝典>,还有opengles1.0的视频 https://yunpan.cn/OcxubipBdNZdX3 访问密码 fc4c 视频是1.0的,已经过时了,不用在意细节 但是很多思想在2.0同样适用 如果有不懂的地方 不妨看看视频吧,虽然书是游戏开发,但是绘制复杂的特效,绝对高大上,先从最简单的开始,绘制一个三角形,目录结构很简单,就一个java文件,两个glsl文件
package com.example.es1;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.app.Activity;
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// TODO 1 new GLSurfaceView
setContentView(new MSur(this));
}
}
class MSur extends GLSurfaceView {
Render render;
public MSur(Context context) {
super(context);
// TODO 2 设置GLES版本
this.setEGLContextClientVersion(2);
render = new Render(context);
// TODO 3 设置GLSurfaceView回掉
setRenderer(render);
this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
}
class Render implements GLSurfaceView.Renderer {
private int vCount;
private Context ctx;
private FloatBuffer fbv;
private FloatBuffer fbc;
static float[] mMMatrix = new float[16];
int mProgram;// 自定义渲染管线程序id
int muMVPMatrixHandle;// 总变换矩阵引用id
int maPositionHandle; // 顶点位置属性引用id
int maColorHandle; // 顶点颜色属性引用id
public static float[] mProjMatrix = new float[16];// 4x4矩阵 投影用
public static float[] mVMatrix = new float[16];// 摄像机位置朝向9参数矩阵
public static float[] mMVPMatrix;// 最后起作用的总变换矩阵
public Render(Context ctx) {
super();
this.ctx = ctx;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0, 0, 0, 1.0f);
// TODO 4 初始化顶点 颜色数据
initVertex();
// TODO 5 初始化shader
initShader();
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO 6 设置视口
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
// TODO 7 设置投影
Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 1, 10);
// TODO 8 设置摄像机
Matrix.setLookAtM(mVMatrix, 0, 0, 0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
// TODO 9 绘制
draw();
}
private void initVertex() {
// TODO 4_1 初始化顶点数据
float v[] = { 1f, -1f, 0, 0, 1f, 0, -1f, -1f, 0 };
vCount = v.length / 3;
ByteBuffer bb = ByteBuffer.allocateDirect(v.length * 4);
bb.order(ByteOrder.nativeOrder());
fbv = bb.asFloatBuffer();
fbv.put(v);
fbv.position(0);
// TODO 4_2 初始化颜色数据
float vc[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
ByteBuffer cbb = ByteBuffer.allocateDirect(vc.length * 4);
cbb.order(ByteOrder.nativeOrder());
fbc = cbb.asFloatBuffer();
fbc.put(vc);
fbc.position(0);
}
public void draw() {
GLES20.glUseProgram(mProgram);
Matrix.setRotateM(mMMatrix, 0, 0, 0, 1, 0);
// TODO 9_1 设置总变换矩阵
mMVPMatrix = new float[16];
Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// TODO 9_2 设置顶点
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
false, 3 * 4, fbv);
// TODO 9_3 设置颜色
GLES20.glVertexAttribPointer(maColorHandle, 4, GLES20.GL_FLOAT, false,
3 * 4, fbc);
GLES20.glEnableVertexAttribArray(maPositionHandle);
GLES20.glEnableVertexAttribArray(maColorHandle);
// TODO 9_4 绘制三角形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
}
private void initShader() {
String vertex = loadSH("vertex.sh");
String shader = loadSH("frag.sh");
// TODO 5_1 创建顶点
int verS = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
if (verS != 0) {
GLES20.glShaderSource(verS, vertex);
GLES20.glCompileShader(verS);
}
// TODO 5_2 创建颜色
int fragS = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
if (fragS != 0) {
GLES20.glShaderSource(fragS, shader);
GLES20.glCompileShader(fragS);
}
mProgram = GLES20.glCreateProgram();
if (mProgram != 0) {
GLES20.glAttachShader(mProgram, verS);
GLES20.glAttachShader(mProgram, fragS);
GLES20.glLinkProgram(mProgram);
}
// TODO 5_3 关联glsl变量
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
maColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
}
//将sh文件加载进来
private String loadSH(String fname) {
String result = null;
try {
InputStream in = ctx.getAssets().open(fname);
int ch = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((ch = in.read()) != -1) {
baos.write(ch);
}
byte[] buff = baos.toByteArray();
baos.close();
in.close();
result = new String(buff, "UTF-8");
result = result.replaceAll("\\r\\n", "\n");
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
frag.sh文件 片元文件
precision mediump float;
varying vec4 vColor; //接收从顶点着色器过来的参数
void main()
{
gl_FragColor = vColor;//给此片元颜色值
}
vertex.sh 顶点文件
uniform mat4 uMVPMatrix; //总变换矩阵
attribute vec3 aPosition; //顶点位置
attribute vec4 aColor; //顶点颜色
varying vec4 vColor; //用于传递给片元着色器的变量
void main()
{
gl_Position = uMVPMatrix * vec4(aPosition,1); //根据总变换矩阵计算此次绘制此顶点位置
vColor = aColor;//将接收的颜色传递给片元着色器
}
效果: