利用shader来实现飘扬的旗帜,同样可以实现水面起伏的效果.

说多无益,来看一张实现的美图,蔚蓝的天,还有那阵阵微风,水浪徐徐波动,动人心悸.

Unity Shader之波浪效果_矩阵计算



一.原理


旗帜飘扬的动作都比较平滑,这个是利用了正弦曲线来实现顶点位置的变换规则,


Unity Shader之波浪效果_Unity Shader之波浪效果_02


简单看一下上图,水波利用先定义的一个函数来计算Y方向的移动,在VertexShader里面调用此函数来实现模型在Y轴方向的位置,并随着时间而起伏,实现类似波浪和旗帜飘扬的效果.

看一下效果图


Unity Shader之波浪效果_矩阵计算_03


代码实现:


float ReturnY( VS_INPUT In )
  {
    // --------------------- shader 1 -----------------------
    // 设置比较点,
    float3 fZero = float3( 0.0 ,0.0 , 0.0 );
    //振动值
    float fScale = sin(1.40*distance(In.Position, fZero) - g_fTime * 5) + 1.5;
    //随距离衰减

    float fY = -1.0 * exp( - fScale ) +1.0 ;
    //; 
    return max( fY , -4.0 );
  }

VS_OUTPUT RenderSceneVS( VS_INPUT In )
  {
    
    VS_OUTPUT Out = ( VS_OUTPUT )0;
    In.Position.y = ReturnY( In );
      
    float4x4 matWorldView = mul( g_matWorld ,g_matView );
    float4x4 matWorldViewProject = mul( matWorldView ,g_matProject );
    Out.Position = mul( In.Position , matWorldViewProject );
    Out.TextureUV = In.TextureUV;
    return Out; 
  }



Unity Shader之波浪效果_矩阵计算_04



水波制作




Unity Shader之波浪效果_Unity Shader之波浪效果_05




其实这里的浪是可以动的,只是在图片下面不是非常好的表达出来,在远处的波浪的效果更佳


我们只贴出处water的Vertex代码




uniform mat4 uMVPMatrix; //总变换矩阵
uniform float uStartAngle;//本帧起始角度
uniform float uWidthSpan;//横向长度总跨度
attribute vec3 aPosition;  //顶点位置
attribute vec2 aTexCoor;    //顶点纹理坐标
varying vec2 vTextureCoord;  //用于传递给片元着色器的变量
void main()     
{                  
   
   //计算X向角度          		
   float angleSpanH=40.0*3.14159265;//横向角度总跨度,对波纹的X轴幅度有影响 
   float startX=0.0;//起始X坐标
   //根据横向角度总跨度、横向长度总跨度及当前点X坐标折算出当前点X坐标对应的角度
   float currAngleH=uStartAngle+((aPosition.x-startX)/uWidthSpan)*angleSpanH;
   
   //计算出随z向发展起始角度的扰动值
   float startZ=0.0;//起始z坐标
   //根据纵向角度总跨度、纵向长度总跨度及当前点Y坐标折算出当前点Y坐标对应的角度
   float currAngleZ=((aPosition.z-startZ)/uWidthSpan)*angleSpanH;
   //计算斜向波浪
   float tzH=sin(currAngleH-currAngleZ)*0.7;   
   //根据总变换矩阵计算此次绘制此顶点位置
   gl_Position = uMVPMatrix * vec4(aPosition.x,tzH,aPosition.z,1); 
   
  // gl_Position = uMVPMatrix * vec4(aPosition,1); 
   vTextureCoord = aTexCoor;//将接收的纹理坐标传递给片元着色器
}