OpenGL ES应用开发实践指南(android 卷)笔记 第三章2

第三章 编译着色器及在屏幕上绘图

1.获取一个uniform的位置

下一步是获得我们早前在着色器中定义的uniform的位置。当OpenGL把着色器链接成一个程序的时候,它实际上用一个位置编号把片段着色器中定义的每个uniform都关联起来了。这些位置编号用来给着色器发送数据,并且我们需要u_Color的位置,以便我们可以在要绘画的时候设置颜色。

让我们快速看一下片段着色器:

precision mediump float;
uniform vec4 u_Color;

void main(){
       gl_FragColor = u_Color;
}
在这个着色器里,我们已经定义了一个称为u_Color的uniform,并在main()中把这个uniform的值赋给了gl_FragColor。我们要使用这个uniform设置将要绘制的东西的颜色;我们要绘制一张桌子、一个中间分割线和两个木槌,并且我们要使用不同的颜色绘制他们。

private static final String U_COLOR = "u_Color";
private int uColorLocation;

我们已经为这个uniform的名字创建了一个常量和一个用来容纳它在OpenGL程序对象中的位置的变量。uniform的位置并不是事先指定的,因此,一旦程序链接成功了,我们就要查询这个位置。一个uniform的位置在一个程序对象中是唯一的:即使在两个不同的程序中使用了相同的uniform名字,也不意味着它们使用相同的位置。

/**
 * 调用glGetUniformLocation()获取uniform的位置,并把这个位置存入uColorLocation;当我们稍后要更新这个uniform值的时候,我们会使用它。
 */
uColorLocation = glGetUniformLocation(program,U_COLOR);

2.获取属性的位置

像uniform一样,在使用属性之前我们也要获取它们的位置。我们可以让OpenGL自动给这些属性分配位置编号,或者在着色器被链接到一起之前,可以通过调用glBindAttribLocation()由我们自己给它们分配位置编号。我们要让OpenGL自动分配这些属性位置,因为它使代码更容易管理。

private static final String A_POSITION = "a_Position";
private int aPostionLocation;

3.OpenGL如何把坐标映射到屏幕

目前为止,我们还没有解决的一个大问题就是:OpenGL是怎样把我们已经定义的坐标映射到屏幕上的实际物理坐标的?

这个问题的答案很复杂,随着后面章节的讲解,我们会了解到更多有关的内容;目前,我们只需要知道,无论是x还是y坐标,OpenGL都会把屏幕映射到[-1,1]的范围内。这就意味着屏幕的左边对应x轴的-1,而屏幕的右边对应+1,屏幕的底边会对应y轴的-1,而屏幕的顶边就对应+1。

不管屏幕是什么形状和大小,这个坐标范围都是一样的,如果我们需要在屏幕上显示任何东西,都需要在这个范围内绘制它们。

public class FirstOpenGLRenderer implements GLSurfaceView.Renderer{

    private static final int POSITION_COMPOMENT_COUNT = 2;

    private static final int BYTES_PER_FLOAT = 4;
    private final FloatBuffer vertexData;


    private static final String U_COLOR = "u_Color";
    private int uColorLocation;

    private static final String A_POSITION = "a_Position";
    private int aPostionLocation;

    private Context mContext;
    private int program;

    public FirstOpenGLRenderer(Context context){
        this.mContext = context;
//        float[] tableVerticals = {
//            0f,0f,
//                0f,14f,
//                9f,14f,
//                9f,0f
//        };

//        float[] tableVerticesWithTriangles= {
//            0f,0f,
//                9f,14f,
//                0f,14f,
//
//                0f,0f,
//                9f,0f,
//                9f,14f,
//
//                0f,7f,
//                9f,7f,
//
//                4.5f,2f,
//                4.5f,12f
//        };

        float[] tableVerticesWithTriangles= {
                -0.5f,-0.5f,
                0.5f,0.5f,
                -0.5f,0.5f,

                -0.5f,-0.5f,
                0.5f,-0.5f,
                0.5f,0.5f,

                -0.5f,0f,
                0.5f,0f,

                0f,-0.25f,
                0f,0.25f
        };



        vertexData = ByteBuffer.allocateDirect(tableVerticesWithTriangles.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        vertexData.put(tableVerticesWithTriangles);
    }
    /**
     * 当Surface被创建的时候,GLSurfaceView会调用这个方法;
     * 这发生在应用程序第一次运行的时候,并且,当设备被唤醒或者用户从其他activity切换回来时,这个方法也可能会被调用。
     * 在实践中,这意味着,当应用程序运行时,本方法可能会被调用多次。
     * @param gl10
     * @param eglConfig
     */
    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
//        //红绿蓝透明度,渲染后结果为红色
//        gl10.glClearColor(1.0f,0.0f,0.0f,0.0f);
        gl10.glClearColor(0.0f,0.0f,0.0f,0.0f);

        String vertexShaderSource = TextResourceReader.readTextFileFromResource(mContext, R.raw.simple_vertex_shader);
        String fragmentShaderSource = TextResourceReader.readTextFileFromResource(mContext,R.raw.simple_fragment_shader);

        int vertexShader = ShaderHelper.compileVertexShader(vertexShaderSource);

        int fragmentShader = ShaderHelper.compileFragmentShader(fragmentShaderSource);

        program = ShaderHelper.linkProgram(vertexShader, fragmentShader);

        if(LoggerConfig.ON){
            ShaderHelper.validateProgram(program);
        }

        //告诉OpenGL在绘制任何东西到屏幕上的时候要使用这里定义的程序
        glUseProgram(program);

        /**
         * 调用glGetUniformLocation()获取uniform的位置,并把这个位置存入uColorLocation;当我们稍后要更新这个uniform值的时候,我们会使用它。
         */
        uColorLocation = glGetUniformLocation(program,U_COLOR);
        /**
         * 一旦着色器被链接在一起了,我们就只需要加入一些代码去获取属性位置。
         * 调用glGetAttribLocation()获取属性的位置。有了这个位置,就能告诉OpenGL到哪里去找到这个属性对应的数据了。
         */
        aPostionLocation = glGetAttribLocation(program, A_POSITION);

        /**
         * 下一步是要告诉OpenGL到哪里找到属性a_Position对应的数据
         * 在我们确保它会从开头处开始读取数据,而不是中间或者结尾处。每个缓冲区都有一个内部的指针,可以通过调用position(int)移动它
         * 并且当OpenGL从缓冲区读取时,它会从这个位置开始读取。为了保证它一定从开头出开始读取。我们调用position把位置设在数据的开头处。
         */
        vertexData.position(0);
        /**
         * 传递不正确的参数给glVertexAttribPointer()会导致奇怪的结果,甚至导致程序崩溃。
         * 这种崩溃还很难跟踪,因此,我不是言过其实,获得正确的参数是非常重要的。
         */
        glVertexAttribPointer(aPostionLocation,POSITION_COMPOMENT_COUNT,GL_FLOAT,false,0,vertexData);
        /**
         * 通过这最后一个调用,OpenGL现在就知道去哪里寻找它所需要的数据了。
         */
        glEnableVertexAttribArray(aPostionLocation);

    }

    /**
     * 在Surface被创建以后,每次Surface尺寸变化时,这个方法都会被GLSurfaceView调用到。在横屏、竖屏来回切换的时候,Surface尺寸会发生变化
     * @param gl10
     * @param width
     * @param height
     */
    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        gl10.glViewport(0, 0, width, height);
    }

    /**
     * 当绘制一帧时,这个方法会被GLSurfaceView调用。
     * 在这个方法中,我们一定要绘制一些东西,即使只是清空屏幕;
     * 因为,在这个方法返回后,渲染缓冲区会被交换并显示在屏幕上,如果什么都没画,可能会看到糟糕的闪烁效果
     * @param gl10
     */
    @Override
    public void onDrawFrame(GL10 gl10) {
        gl10.glClear(GL10.GL_COLOR_BUFFER_BIT);
        /**
         * 我们首先通过调用glUniform4f()更新着色器代码中的u_Color的值。
         * 与属性不同,uniform的分量没有默认值,因此,如果一个uniform在着色器中被定义为vec4类型,我们需要提供所有四个分量的值。
         * 我们想要以画一张白桌子作为开始,因此我们把红色、绿色和蓝色的值设置为代表完全亮度的值1.0f;阿尔法的值无关紧要,但是我们还是要指定它,因为一个颜色有四个分量。
         */
        glUniform4f(uColorLocation, 1.0f, 1.0f,1.0f,1.0f);

        /**
         * 一旦制定了颜色,接下来就可以用glDrawArrays(GLES20.GL_TRIANGLES,0,6)绘制桌子了,第一个参数告诉OpenGL,我们想要画三角形。
         * 而要话三角形,我们需要给每个三角形传递进去至少三个顶点;
         * 第二个参数告诉OpenGL从顶点数组的开头处开始读顶点;
         * 而第三个参数是告诉OpenGL读入六个顶点。因为每个三角形有三个顶点,这个调用最终会画出两个三角形
         */
        glDrawArrays(GL_TRIANGLES,0,6); //从0开始读,读6个

        glUniform4f(uColorLocation,1.0f,0.0f,0.0f,1.0f);
        glDrawArrays(GL_LINES, 6, 2); //从6开始读,读2个

        glUniform4f(uColorLocation,0.0f, 0.0f, 1.0f, 1.0f);
        glDrawArrays(GL_POINTS,8,1);

        glUniform4f(uColorLocation,0.0f,0.0f,1.0f,1.0f);
        glDrawArrays(GL_POINTS,9,1);

    }

}





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值