OpenGL ES初探(二) -- 用OpenGL画一个三角形(2)

时间:2021-02-24 17:49:47

OpenGL ES初探(二) – 用OpenGL画一个三角形(2)

目录

OpenGL中的投影转化

承接上一篇博客

OpenGL ES初探(一) – 用OpenGL画一个三角形(1)

在上篇最后留了一个问题:

OpenGL 坐标单位非长度的问题

那么如何解决这个问题呢?

我们继续使用上篇博客的测试代码

OpenGL-Triangle-1

其实我们大可不必去想如何改变OpenGL的视口单位规则

我们可以考虑如何以一种巧妙的形式去将我们的单位转化成OpenGL使用的单位

那么如何转化呢?

数学上有一个非常巧妙神奇的东西 – 矩阵

通过矩阵与向量的乘法我们可以实现各种几何坐标的变换,比如平移,旋转,伸缩,切换投影方式等.

引入正交投影矩阵

triangle_vertex_shader.glsl更新如下

uniform mat4 u_Matrix;
attribute vec4 a_Position;

void main() {
    gl_Position = u_Matrix * a_Position;
}

MyRenderer中添加全局变量和常量如下

    //19,定义正交矩阵相关常量和变量
    private static final String U_MATRIX = "u_Matrix";
    private static final float[] projectionMatrix = new float[16];
    private int uMatrixLocation;

MyRenderer.onSurfaceChanged的末尾添加

        //20,创建正交投影矩阵
        final float aspectRatio = height / (float) width;
        orthoM(projectionMatrix, 0, -1f, 1f,
                -aspectRatio, aspectRatio, -1f, 1f);

MyRenderer.onSurfaceCreated的注释16上面添加如下代码

        //22,获取u_Matrix在顶点着色器中的位置
        uMatrixLocation = glGetUniformLocation(program, U_MATRIX);

现在我们已经有了正交投影矩阵projectionMatrix和顶点着色器中u_Matrix的位置uMatrixLocation

传递矩阵给着色器

MyRenderer.onDrawFrame中glClear下面添加如下方法

        //23,将正交投影矩阵传递给顶点着色器
        glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0);

我们再运行下程序看看,会发现已经变成下图这样了,真的成了一个直角三角形了

OpenGL ES初探(二) -- 用OpenGL画一个三角形(2)

给着色器增加颜色属性

白色的三角形是不是显得非常单调?

其实OpenGL是支持非常强大的颜色渲染的,接下来让我们让三角形变得绚烂多彩吧

更新triangle_vertex_shader.glsl如下

uniform mat4 u_Matrix;
attribute vec4 a_Position;
attribute vec4 a_Color;

varying vec4 v_Color;
void main() {
    v_Color = a_Color;
    gl_Position = u_Matrix * a_Position;
}

更新triangle_fragment_shader.glsl如下

precision mediump float;

varying vec4 v_Color;

void main(){
    gl_FragColor = v_Color;
}

简单解释下,我们在triangle_vertex_shader中添加了aColorv_Color,接下来我们将会把我们想设置的颜色传递给a_Color,然后a_Color传递给v_Color,varying修饰的在片段着色器和顶点着色器中同名变量,片段着色器将获得顶点着色器中的值并混合,所以triangle_fragment_shader中的v_Color即拥有了我们传给三个顶点a_Color的颜色混合值,然后片段着色器将混合值赋值给了gl_FragColor

更新MyRenderer的关于triangleVertices初始化部分如下

//24,注释掉注释6的修改
    /*//6,设置三角形的三个顶点坐标: 左下(-0.5f,0f),右下(0.5f,0f),中上(0f,0.5f) private float[] triangleVertices = { -0.5f,0f, 0.5f,0f, 0f,0.5f, };*/

    //25,给triangleVertices增加颜色数组
    private float[] triangleVertices = {
            -0.5f, 0f,1f,0f,0f,//red
            0.5f, 0f,0f,0f,1f,//blue
            0f, 0.5f,1f,1f,1f,//white
    };

MyRenderer中添加如下全局属性

    //26,定义a_Color常量及位置变量
    private static final String A_COLOR = "a_Color";
    private int aColorLocation;
    //27,定义颜色值所需数字数量
    private static final int COLOR_COMPONENT_COUNT = 3;
    //28,定义数组中相邻点的字节数间隔
    private static final int STRIDE = (POSITION_COMPONENT_COUNT + 
            COLOR_COMPONENT_COUNT) * BYTES_PER_FLOAT;

更新MyRenderer.onSurfaceCreated如下

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //2,设置清空屏幕用的颜色
        glClearColor(0f, 1f, 0f, 0f);

        //9,读取shader源文件
        String vertexShaderSource = CommonUtils.readTextFromResource(context, R.raw.triangle_vertex_shader);
        String fragmentShaderSource = CommonUtils.readTextFromResource(context, R.raw.triangle_fragment_shader);

        //10,编译shader 源文件
        int vertexShader = CommonUtils.compileVertexShader(vertexShaderSource);
        int fragmentShader = CommonUtils.compileFragmentShader(fragmentShaderSource);

        //12,将shader添加进program,并获得Program的Id
        program = CommonUtils.linkProgram(vertexShader, fragmentShader);
        //13,使用这个program
        glUseProgram(program);

        //15,获得u_Color和a_Position的位置
        //一个Uniform,一个Attribute别搞错了
        uColorLocation = glGetUniformLocation(program, U_COLOR);
        aPositionLocation = glGetAttribLocation(program, A_POSITION);

        //22,获取u_Matrix在顶点着色器中的位置
        uMatrixLocation = glGetUniformLocation(program, U_MATRIX);

        //29,增加对a_Color位置的获取
        aColorLocation = glGetAttribLocation(program, A_COLOR);

        //30,注释掉16的操作
        /*//16,根据a_Position的位置将顶点数据传给a_Position vertexData.position(0); glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT, false, 0, vertexData);*/
        //31,更新跨距
        vertexData.position(0);
        glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);

        //17,激活顶点数组
        glEnableVertexAttribArray(aPositionLocation);

        //32,传输颜色数据给a_Color
        vertexData.position(POSITION_COMPONENT_COUNT);
        glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);

        //33,激活颜色数组
        glEnableVertexAttribArray(aColorLocation);
    }

片段着色器的u_Color属性已经被我们删除,所以在MyRenderer中,删除和u_Color相关的属性和方法.

详细操作不再赘述.

运行程序

会获得下图效果

OpenGL ES初探(二) -- 用OpenGL画一个三角形(2)

示例源码

OpenGL-Triangle2

参考

OpenGL ES应用开发实践指南 Android卷

相关链接

GLSL Shader常见属性说明

Android OpenGL ES 部分方法说明

OpenGL ES初探(一) – 用OpenGL画一个三角形(1)