美文网首页
案例-顶点动画-模拟水面

案例-顶点动画-模拟水面

作者: JervieQin | 来源:发表于2018-05-15 23:56 被阅读0次

    准备

    1. 创建shader文件、将它拖到新建的材质球上。不赘述。
    2. 在场景中创建一个plane用于演示,不赘述。

    编写VF shader

    1. 首先我们定义一些要用到的属性:
        //外部属性 ,用于初始传值
        Properties {
            _Color ("Color", Color) = (1,1,1,1)       //整体颜色
            _MainTex ("Main Tex", 2D) = "white" {}    //河流纹理 
            _Magnitude ("Wave Magnitude",Float) = 1   //波动幅度
            _Frequency("Wave Frequency",Float) = 1    //波动频率
            _InvWaveLength("Wave Length",Float) = 10  //波动长度倒数
            _Speed("Wave Speed",Float) = 0.5          //波动速度
        }
    
    1. 然后着手写VF着色器,首先定义一些标签。依次声明渲染物体类型是透明的,渲染队列为透明,忽略投影,关闭批处理。
        SubShader {
            //顶点动画需要关闭批处理
            //标签中的两个Transparent意义不同:RenderType中标记物体的渲染类型,而Queue中表示渲染透明几何体阶段时调用此shader(控制渲染时机)
            //详情:https://blog.csdn.net/treepulse/article/details/53484505 ; https://docs.unity3d.com/Manual/SL-SubShaderTags.html
            //另外注意,Tags分为subshader tags 和 pass tags ,前者适用于所有pass,后者只针对一个pass
            Tags { "RenderType"="Transparent" "Queue"="Transparent" "IgnoreProjector"="True" "DisableBatching"="True" }
    
    1. 重要部分编写
            Pass{
                // pass tags 详情:https://docs.unity3d.com/Manual/SL-PassTags.html
                Tags{ "LightMode" = "ForwardBase"}//设置光照类型
                ZWrite off                        //关闭深度写入,避免层次覆盖
                Blend SrcAlpha OneMinusSrcAlpha   //开启颜色混合模式
                Cull off                          //让水流的每一个面都显示
    
            CGPROGRAM 
            #pragma vertex vert                  //vextex着色器阶段
            #pragma fragment frag                //fragment着色器阶段
            #include "UnityCG.cginc" 
    
                //对属性的声明,便于后续使用
                
                //采样器,用于才片元片元着色器输出阶段对纹理的采样
                //通常和tex2D配合使用
                //采样器详情:https://docs.unity3d.com/Manual/SL-SamplerStates.html
                sampler2D _MainTexer;   
    
                //属性对应的值变量
                float4 _MainTex_ST;         
                fixed4 _Color;
                float _Magnitude;
                float _Frequency;
                float _InvWaveLength;
                float _Speed;
    
            //定义输入顶点着色器阶段的数据结构  
            struct Input{
                float4 vertex : POSITION;       //顶点位置
                float4 texcoord : TEXCOORD0;    //纹理坐标
            };
            
            //定义顶点着色器阶段输出的数据结构
            struct v2f{
    
                //SV_前缀的变量代表system value,
                //DX10之后就推荐使用SV_POSITION作为vertex shader的输出和fragment shader的输入了,
                //注意vertex shader的输入还是使用POSITION!
                float4 pos:SV_POSITION;          
                float2 uv:TEXCOORD0;             //纹理坐标
            };
    
            //输出v2f到下一渲染阶段
            v2f vert(Input v){
                v2f o ;
    
                float4 offset;
    
                //因为只希望顶点在X方向移动,所以yzw方向设置为0
                offset.yzw = float3(0,0,0);
    
                /*
                偏移公式: 正弦化(频率 * 时间 + (顶点x坐标 + 顶点y坐标 + 顶点z坐标)  * 波长倒数)*振幅
                          为了让不同的位置有不同的有不同的位移,加上了模型空间下的位置分量
                float4 _Time : 表示自场景加载经过的时间 ,4个分量分别是 (t/20, t, t*2, t*3)
                另外:  float4 _SinTime/_CosTime :4个分量分别是 (t/8, t/4, t/2, t)
                        float4 unity_DeltaTime: 4个分量的值分别是(dt, 1/dt, smoothDt, 1/smoothDt)
                */
                offset.x = sin(_Frequency*_Time.y
                                                  +v.vertex.x*_InvWaveLength
                                                  +v.vertex.y *_InvWaveLength
                                                  +v.vertex.z*_InvWaveLength)*_Magnitude;
    
                //o.pos = mul(UNITY_MATRIX_MVP,v.vertex + offset); 将顶点坐标转换成齐次裁剪空间,
                //mul函数相当于UnityObjectToClipPos函数 ,但是要通过两次矩阵运算,
                // 如果只是为了将顶点空间转换成齐次裁剪空间,推荐使用UnityObjectToClipPos函数。
                o.pos = UnityObjectToClipPos(v.vertex + offset);
    
                //TRANSFORM_TEX:#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
                //定义中的 name##_ST,表示要先声明一个与第二个参数同名且以_ST结尾的“变量”。比如此处的 _MainTex_ST。
                //作用:将模型顶点的uv和Tiling、Offset两个变量进行运算(xy控制缩放,zw控制偏移),计算出实际显示用的顶点uv。
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.uv +=float2(0,_Time.y * _Speed);
    
                return o;
            }
    
            //SV_TARGET是系统值,表示该函数返回的是用于下一个阶段OutPut Merger的颜色值
            //tex2D(s, t)    s:采样器(之前定义的sampler2D)   , t:uv坐标    输出纹理信息
            fixed4 frag(v2f i):SV_TARGET{
                //纹理采样
                fixed4 c = tex2D(_MainTexer,i.uv);  
                //设置输出颜色
                c.rgb *= _Color.rgb;
    
                return c;
            }
            ENDCG
            }
                }
        FallBack "Transparent/VertexLit"
    }
    
    

    给材质球贴上水纹理
    完成。

    相关文章

      网友评论

          本文标题:案例-顶点动画-模拟水面

          本文链接:https://www.haomeiwen.com/subject/ctbcdftx.html