OpenGL精简案例一
public class FRenderer implements GLSurfaceView.Renderer {
private String TAG = "Qm";
private Context context;
private float[] projectionMatrix = new float[]{
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
//图片程序
private TextureShaderProgram textureProgram;
//颜色程序
private ColorShaderProgram colorProgram;
public FRenderer(Context context) {
this.context = context;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Log.w(TAG, "onSurfaceCreated");
//设置背景清除颜色为红色。
//第一个分量是红色的,第二个是绿色的,第三个是蓝色的,最后一个分量是alpha。
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
textureProgram = new TextureShaderProgram(context);
colorProgram = new ColorShaderProgram(context);
}
/**
* 当表面发生变化时,onSurfaceChanged被调用。
* 这个函数在曲面初始化时至少被调用一次。
* 请记住,Android通常会在旋转时重启一个活动,在这种情况下,渲染器将被销毁并创建一个新的。
*
* @param gl
* @param width 新的宽度,以像素为单位。
* @param height 新的高度,以像素为单位。
*/
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.w(TAG, "onSurfaceChanged");
//设置OpenGL视口填充整个表面。
GLES20.glViewport(0, 0, width, height);
}
/**
* 每当需要绘制一个新帧时,OnDrawFrame就会被调用。通常,这是在屏幕的刷新率下完成的。
*
* @param gl
*/
@Override
public void onDrawFrame(GL10 gl) {
//清除渲染表面。
GLES20.glClear(GL_COLOR_BUFFER_BIT);
//告诉 OpenGL 使用这个程序
textureProgram.userProgram();
//把那些 uniform 传递进去
textureProgram.setUniforms(projectionMatrix);
//绘制
textureProgram.draw();
//告诉 OpenGL 使用这个程序
colorProgram.userProgram();
//把那些 uniform 传递进去
colorProgram.setUniforms(projectionMatrix);
//绘制
colorProgram.draw();
}
}
public class ShaderProgram {
protected static final String TAG = "ShaderProgram";
//程序
protected final int program;
//float字节数
protected static final int BYTES_PER_FLOAT = 4;
//矩阵句柄 实现3D
protected static final String U_MATRIX = "u_Matrix";
//图片句柄
protected static final String U_TEXTURE_UNIT = "u_TextureUnit";
//顶点着色器句柄 决定绘制位置
protected static final String A_POSITION = "a_Position";
//片段着色器句柄 决定最终渲染颜色
protected static final String A_COLOR = "a_Color";
//图片位置句柄 决定绘制图片位置
protected static final String A_TEXTURE_COORDINATES = "a_TextureCoordinates";
//矩阵句柄
protected int uMatrixLocation;
//图片句柄
protected int uTextureUnitLocation;
//顶点着色器句柄
protected int aPositionLocation;
//图片位置句柄
protected int aTextureCoordnatesLocation;
//片段着色器句柄
protected int aColorLocation;
//每行颜色着色器个数
protected int COLOR_COMPONENT_COUNT;
//每行顶点着色器个数
protected int POSITION_COMPONENT_COUNT;
//每行图片着色器个数
protected int TEXTURE_COORDINATES_COMPONENT_COUNT;
//每行间隔
protected int STRIDE;
//gl渲染的buffer
protected FloatBuffer floatBuffer;
//图片纹理
protected int bitmapTexture;
//初始化着色器
protected ShaderProgram(Context context, int vertexShaderResourceId, int fragmentShaderResourceId) {
program = ShaderHelper.buildProgram(
TextResourceReader.readTextFileFromResource(context, vertexShaderResourceId),
TextResourceReader.readTextFileFromResource(context, fragmentShaderResourceId)
);
}
//选择程序
public void userProgram() {
GLES20.glUseProgram(program);
}
/**
* 着色器渲染
* @param dataOffset 其实偏移
* @param attributeLocation 着色器句柄
* @param componentCount 渲染数量
* @param stride 行宽
*/
public void setVertexAttribPointer(int dataOffset, int attributeLocation
, int componentCount, int stride) {
//将位置设置在数据的开头处
floatBuffer.position(dataOffset);
//为着色器赋值
GLES20.glVertexAttribPointer(attributeLocation, componentCount,
GLES20.GL_FLOAT, false, stride, floatBuffer);
//指定OpenGL在哪使用顶点数组
GLES20.glEnableVertexAttribArray(attributeLocation);
//将位置设置在数据的开头处
floatBuffer.position(0);
}
//生成图片纹理
public int loadTexture(Context context, int resourceId) {
final int[] textureObjectIds = new int[1];
GLES20.glGenTextures(1, textureObjectIds, 0);
if (textureObjectIds[0] == 0) {
Log.w(TAG, "Could not generate a new OpenGL texture object.");
return 0;
}
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
if (bitmap == null) {
Log.w(TAG, "Resource ID " + resourceId + " could not be decoded");
GLES20.glDeleteTextures(1, textureObjectIds, 0);
return 0;
}
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureObjectIds[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
bitmap.recycle();
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
return textureObjectIds[0];
}
}
public class ColorShaderProgram extends ShaderProgram {
public ColorShaderProgram(Context context) {
super(context, R.raw.f_vertex_shader, R.raw.f_fragment_shader);
uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);
aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);
aColorLocation = GLES20.glGetAttribLocation(program, A_COLOR);
float[] vertexData = new float[]{
//X,Y R, G, B
0f, -0.4f, 0f, 0f, 1f,
0f, 0.4f, 1f, 0f, 0f
};
POSITION_COMPONENT_COUNT = 2;
COLOR_COMPONENT_COUNT = 3;
STRIDE = (POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) * BYTES_PER_FLOAT;
floatBuffer = ByteBuffer.allocateDirect(vertexData.length * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData);
}
//设置矩阵 呈现3D效果
public void setUniforms(float[] matrix) {
GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0);
}
public void draw() {
//把顶点数组数据和着色器程序绑定起来
setVertexAttribPointer(0, aPositionLocation, POSITION_COMPONENT_COUNT, STRIDE);
setVertexAttribPointer(POSITION_COMPONENT_COUNT, aColorLocation, COLOR_COMPONENT_COUNT, STRIDE);
//绘制
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 2);
}
}
public class TextureShaderProgram extends ShaderProgram {
public TextureShaderProgram(Context context) {
super(context, R.raw.f_texture_vertex_shader, R.raw.f_texture_fragment_shader);
uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);
uTextureUnitLocation = GLES20.glGetUniformLocation(program, U_TEXTURE_UNIT);
aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);
aTextureCoordnatesLocation = GLES20.glGetAttribLocation(program, A_TEXTURE_COORDINATES);
float[] vertexData = new float[]{
//X ,Y X, Y
0f, 0f, 0.5f, 0.5f,
-0.5f, -0.8f, 0f, 1f,
0.5f, -0.8f, 1f, 1f,
0.5f, 0.8f, 1f, 0f,
-0.5f, 0.8f, 0f, 0f,
-0.5f, -0.8f, 0f, 1f
};
POSITION_COMPONENT_COUNT = 2;
TEXTURE_COORDINATES_COMPONENT_COUNT = 2;
STRIDE = (POSITION_COMPONENT_COUNT + TEXTURE_COORDINATES_COMPONENT_COUNT) * BYTES_PER_FLOAT;
floatBuffer = ByteBuffer.allocateDirect(vertexData.length * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData);
bitmapTexture =loadTexture(context, R.drawable.air_hockey_surface);
}
//设置矩阵 呈现3D效果
public void setUniforms(float[] matrix) {
// 传递矩阵给它的 uniform
GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0);
//这个方法把活动的纹理单元 设置为纹理单元0
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
//把纹理绑定到这个单元
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, bitmapTexture);
//把被选定的纹理单元传递给片段着色器中的 uTextureUnitLocation
GLES20.glUniform1i(uTextureUnitLocation, 0);
}
public void draw() {
//把顶点数组数据和着色器程序绑定起来
setVertexAttribPointer(0, aPositionLocation, POSITION_COMPONENT_COUNT, STRIDE);
setVertexAttribPointer(POSITION_COMPONENT_COUNT, aTextureCoordnatesLocation, TEXTURE_COORDINATES_COMPONENT_COUNT, STRIDE);
//绘制
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6);
}
}
import android.annotation.SuppressLint;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.guide.opengllib.simple.c.CRenderer;
public class Simplectivity extends AppCompatActivity {
private GLSurfaceView glSurfaceView;
private GLSurfaceView.Renderer mRenderer;
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
glSurfaceView = new GLSurfaceView(this);
mRenderer = new FRenderer(this);
glSurfaceView.setEGLContextClientVersion(2);
glSurfaceView.setRenderer(mRenderer);
setContentView(glSurfaceView);
}
@Override
protected void onResume() {
super.onResume();
glSurfaceView.onResume();
}
@Override
protected void onPause() {
super.onPause();
glSurfaceView.onPause();
}
}
修饰符 | 说明 |
---|---|
none | (默认的可省略)本地变量,可读可写,函数的输入参数既是这种类型 |
const | 声明变量或函数的参数为只读类型 |
attribute | 只能存在于vertex shader中,一般用于保存顶点或法线数据,它可以在数据缓冲区中读取数据 |
uniform | 在运行时shader无法改变uniform变量, 一般用来放置程序传递给shader的变换矩阵,材质,光照参数等等. |
varying | 主要负责在vertex 和 fragment 之间传递变量 |