Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Rewriting Shader to use Arbitrary Y-UP

Discussion in 'Shaders' started by PhoenixAdvanced, Jun 22, 2021.

  1. PhoenixAdvanced

    PhoenixAdvanced

    Joined:
    Sep 30, 2016
    Posts:
    316
    I am using a paid asset to generate a snow effect in my project, however, I just recently discovered that this asset does not work when the player orientation is not Y-Up. This is an issue in my project since it is a space game with realistic planets, etc.
    I posted on the developers forums, and got some useful advice, but unfortunately I don't have the knowledge to implement this advice.
    I am going to post the relevant part of the shader here, along with an explanation.

    The relevant section of the code is:
    Code (CSharp):
    1. float3 worldPos = getWorldPos(i, depth01);
    2.         float3 snowPos  = worldPos;
    3.         #if defined(USE_ZENITHAL_DEPTH)
    4.             float4 st = float4(worldPos.xz - _GS_SnowCamPos.xz, 0, 0);
    5.             st *= _GS_SnowData2.z;
    6.             st += 0.5;
    7.             float2 zmask = tex2Dlod(_GS_DepthTexture, st).rg;
    8.             _GS_SnowData6.x += zmask.g;
    9.             float y = max(_GS_SnowCamPos.y - worldPos.y, 0.001) / _GS_SnowCamPos.w;
    10.             float zd = min(zmask.r + _GS_SnowData3.z, y);
    11.             fixed snowCover = saturate( ((zd / y) - 0.9875) * 110.0);
    12.         #else
    13.             float2 maskUV = (worldPos.xz - _GS_DepthMaskWorldSize.yw) / _GS_DepthMaskWorldSize.xz + 0.5.xx;
    14.             fixed snowCover = tex2D(_GS_DepthMask, maskUV).a;
    15.             if (maskUV.x<=0.01 || maskUV.x>=0.99 || maskUV.y<=0.01 || maskUV.y>=0.99) snowCover = 1.0;
    16.         #endif
    17.         // diffuse
    18.         #if GLOBALSNOW_FLAT_SHADING
    19.         fixed4 diff = tex2D(_GS_SnowTex, snowPos.xz * 0.02);
    20.         #else
    21.         fixed4 diff = tex2D(_GS_SnowTex, snowPos.xz * 0.02).gggg;
    22.         #endif
    23.         // get world space normal
    24.         #if GLOBALSNOW_FLAT_SHADING
    25.             float3 wsNormal = tex2D(_GS_GBuffer2Copy, uv_flat).xyz * 2.0 - 1.0;
    26.         #else
    27.             float3 wsNormal = tex2D(_GS_GBuffer2Copy, i.uv).xyz * 2.0 - 1.0;
    28.         #endif
    29.         // prevent snow on walls and below minimum altitude
    30.         float altG = tex2D(_GS_SnowTex, snowPos.xz * 0.5).g;
    31.         float altNoise = diff.r * altG - 0.9;
    32.         #if !SHADER_API_D3D9 && defined(GLOBALSNOW_ENABLE_SLOPE_CONTROL)
    33.         float ny = wsNormal.y - _GS_SnowData5.x;
    34.         float flatSurface = saturate( (ny + altNoise * _GS_SnowData5.z) * _GS_SnowData5.y);
    35.         #else
    36.         float ny = wsNormal.y - 0.7;
    37.         float flatSurface = saturate(ny * 15.0);
    38.         #endif
    39.         float minAltitude = worldPos.y - _GS_SnowData2.w - altNoise * _GS_SnowData2.y;
    40.         minAltitude = saturate(minAltitude / _GS_SnowData6.z);
    41.         snowCover = snowCover * minAltitude * flatSurface - _GS_SnowData6.x;
    _GSSnowCampos is the position of the camera
    _GS_SnowCamPos.w is the camera clip plane
    _GS_SnowData5.x is the slopethreshold
    _GS_SnowData5.z is the distance slope threshold
    _GS_SnowData6.z contains the altitude blending paramater
    _GS_SnowData2.y is the altitude scatter

    I think the most crucial line is:

    snowCover = snowCover * minAltitude * flatSurface - _GS_SnowData6.x

    I really need to find a way to rewrite this code to use a non-y-up vector.

    The advice I got from the dev was to changes this code so that it uses the distance to the surface, and not just the y-pos, but I am not sure how to do this.

    I know this is a tricky one, but can anyone offer any advice on this?