zoukankan      html  css  js  c++  java
  • Unity Shader波纹效果

    我们今天来模拟一下波纹效果,当一颗石头投入水面时,在水中会形成向外扩散的一圈波纹,本质上就是一个向四周扩散的波。根据我们日常生活的经验可以知道,当一个物体投入水中时,中心的振幅时比较大的,而随着波向边缘运动,振幅越来越小,而波的频率在中心总体时很小的,而在边缘时波频率很大。

    那么我们可以先试着用正弦波来模拟。根据我们上述的波的性质,可以简单的将公式写为

     

     这样,一个以(0,0,0)为中心点的正弦波就构造出来了,前面振幅之所以要在分母上加1是为了防止分母为0.

    然后上代码:

    Shader "Unlit/VertWave"
    {
        Properties
        {
            _MainTex ("Texture", 2D) = "white" {}
            _Color("Color",Color) = (1,1,1,1)
            _WaveIntensity("Intensity",float) = 0.2
            _Speed("Speed",float) = 1
            _Frequency("Frequency",Range(0.1,1)) = 1
            
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            LOD 100
    
            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
                #pragma multi_compile_fog
    
                #include "UnityCG.cginc"
                #include "UnityLightingCommon.cginc"
    
                struct appdata
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                    float3 normal:NORMAL;
                };
    
                struct v2f
                {
                    float2 uv : TEXCOORD0;
                    UNITY_FOG_COORDS(1)
                    float4 vertex : SV_POSITION;
                    float3 normalWS : TEXCOORD2;
                };
    
                sampler2D _MainTex;
                float4 _MainTex_ST;
                float _WaveIntensity;
                float _Speed;
                float _Frequency;
                half4 _Color;
                v2f vert (appdata v)
                {
                    v2f o;
                    float4 positionWS = mul(UNITY_MATRIX_M,v.vertex);
                    float distanceSqr = dot(positionWS.xz,positionWS.xz);
                    positionWS.y = _WaveIntensity*rcp(distanceSqr+1) * sin(_Frequency*distanceSqr -_Time.y*_Speed);
                    o.vertex = UnityWorldToClipPos(positionWS);
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                    o.normalWS = UnityObjectToWorldNormal(v.normal);
                    UNITY_TRANSFER_FOG(o,o.vertex);
                    return o;
                }
    
                half4 frag (v2f i) : SV_Target
                {
                    half4 col = tex2D(_MainTex, i.uv)*_Color;
                    float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                    float3 normalWS = normalize(i.normalWS);
                    col.rgb *= _LightColor0.rgb*saturate(dot(normalWS,lightDir));
                    UNITY_APPLY_FOG(i.fogCoord, col);
                    return col;
                }
                ENDCG
            }
        }
    }

    结果如下:

     我们会看到因为只移动了顶点(不要直接用plane那个unity自带的网格,顶点数太少,出来的效果很丑,吼吼吼~),没有调整法线导致的光照一致,如果不是用了一张mainTex可能都看不出来里面有波在运动。所以我们接下来就修正法线。

    法线怎么求呢?我们可以通过求每个点x向的切线和z向的切线,然后通过叉乘构造出法线。那么问题就回到了如何求切线。我们知道切线的斜率其实就是一个函数在某一点的导数,在3维空间中的偏导数。那么我们就开始求偏导数:

      

     代码:

    float distanceSqr = dot(positionWS.xz,positionWS.xz);
                    positionWS.y = _WaveIntensity*rcp(distanceSqr+1) * sin(_Frequency*distanceSqr -_Time.y*_Speed);
                    
                    float3 xTangent = float3(1,0,0);
                    xTangent.y = (2*positionWS.x*(distanceSqr+1)*cos(distanceSqr)-sin(distanceSqr))/((distanceSqr+1)*(distanceSqr+1));
                    float3 zTangent = float3(0,0,1);
                    zTangent.y = (2*positionWS.z*(distanceSqr+1)*cos(distanceSqr)-sin(distanceSqr))/((distanceSqr+1)*(distanceSqr+1));
    
                    o.normalWS =  normalize(cross(zTangent,xTangent));

    效果如下:

    gif图前半部分是法线错误的效果,后半部分是计算法线后的效果。

    但是这个算出来的结果真的正确吗?别忘了我们还在shader里面公开了一些参数,这些参数的变化都会影响法线,也就是我们要把这些变动因素也要计入。

    公式修改为:

    代码修改为:

    float3 xTangent = float3(1,0,0);
                    xTangent.y = (2*_Frequency*positionWS.x*_WaveIntensity*(distanceSqr+1)*cos(distanceSqr)-sin(distanceSqr))/((distanceSqr+1)*(distanceSqr+1));
                    float3 zTangent = float3(0,0,1);
                    zTangent.y = (2*_Frequency*positionWS.z*_WaveIntensity*(distanceSqr+1)*cos(distanceSqr)-sin(distanceSqr))/((distanceSqr+1)*(distanceSqr+1));

    最终结果:

    其实和水纹一点都不像,哈哈哈,主要是正弦波函数是随便一拍脑门拟合的,没去细究真实世界的波函数究竟是什么,但是这里提供这样一个思路,换一个波函数也可以解决~~

    终于写完了,睡午觉~~~

  • 相关阅读:
    OSCP Learning Notes Buffer Overflows(3)
    OSCP Learning Notes Buffer Overflows(5)
    OSCP Learning Notes Exploit(3)
    OSCP Learning Notes Exploit(4)
    OSCP Learning Notes Exploit(1)
    OSCP Learning Notes Netcat
    OSCP Learning Notes Buffer Overflows(4)
    OSCP Learning Notes Buffer Overflows(1)
    OSCP Learning Notes Exploit(2)
    C++格式化输出 Learner
  • 原文地址:https://www.cnblogs.com/shenyibo/p/14158729.html
Copyright © 2011-2022 走看看