OpenGL精简案例二

文章目录

    • 书接上回
    • OpenGL图片渲染
    • Renderer
    • 程序基类
    • 颜色程序
    • 图片程序
    • 应用场景
    • glsl 解析
    • 变量限定符

书接上回

OpenGL精简案例一

OpenGL图片渲染

OpenGL精简案例二_第1张图片
OpenGL精简案例二_第2张图片
OpenGL精简案例二_第3张图片
OpenGL精简案例二_第4张图片

Renderer


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();
    }
}

glsl 解析

OpenGL精简案例二_第5张图片

变量限定符

修饰符 说明
none (默认的可省略)本地变量,可读可写,函数的输入参数既是这种类型
const 声明变量或函数的参数为只读类型
attribute 只能存在于vertex shader中,一般用于保存顶点或法线数据,它可以在数据缓冲区中读取数据
uniform 在运行时shader无法改变uniform变量, 一般用来放置程序传递给shader的变换矩阵,材质,光照参数等等.
varying 主要负责在vertex 和 fragment 之间传递变量

你可能感兴趣的:(opengl)