OpenGL ES 2.0游戏开发(下卷)
上QQ阅读APP看书,第一时间看更新

1.2 扭动的软糖

上一节介绍的飘扬的旗帜是对一个纹理矩形中的顶点位置进行了变换,本节的案例将对一个长方体中的顶点位置进行变换以实现软糖扭动的效果。

1.2.1 基本原理

介绍本案例的具体开发之前首先需要了解一下实现的基本原理,具体情况如图1-4所示。

从图1-4中可以看出,软糖模型实际上是由很多层的小矩形叠加而成。在同一帧中,随着 y坐标的不断升高此层的顶点绕中心轴扭曲的角度越大。因此,实现扭动软糖的效果只要将代表软糖的长方体中各层顶点的xz坐标按照一定的规则根据顶点的y坐标以及当前帧的控制参数进行变换即可,具体的计算思路如图1-5、图1-6与图1-7所示。

▲图1-4 软糖的线框图

▲图1-5 软糖扭曲原理图1

▲图1-6 软糖扭曲原理图2

▲图1-7 向量旋转图

具体的计算步骤如下。

● 首先如图1-5所示,需要计算出当前顶点y坐标与最下层顶点y坐标的差值。

● 接着根据 y 坐标的差值,角度换算比例以及本帧的总扭曲角度换算出当前顶点的扭曲角度,计算公式为:currAngle =(currY-startY)/ySpan×angleSpan

● 最后根据当前顶点的xz坐标,扭曲的角度计算出变换后顶点的xz坐标,此步的计算思路如图1-6与图1-7所示。

从图1-6与图1-7中可以看出,将顶点绕中心轴扭曲(旋转)实际上可以看作,将从中心点出发到变换前顶点的向量旋转指定的角度。旋转后得到的新向量的终点位置即所求的变换后顶点的位置,因此具体的计算公式如下。

x'=xcosα-zsinα

z'=xsinα+zcosα

说明

上述公式中的α为需要旋转(扭曲)的角度,实际计算时采用前面步骤计算出来的变量currAngle的值即可。

1.2.2 开发步骤

上一小节介绍了软糖扭动的基本原理,本小节将基于此原理开发一个软糖不断扭动的案例Sample1_2,其运行效果如图1-8所示。

▲图1-8 案例Sample1_2的运行效果图

说明

图1-8所示给出了4幅软糖扭动过程中的程序抓图,从左至右扭动角度不断增大。

了解了案例的运行效果后,接下来对本案例的具体开发过程进行简要介绍。由于本案例中的大部分类和前面章节很多案例中的非常类似,因此在这里只给出本案例中比较有代表性的部分,具体内容介绍如下。

(1)首先需要简单说明的是,表示软糖的长方体类Cuboid,其大部分代码与本书前面的很多案例基本一致。主要的区别是需要增加将当前帧最大扭动角度、y起始坐标、y坐标总跨度等数据传入渲染管线的相关代码,有了这些数据后顶点着色器在绘制每帧画面前就可以顺利地对顶点位置进行变换了。

提示

增加的代码非常简单,需要的读者请自行查阅随书光盘。

(2)接着需要给出的是实现软糖扭动的顶点着色器,其代码如下。

代码位置:见随书光盘中源代码/第1章/Sample1_2/ assets目录下的vertex_tex.sh。

      1    uniform mat4 uMVPMatrix;                     //总变换矩阵
      2    attribute vec3 aPosition;                    //顶点位置
      3    attribute vec2 aTexCoor;             //顶点纹理坐标
      4    varying vec2 vTextureCoord;          //用于传递给片元着色器的纹理坐标
      5    uniform float angleSpan;             //本帧扭曲总角度
      6    uniform float yStart;                //y坐标起始点
      7    uniform float ySpan;                 //y坐标总跨度
      8    void main(){
      9       float tempAS= angleSpan*(aPosition.y-yStart)/ySpan;
                                                  //计算当前顶点扭动(绕中心点选择)的角度
      10      vec3 tPosition=aPosition;
      11      if(aPosition.y>yStart){           //若不是最下面一层的顶点则计算扭动后的 xz坐标
      12        tPosition.x=(cos(tempAS)*aPosition.x-sin(tempAS)*aPosition.z);
      13        tPosition.z=(sin(tempAS)*aPosition.x+cos(tempAS)*aPosition.z);
      14      }
      15      gl_Position = uMVPMatrix * vec4(tPosition,1); //根据总变换矩阵计算此次绘制此顶点的位置
      16      vTextureCoord = aTexCoor;         //将接收的纹理坐标传递给片元着色器
      17   }

说明

上述顶点着色器根据上一小节介绍的计算过程实现了对顶点位置的变换,其中最核心的就是第12-13行根据扭动角度计算变换后顶点xz坐标的代码。