NO.4 OpenGl 色彩过渡&正投影

零蚀


前言

  • 步骤如下:
    • step 1:实现一个三色揉合的三角形,从案例出发,解释其用法和原理。

    • step 2:长宽比问题。利用矩阵完成正投影。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Khc4LrVN-1590555261337)(media/15903801694064/15905549900085.jpg)]


色彩设置

  • 介绍
    • 之前都是直接限定死了一个元素对象的色彩,比如之前的三角形,线,点,在这一篇里会设置它不同颜色糅合的情况,然后还会设置阴影。之前我们是如何限定死只渲染了一种颜色的呢?首先我们在顶点着色器里面定义了一个v_Color,这个是干嘛的,它是控制顶点着色的,然后这个参数,会将色值传递给片段着色器的v_Color,然后再由gl_FragColor = v_Color;来设置片段着色器的颜色。

    • 而我们实在java里int uColorLocation=glGetUniformLocation获取了颜色(顶点着色器)的参数,然后通过GLES20.glUniform4f(uColorLocation , Rf, Gf, Bf, Af);对这个v_Color进行赋值。

    • Opengl给我们一种相对而言不损耗过多性能的方案,就是,通过设置图形的每个点颜色,来起到颜色平滑过度的效果。我们要让整个桌面看起来有灯照效果,所以要将,平面的中心点的颜色设置起来,这样,就可以通过中点到四周呈光亮度降低的感觉。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UD4sQnVl-1590555261338)(media/15903801694064/15903824261383.jpg)]

      代码上我们一刻这么写

      //  one
      0,     0,
      -0.5f, -0.5f,
      0.5f, -0.5f,
      // two
      0,     0,
      0.5f, -0.5f,
      -0.5f,  0.5f,
      // three
      0 ,0,
      0.5f,  0.5f,
      -0.5f,  0.5f,
      // four
      0.0f,0.0f,
      -0.5f,  0.5f,
      -0.5f, -0.5f,
      
    • 然后我们可以重新定义我们桌子的顶点,除了正常的xy之外,还要添加RGB来控制每个点的颜色,我们以一个三角形为例,大致结果如下所示:

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DQWcD5yE-1590555261339)(media/15903801694064/15903949356902.jpg)]

  • 代码&解释
    • 首先我们需要设置我们的三角形的顶点的坐标和颜色,修改之前的坐标样式,这里每一行5个参数,代表一个坐标点,坐标的含义对应着 x,y,r, g 。(Android中的颜色例如Color.red色值范围是(0-255),而opengl中的色值是(0-1))

      static float tableVertices[] = {
          // Triangle one
          0f,       0f,  0f,   1f,   1f,
          -0.5f, -0.5f,  1f,   0f,   1f,
          0.5f,  -0.5f,  0f,   1f,   1f,
      }
      
    • OpenGL ES 三种类型修饰 uniform,attribute``````varying

      • 1、uniform它是application通过glUniform**进行赋值的,它相当于一个常量,shader只能用不能改动,uniform修饰的变量在vertex和fragment中完全是一样的话,则说明这个变量是在vertex和fragment之间进行共享,相当于他们之间的全局变量,

      • 2、attribute只能在vertex中使用,一般它用来描述一个顶点的数据,如顶点坐标,纹理坐标,法线,顶点颜色.etc,用glBindAttribLocation来绑定每个attribute变量的位置,然后用函数glVertexAttribPointer()为每个attribute变量赋值。

      • 3、varying变量是vertex和fragment shader之间做数据传递用的,一般vertex shader修改varying变量的值,然后fragment shader使用该varying变量的值,因此varying变量在vertex和fragment shader二者之间的声、明必须是一致的。application不能使用此变量(uniform是外部传入,这个是内部传入)

    • 然后我们来看一下OpenGL里面关于着色器的设置:

      • 片段着色器:这里我们改变固定的uniform传入的数据,改用varying,让顶点着色器来传递色值。

        precision mediump float;
        //uniform vec4 v_Color;
        varying vec4 v_Color;
        void main() {
            gl_FragColor = v_Color;
        }
        
      • 顶点着色器:这里我们除了需要坐标的位置,还需要传递的颜色值,传递的着标点的颜色给fragment后,opengl会根据这些坐标值进行计算,构建出光滑的颜色过渡。

        attribute vec4 a_Position;
        attribute vec4 a_Color;
        varying vec4 v_Color;
        void main() {
            v_Color = a_Color;
            gl_Position = a_Position;
            gl_PointSize = 20.0;
        }
        
      • 然后我们需要获取到OpenGL的参数a_Color,将参数传递给它,由它通知顶点和片段着色器来实现颜色的揉合,所以我们可以获取一下我们需要的颜色参数:

        // ShaderHelp
        public static final String A_COLOR="a_Color";
        public static int getAColorLocation(int programId){
            return GLES20.glGetAttribLocation(programId,A_COLOR);
        }
        
      • 然后就是Renderer里面的参数配比了,我们这里的坐标有5个点,前两个是坐标,后三个是颜色,所以,我们要告诉OpenGL从哪开始读,然后隔多少位继续读(偏移量),所以,之前我们设置了坐标positoin的元素个数POSITION_COMPONENT_COUNT=2,我们还要添加色彩的元素个数的参数COlOR_COMPONENT_COUNT=3,这样我们就有了最基本的两个记录位置的。

      • 那么我们如何告诉OpenGL绘制的方式,他怎么知道前两个是坐标,后三个是颜色呢?,我们在onSurfaceCreated里面可以实现如下的代码:

        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            GLES20.glClearColor(0.0f,0.0f,0.0f,0.0f);
        
            int program =ShaderHelp.linkShader(context);
            if(program!=0){
                // 坐标点的设置
                vertexBuffer.position(0);
                int positionLocation = ShaderHelp.getPositionLocation(program);
                GLES20.glVertexAttribPointer(
                        positionLocation,
                        POSITION_COMPONENT_COUNT,
                        GLES20.GL_FLOAT,
                        false,
                        BYTES_FLOAT*(POSITION_COMPONENT_COUNT+COlOR_COMPONENT_COUNT),
                        vertexBuffer);
                        
                GLES20.glEnableVertexAttribArray(positionLocation);
        
                // 坐标颜色的设置
                vertexBuffer.position(POSITION_COMPONENT_COUNT); //
        
                int aColorLocation = ShaderHelp.getAColorLocation(program);
                // 抛弃v_Color赋值 uColorLocation = ShaderHelp.getColorLocation(program);
                // 关联java和OpenGl的数据
                GLES20.glVertexAttribPointer(
                        aColorLocation,
                        COlOR_COMPONENT_COUNT,
                        GLES20.GL_FLOAT,
                        false,
                        BYTES_FLOAT*(POSITION_COMPONENT_COUNT+COlOR_COMPONENT_COUNT),
                        vertexBuffer);
                GLES20.glEnableVertexAttribArray(aColorLocation);
        
            }
        }
        
      • 这里首先我们开始坐标点的设置,我们要告诉opengl 坐标的读取是从头开始读取的position(0),且读取的偏移量(跨度)为BYTES_FLOAT*(POSITION_COMPONENT_COUNT+COlOR_COMPONENT_COUNT)这是xyRGB的字节长度(一个坐标点),然后呢,我们可以看到,第一个赋值的是a_Position,把数组里的位置坐标传递了过去,每次赋值长度为POSITION_COMPONENT_COUNT,然后我们设置了颜色的读取位置position(POSITION_COMPONENT_COUNT)是从坐标之后开始读取,然后每次读取也是一个坐标的字节长度,然后把数值传递给了a_Color,到此OpenGL已经拿到了数值&颜色值,我们不需要再传任何数值过去了,

      • 这里我们不需要在通过glUniform4f来给v_Color赋值设置固定的颜色,所以我们可以注掉相关的代码,也不需要glGetUniformLocation来获取v_Color。所以我们的渲染类onDrawFrame代码里只需要下列的代码就可以了。

        @Override
        public void onDrawFrame(GL10 gl) {
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
        }    
        
      • 如此我们可以获取上面的一个三色杂糅的三角形了。


比例

  • 一个问题
    • 其实在我们绘制的时候opengl知道了要如何去绘制,但是,在一些情况下,比如绘制结束,横屏竖屏的情况下,由于长宽比不同而导致,图像变形的问题。如下图所示,我们的三角形被压扁了。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cn3AOboY-1590555261341)(media/15903801694064/15904677160668.jpg)]

    • 在解决问题前,我们要了解一些知识,1、正投影:它是正向对物体的投影,无论远近都不会改变问题的形状和比例。2、单位矩阵:任何向量✖️单位矩阵都是向量本身,3、转换矩阵:利用向量和矩阵的乘积来改变向量的结果。具体的内容就不解释了,感兴趣,网上有很多。

    • 首先为了解决问题,我们需要设置一个正投影,通过更新着色器,给着色器添加矩阵来设置我们的位置。我们在顶点着色器来控制我们的正投影的矩阵(4x4)。

      // simple_vertex_shader.glsl
      attribute vec4 a_Position;
      attribute vec4 a_Color;
      varying vec4 v_Color;
      
      
      uniform mat4 u_Matrix;
      
      void main() {
          v_Color = a_Color;
          gl_Position =  u_Matrix * a_Position;;
          gl_PointSize = 20.0;
      }
      
    • 然后我们获取这个参数

      //ShaderHelp
      private static final String U_MATRIX = "u_Matrix";
      public static int getMatrixLocation(int programId){
          return  GLES20.glGetUniformLocation(programId, U_MATRIX);
      }
      
    • 我们还需要在java中创建一个矩阵来传递参数给我们的opengl,

      // Renderer
      private final float[] projectionMatrix = new float[16];
           @Override
          public void onSurfaceCreated(GL10 gl, EGLConfig config) {
          .....
          // 获取到u_Matrix在java中的对象
          matrixLocation = ShaderHelp.getMatrixLocation(program);
          .....
          }
      
    • 将我们坐标变化的参数值传递给我们的矩阵,这里用到了android.opengl.Matrix里的方法orthoM,参数不说,都有提示,然后这个aspectRatio是宽高比,也就是无论横竖屏都是这个值,我们把短的那一边定义为1(防止图像溢出),那么长的一边的坐标长度就是[-aspectRatio,aspectRatio],这个区间,所以我们可以如下设置,将后面的参数设置放入第一个参数的矩阵中。

      @Override
      public void onSurfaceChanged(GL10 gl, int width, int height) {
          GLES20.glViewport(0,0,width,height);
          final float aspectRatio = width > height ? (float)width/(float)height:(float)height/(float)width;
          if(width>height){
              // 横屏 landscapes
              Matrix.orthoM(projectionMatrix,0,-aspectRatio,aspectRatio,-1f, 1f, -1f, 1f);
          }else{
              // 竖屏 portrait
              Matrix.orthoM(projectionMatrix,0,-1f, 1f, -aspectRatio,aspectRatio,-1f, 1f);
      
          }
      }
      
    • 最后我们根据矩阵描绘出图形,这里也是运用了glUniformMatrix4fv将矩阵信息传给了OpenGL然后由OpenGL绘制出矩阵对应的图像。

      @Override
      public void onDrawFrame(GL10 gl) {
          GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
          GLES20.glUniformMatrix4fv(matrixLocation, 1, false, projectionMatrix, 0);
          GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
          
      }
      

      在这里插入图片描述


🔗 前言
🔗 OpenGL ES 篇
🔗 NO.1 OpenGL ES 前言
🔗 NO.2 从OpenGL与GC的矛盾说起
🔗 NO.3 OpenGl 着色器-绘制
🔗 NO.5 OpenGl 第三维度
🔗 NO.6 OpenGl 纹理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零蚀zero eclipse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值