简单卡通水

参考
https://roystan.net/articles/toon-water/
源码
https://github.com/IronWarrior/ToonWaterShader

两张噪声图请添加图片描述
请添加图片描述
挂在相机上,开启深度模式,使shader可以拿到深度图

using UnityEngine;

public class ChangeCameraDepth : MonoBehaviour
{
    public DepthTextureMode textureMode;
    private void OnValidate()
    {
        GetComponent<Camera>().depthTextureMode = textureMode;
    }
    private void Awake()
    {
        GetComponent<Camera>().depthTextureMode = textureMode;
    }
   
}

水面shader

Shader "Custom/Water"
{
    Properties
    {
        _ShallowColor ("_ShallowColor", Color) = (0.4,0.9,1,1)
        _DeepColor ("_DeepColor", Color) = (0,0.2,0.7,1)
        _FoamColor("_FoamColr",COLOR) = (1,1,1,1)
        //这里用黑白噪声
        _NoiseTex ("_NoiseTex", 2D) = "white" {}
        //用彩色噪声表示扭曲
        _DistortionTex("_DistortionTex",2D) = "white"{}
        _FoamMinDistance("FoamMinDistance",float) = 0.02
        _FoamMaxDistance("_FoamMaxDistance",float) = 0.05
        _SurferNoiseCutoff("_SurferNoiseCutoff",Range(0,1)) = 0.7
        _foamSpeed("_foamSpeed",vector) = (0.3,0.3,0,0)
    }
    SubShader
    {
        Tags { "Queue" = "Transparent" }
      pass
        {

        Blend SrcAlpha OneMinusSrcAlpha
			ZWrite Off

        CGPROGRAM
        
        #pragma vertex vert
        #pragma fragment frag

        #include "UnityCG.cginc"


        float4 _ShallowColor;
        float4 _DeepColor;
        float4 _FoamColor;
        float _FoamMinDistance;
        float _FoamMaxDistance;
        float _SurferNoiseCutoff;
        //水波移动速度,只用xy两个参数
        float2 _foamSpeed;

        sampler2D _CameraDepthTexture;
        sampler2D _CameraNormalsTexture;
        sampler2D _NoiseTex;
        sampler2D _DistortionTex;
        float4 _NoiseTex_ST;
        float4 _DistortionTex_ST;
        struct appdata
        {
            float4 vertex:POSITION;
            float2 uv:TEXCOORD0;
            float3 normal:NORMAL;

        };

        struct v2f
        {
            float4 pos:SV_POSITION;
            float4 screenPos:TEXCOORD0;
            float2 noiseUV:TEXCOORD1;
            float2 distortionUV:TEXCOORD2;
            float3 viewNormal:NORMAL;
        };
        
        v2f vert(appdata v)
        {
            v2f o;
            o.pos = UnityObjectToClipPos(v.vertex);
            //齐次坐标下的屏幕坐标值
            o.screenPos = ComputeScreenPos(o.pos);
            o.viewNormal = COMPUTE_VIEW_NORMAL;
            o.noiseUV = TRANSFORM_TEX(v.uv,_NoiseTex);
            o.distortionUV = TRANSFORM_TEX(v.uv,_DistortionTex);
            return o;
        }
        
        float4 frag(v2f i):SV_TARGET0
        {
                          
           float4 depth = tex2Dproj(_CameraDepthTexture,UNITY_PROJ_COORD( i.screenPos));
           //等价于
           //depth = tex2D(_CameraDepthTexture,i.screenPos.xy/i.screenPos.w);

            float depthliner = LinearEyeDepth( depth.x);
            //i.screenPos.zw= i.pos.zw,所以这里还可以替换成i.pos.w ,pos.w就是裁剪空间里与相机的距离(大概是,之后去确认下)
           float depthDiff = depthliner-i.screenPos.w;

           //这步非常重要,不然把视角拉平之后会出现颜色堆积渐变,也就是远处颜色深近处颜色浅,此外,在linner色彩空间下明显,在gamma空间下不明显,不太明白为啥
           float waterDepthDifference = saturate(depthDiff/1);

           float3 existingNormal = tex2Dproj(_CameraNormalsTexture,UNITY_PROJ_COORD(i.screenPos));
           //相当于拿到屏幕坐标和view坐标下法线的夹角,以此判断物体边缘
           float normalDot = saturate(dot(existingNormal,i.viewNormal));
           float normalDistance = lerp(_FoamMinDistance,_FoamMaxDistance,normalDot);
           float foamDepthDiff = saturate(depthDiff/normalDistance) *_SurferNoiseCutoff;
           //水的小扭曲水花
           float4 distortionSample = tex2D(_DistortionTex,i.distortionUV);

           float2 noiseUV = i.noiseUV;
           noiseUV =float2(noiseUV.x+ _Time.y*_foamSpeed.x+distortionSample.r,noiseUV.y+_Time.y*_foamSpeed.y+distortionSample.g);

           float surferNoiseSample = tex2D(_NoiseTex,noiseUV).r;
           
           float4 waterColor = lerp(_ShallowColor,_DeepColor,waterDepthDifference);
           float4 foamColor = _FoamColor;
           foamColor.a = smoothstep( foamDepthDiff-0.1,foamDepthDiff+0.1,surferNoiseSample);
           

        
             float4 res = lerp(waterColor,foamColor,foamColor.a);
            
             //调下透明度,让水底物体可见,而不是深度图的颜色
             res.a = 0.7;
           return res;
           
            
         }

        ENDCG
    }
    }
    
}

核心就两点,一是对_CameraDepthTexture进行采样,获得水深水浅效果,同时获得物体水下的效果
二是对_CameraNormalsTexture进行采样拿到屏幕深度图,再和水面的view空间下的法线进行点乘,可以获得物体与水面相交的泡沫
SmoothStep用来生成:指定范围内0到1的平滑过渡值smoothstep(a,b,x) x取a-b之间

简化其中的步骤,使
foamColor.a = saturate((0.1-foamDepthDiff)/0.2);
return(0,0,0,0.7-foamDepthDiff);
可以单输出泡沫

shader想弄明白,就一条一条去把每行代码修改的结果输出出来看看,这个折腾了很长时间就是因为数值太小,输出在r通道上看不出来,弄到a通道上就清楚了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值