Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Snow shader with perlin noise

Discussion in 'Shaders' started by spiritworld, Aug 19, 2019.

  1. spiritworld

    spiritworld

    Joined:
    Nov 26, 2014
    Posts:
    29
    I added snow effect feature into a toon shader I'm using (MKToon Free). I utilized basically this: https://forum.unity.com/threads/snow-up-vector-shader.177606/

    MKToon's v2f struct:
    Code (CSharp):
    1. struct VertexOutputForward {
    2.     float4 pos : SV_POSITION;
    3.     float2 uv_Main : TEXCOORD0;
    4.  
    5.     float4 posWorld : TEXCOORD1;
    6.     half3 normalWorld : TEXCOORD2;
    7.     half3 tangentWorld : TEXCOORD3;
    8.     half3 binormalWorld : TEXCOORD4;
    9. ...
    10. };
    11.  
    Inside MKToon I modified SurfaceColor function.
    Code (CSharp):
    1.    
    2. //get surface color based on blendmode and color source
    3. void SurfaceColor(out fixed3 albedo, out fixed alpha, float2 uv, half3 normal) {
    4.    fixed4 c = tex2D(_MainTex, uv) * _Color;  
    5.    float difference = dot(normal, _SnowDirection.xyz);
    6.    if(difference >= _SnowLevel) {
    7.       albedo = _SnowColor.rgb;
    8.    }
    9.    else {
    10.       albedo = c.rgb;
    11.    }
    12.  
    13.    alpha = c.a;
    14. }
    Here's outcome when it's only partly snowy:
    upload_2019-8-19_14-20-19.png

    It looks fine on small surfaces but e.g. on large grounds it's more on/off effect (no snow/full snow). What I really want is in the first example here using perlin noise: https://www.alanzucconi.com/2018/08/18/shader-showcase-saturday-6/

    "The snowy transition seen in Overland can be replicated using a grayscale, smooth noise texture. The UV coordinates of the ground mesh are used to sample a colour from that texture."

    I tinkered with this shader months ago and didn't get the sampling working, mostly because I'm not very adept with shader language. I added _NoiseTexture for perlin noise texture and tried to take samples

    Code (CSharp):
    1. float surfaceNoiseSample = tex2D(_NoiseTex, uv).r;
    2. if(difference >= _SnowLevel) {
    3.     albedo = surfaceNoiseSample > 0.75 ? _SnowColor.rgb : c.rgb;
    4. }
    5. else ...
    but this has no effect, instead snow doesn't appear at all. Should I use tex2D(_NoiseTex, UvOfNoiseTex) like in here: https://github.com/IronWarrior/ToonWaterShader/blob/master/Assets/Shaders/ToonWater.shader sample
     
  2. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    375
    You don't need these branches. Generally, don't do branches in shaders until you really know what you're doing. Just do something like:

    Code (csharp):
    1.  
    2. float snowMask = saturate(difference * surfaceNoiseSample * 10.0);
    3. albedo = lerp(c.rgb, _SnowColor.rgb, snowMask);
    4.  
     
  3. spiritworld

    spiritworld

    Joined:
    Nov 26, 2014
    Posts:
    29
    Ok thanks. I'll try to refactor my code better because I just solved it by... putting noiseSample comparison in same IF :D

    Code (CSharp):
    1. if(difference >= _SnowLevel && surfaceNoiseSample >= _SnowLevel)
    2. {
    3.      albedo = _SnowColor.rgb;
    4. }
    5. else ...
    6.  
    upload_2019-8-19_21-15-40.png
     
  4. spiritworld

    spiritworld

    Joined:
    Nov 26, 2014
    Posts:
    29
    Using saturate() was a incorrect solution because then snow loses the toony edge, some googling and found that step() is used for branching.

    Code (CSharp):
    1. float difference = dot(normal, _SnowDirection.xyz);
    2. albedo =  lerp(_SnowColor.rgb, c.rgb, step(difference, 1 - _SnowLevel));
    Also realized that my code was fine all along and the problem was the missing normal maps from material because didn't want any bumpiness in my objects :D but as a side effect the snow that is based on normal direction, well would need normal maps.

    Lessons learned.
     
    Last edited: Dec 5, 2020