寻找更好的海水的移动解决方案

发表于2018-06-28
评论6 3.1k浏览
本来已经实现了海岛奇兵的海水,但总觉得差点意思。(海岛奇兵海水地址:https//blog.csdn.net/yxriyin/article/details/78708040 ) 

打算进一步优化一下。 

顶点着色器并不需要变化(以后打算加入波动模型,但现在暂时不考虑,因为是在很远的地方看海) 

片段着色器我首先想的是增加一张法线贴图,用来模拟海浪的波纹,因为海盗奇兵是波光,而不是波纹,所以看上去稍微有点呆板。 

    float4变量offsetColor =(tex2D(_BumpTex,i.bumpCoord + FLOAT2(_WaterSpeed * _Time.x * 0.5,0))+ tex2D(_BumpTex,FLOAT2(1 - i.bumpCoord .y,i.bumpCoord.x)+ float2(_WaterSpeed * _Time.x * 0.3,0)))/ 2; 
    half2 offset = UnpackNormal(offsetColor).xy * _Refract; 
    float4 bumpColor =(tex2D(_BumpTex,(i.bumpCoord + offset)+ float2(_WaterSpeed * _Time.x * 0.5,0))+ tex2D(_BumpTex,(float2(1 - i.bumpCoord.y,i.bumpCoord.x )+ offset)+ float2(_WaterSpeed * _Time.x * 0.3,0)))/ 2; 
    float3 Normal = UnpackNormal(bumpColor).xyz; 
    color = _PureColor * _Pure +(1-Pure)* color; 
    color.rgb = color.rgb * 1.2; 

原理很简单,就是通过法线贴图的uv偏移,制造海水流动的感觉,其中_PureColor的用途后面再说。

如果只是 这样还远远不够,因为法线必须要有光照才能有更好的效果,但我的目标是移动平台的中低端机,所以肯定不会使用自带的光照,而是直接自己模拟一个最简单的光照和计算 

    。float3 lightDir = normalize (float3(1,1,1)); 
    half3 halfVector = normalize(lightDir); 
    float diffFactor = max(0,dot(lightDir,Normal)); 
    float addValue = min(0.2,exp2(log2(((normalMapValue.z * i.args.x *(1 - Pure * 0.8))+ 
                    (normalMapValue.w *(1.0 - i.args.x *(1 - Pure ))* i.args.y * 0.8))*((1-i.args.y)* _Pure + i.args.y))* 5.0)); 
    颜色+ = addValue; 
    color.rgb + = color.rgb * diffFactor * strength; 

通过法线和光线的夹角,计算出明暗的分量,加到海水颜色上。 


简单处理后,效果已经有所体现:但这 还不够,海面本身的效果和海岸效果都不能少。 于是打算根据深度来计算海岸部分的变化。由于手机上对深度图的获取比较耗性能,所以还是打算使用额外的一张贴图来表示深度。越白的地方越浅,越黑的地方越深。我自己取了海岛模型的外轮廓,然后用PS做了一个简单的外发光处理,就当做深度图了。当然如果有美术帮忙,可以根据高度图得到一个完美的深度图,但作为测试,先这样子吧。 然后就是代码:     float deltaDepth = tex2D(_DepthTex,i.texcoord * 10).a;     color.rgb + = color.rgb * diffFactor *(1 - min(1,deltaDepth * 2));     fixed4 waveColor = tex2D(_WaveTex,float2(1-min(_Range.z,deltaDepth)/ _Range.z + _WaveRange * sin(_Time.x * _WaveSpeed + noiseColor.r * _NoiseRange),1)+ offset);     waveColor.rgb * =(1 - (sin(_Time.x * _WaveSpeed + noiseColor.r * _NoiseRange)+ 1)/ 2)* noiseColor.r; 

    fixed4 waveColor2 = tex2D(_WaveTex,float2(1-min(_Range.z,deltaDepth)/ _Range.z + _WaveRange * sin(_Time.x * _WaveSpeed + _WaveDelta + noiseColor.r * _NoiseRange),1)+ offset); 
    waveColor2.rgb * =(1 - (sin(_Time.x * _WaveSpeed + _WaveDelta + noiseColor.r * _NoiseRange)+ 1)/ 2)* noiseColor.r; 
    half water_A = 1 - min(_Range.z,deltaDepth)/ _Range.z; 
    half water_B = min(_Range.w,deltaDepth)/ _Range.w; 
    color.rgb + =(waveColor.rgb + waveColor2.rgb)* water_A; 
    color.a = min(1,deltaDepth * 1.5); 

原理也不难,就是根据深度,获取波浪贴图的像素,渲染到海面上,因为波浪要有运动,所以增加了一个sin函数来实现这种变化。另外为了使变化不要那么规则,增加了一个噪点来扭曲海面。 

效果如下: 。然后再说一下_PureColor,主要是因为镜头拉高到一定程度之后,海面上的明暗其实是很刺眼的于是模拟了一个减弱振幅, 根据摄像机和海面的距离调整海面的变化强度。 

。打算未来更多增加的特性参数状语从句:适用来风格不同游戏的 

目前已经上传资产仓库上面了,地址是: 

https://www.assetstore.unity3d.com/en/#!/content/120466 


已向官方申请打折,不知道会不会通过,哈哈。 


最后是片段着色器完整的源代码: 
本部分设定了隐藏,以下是隐藏的内容


注意: 

用'UnityObjectToClipPos(*)' 

替换'mul(UNITY_MATRIX_MVP,*)'//升级注意: UnityObjectToClipPos(*)' 

//升级注意:用'UnityObjectToClipPos(*)' 

Shader“                 Ocean2 ” 
{ 
        Properties 
        { 
_MainTex(“Base(RGB),Alpha(A)”,2D)替换'mul(UNITY_MATRIX_MVP,*) “Black”{} 
                _MainTex1(“Base(RGB),Alpha(A)”,2D)=“black”{} 
                Map(“Base(RGB),Alpha(A)”,2D)=“black”{} 
                _BumpTex (” BumpTex“,2D)=”bump“{} 
                _DepthTex(”_ DepthTex“,2D)=”black“{} 
                _WaveTex(“_ WaveTex”,2D)=“white”{} 
                _WaterSpeed(“_ WaterSpeed”,float)= 1 
                _Refract(“_ Refract”,Range(0,0.1))= 0.03 
                strength(“strength” ))= 0.5 
                _Alpha(“_ Alpha”,Range(0,1))= 1 
                _Pure(“_ Pure”,Range(0,1))= 1 
                _PureColor(“_ PureColor”,Color)=(0, 0) 
                _Range(“Range”,vector)=(                0.13,1.53,0.37,0.78 ) 
        } 

SubShader 
        { 
                LOD 100 

                Tags 
        { 
                “Queue”=“ Geometry-1000“ 
                ”IgnoreProjector“=”False“ 
//“RenderType”=“Transparent” 
        } 
//混合一个 
//混合SrcAlpha OneMinusSrcAlpha 
                混合SrcAlpha OneMinusSrcAlpha 
                Pass 
        { 
                CGPROGRAM 
//升级注意:排除DX11中的着色器; 没有语义的结构(struct v2f members v_darkColor) 
#pragma exclude_renderers d3d11 
#pragma vertex vert 
#pragma fragment frag 

#include“UnityCG.cginc” 
        struct appdata_t 
        { 
                float4 vertex:POSITION; 
                float2 texcoord:TEXCOORD0; 
        }; 

        结构v2f 
        { 
                float4 pos:SV_POSITION; 
                float2 texcoord:TEXCOORD0; 
                float2 normalCoord:TEXCOORD1; 
                float2 bumpCoord:TEXCOORD2; 
                float4 color:COLOR; 
                float2 args:TEXCOORD4; 
        }; 
        统一浮点数_Points [25]; 
        sampler2D _MainTex; 
        sampler2D _MainTex1; 
        sampler2D Map; 
        sampler2D _BumpTex; 
        sampler2D _DepthTex; 
        sampler2D _GTex; 
        sampler2D _WaveTex; 
        浮动_Pure; 
       
        浮力; 
        float _Alpha; 
         
        float4 _PureColor; 
        float _WaterSpeed; 
        float _Refract; 
        float4 _Range; 
        fixed4 frag(v2f i):COLOR 
        { 
                fixed4 color; 
                float4 normalMapValue = tex2D(Map,i.normalCoord); 
                color = tex2D(_MainTex,i.texcoord); 
                color = lerp(color,tex2D(_MainTex1,i.texcoord),(normalMapValue.x * i.args.x)+(normalMapValue.y *(1.0 - i.args.x))); 
                float4 offsetColor =(tex2D(_BumpTex,i.bumpCoord + float2(_WaterSpeed * _Time.x * 0.5,0))+ tex2D(_BumpTex,float2(1 - i.bumpCoord.y,i.bumpCoord.x)+ float2(_WaterSpeed * _Time.x * 0.3,0)))/ 2; 
                half2 offset = UnpackNormal(offsetColor).xy * _Refract; 
                float4 bumpColor =(tex2D(_BumpTex,(i.bumpCoord + offset)+ float2(_WaterSpeed * _Time.x * 0.5,0))+ tex2D(_BumpTex,(float2(1 - i.bumpCoord.y,i.bumpCoord.x )+ offset)+ float2(_WaterSpeed * _Time.x * 0.3,0)))/ 2; 
                float3 Normal = UnpackNormal(bumpColor).xyz; 
                color = _PureColor * _Pure +(1-Pure)* color; 
                color.rgb = color.rgb * 1.2; 
                float3 lightDir = normalize(float3(1,1,1)); 
                half3 halfVector = normalize(lightDir); 
                float diffFactor = max(0,dot(lightDir,Normal)); 
                float addValue = min(0.2,exp2(log2(((normalMapValue.z * i.args.x *(1 - Pure * 0.8))+ 
                        (normalMapValue.w *(1.0 - i.args.x *(1 - _Pure))* i.args.y * 0.8))*((1 - i.args.y)* _Pure + i.args.y) )* 5.0)); 
                颜色+ = addValue; 
                color.rgb + = color.rgb * diffFactor * strength; 
                float index = floor(i.texcoord.x * 10)* 5 + floor(i.texcoord.y * 10); 

                if(_Points [index]> 0) 
                { 
                        float deltaDepth = tex2D(_DepthTex,i.texcoord * 10).a; 
                        color.rgb + = color.rgb * diffFactor *(1 - min(1,deltaDepth * 2)); 
                        //color.rgb + = color.rgb * diffFactor * strength; 
                        float _WaveRange = 0.3; 
                        float _WaveSpeed = -12.64; 
                        float4 noiseColor = float4(1,1,1,1); 
                        float _NoiseRange = 6.43; 
                        float _WaveDelta = 2.43; 
                        fixed4 waveColor = tex2D(_WaveTex,float2(1-min(_Range.z,deltaDepth)/ _Range.z + _WaveRange * sin(_Time.x * _WaveSpeed + noiseColor.r * _NoiseRange),1)+ offset); 


                        waveColor.rgb * =(1 - (sin(_Time.x * _WaveSpeed + noiseColor.r * _NoiseRange)+ 1)/ 2)* noiseColor.r; 

                        fixed4 waveColor2 = tex2D(_WaveTex,float2(1-min(_Range.z,deltaDepth)/ _Range.z + _WaveRange * sin(_Time.x * _WaveSpeed + _WaveDelta + noiseColor.r * _NoiseRange),1)+ offset); 
                        waveColor2.rgb * =(1 - (sin(_Time.x * _WaveSpeed + _WaveDelta + noiseColor.r * _NoiseRange)+ 1)/ 2)* noiseColor.r; 

                        half water_A = 1 - min(_Range.z,deltaDepth)/ _Range.z; 
                        half water_B = min(_Range.w,deltaDepth)/ _Range.w; 

                        // color.rgb = color.rgb * pow(deltaDepth,1)+ waterColor.rgb *(1-pow(deltaDepth,1)); 
                        // color.rgb = color.rgb *(1 - waterColor.a * water_A)+ waterColor.rgb * waterColor.a * water_A; 
                        color.rgb + =(waveColor.rgb + waveColor2.rgb)* water_A; 

                        // color.a = min(_Range.x,deltaDepth)/ _Range.x; 
                        color.a = min(1,deltaDepth * 1.5); 
                } 
                color.a * = _Alpha; 
        // color = float4(normalMapValue.z,normalMapValue.z,normalMapValue.z,1); 
                返回颜色; 
        } 
                ENDCG 
        } 
        } 
} 

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引