Skip to content

Instantly share code, notes, and snippets.

@HAliss
Created January 13, 2025 08:03
Show Gist options
  • Save HAliss/f84e3c482ea2ac9664a3048fa734093c to your computer and use it in GitHub Desktop.
Save HAliss/f84e3c482ea2ac9664a3048fa734093c to your computer and use it in GitHub Desktop.

Revisions

  1. HAliss renamed this gist Jan 13, 2025. 1 changed file with 0 additions and 0 deletions.
  2. HAliss created this gist Jan 13, 2025.
    94 changes: 94 additions & 0 deletions volumetricFogTutorial.shader
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,94 @@
    Shader "Tutorial/VolumetricFog"
    {
    Properties
    {
    _Color("Color", Color) = (1, 1, 1, 1)
    _MaxDistance("Max distance", float) = 100
    _StepSize("Step size", Range(0.1, 20)) = 1
    _DensityMultiplier("Density multiplier", Range(0, 10)) = 1
    _NoiseOffset("Noise offset", float) = 0

    _FogNoise("Fog noise", 3D) = "white" {}
    _NoiseTiling("Noise tiling", float) = 1
    _DensityThreshold("Density threshold", Range(0, 1)) = 0.1

    [HDR]_LightContribution("Light contribution", Color) = (1, 1, 1, 1)
    _LightScattering("Light scattering", Range(0, 1)) = 0.2
    }

    SubShader
    {
    Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }

    Pass
    {
    HLSLPROGRAM
    #pragma vertex Vert
    #pragma fragment frag
    #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN

    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
    #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"

    float4 _Color;
    float _MaxDistance;
    float _DensityMultiplier;
    float _StepSize;
    float _NoiseOffset;
    TEXTURE3D(_FogNoise);
    float _DensityThreshold;
    float _NoiseTiling;
    float4 _LightContribution;
    float _LightScattering;

    float henyey_greenstein(float angle, float scattering)
    {
    return (1.0 - angle * angle) / (4.0 * PI * pow(1.0 + scattering * scattering - (2.0 * scattering) * angle, 1.5f));
    }

    float get_density(float3 worldPos)
    {
    float4 noise = _FogNoise.SampleLevel(sampler_TrilinearRepeat, worldPos * 0.01 * _NoiseTiling, 0);
    float density = dot(noise, noise);
    density = saturate(density - _DensityThreshold) * _DensityMultiplier;
    return density;
    }

    half4 frag(Varyings IN) : SV_Target
    {
    float4 col = SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, IN.texcoord);
    float depth = SampleSceneDepth(IN.texcoord);
    float3 worldPos = ComputeWorldSpacePosition(IN.texcoord, depth, UNITY_MATRIX_I_VP);

    float3 entryPoint = _WorldSpaceCameraPos;
    float3 viewDir = worldPos - _WorldSpaceCameraPos;
    float viewLength = length(viewDir);
    float3 rayDir = normalize(viewDir);

    float2 pixelCoords = IN.texcoord * _BlitTexture_TexelSize.zw;
    float distLimit = min(viewLength, _MaxDistance);
    float distTravelled = InterleavedGradientNoise(pixelCoords, (int)(_Time.y / max(HALF_EPS, unity_DeltaTime.x))) * _NoiseOffset;
    float transmittance = 1;
    float4 fogCol = _Color;

    while(distTravelled < distLimit)
    {
    float3 rayPos = entryPoint + rayDir * distTravelled;
    float density = get_density(rayPos);
    if (density > 0)
    {
    Light mainLight = GetMainLight(TransformWorldToShadowCoord(rayPos));
    fogCol.rgb += mainLight.color.rgb * _LightContribution.rgb * henyey_greenstein(dot(rayDir, mainLight.direction), _LightScattering) * density * mainLight.shadowAttenuation * _StepSize;
    transmittance *= exp(-density * _StepSize);
    }
    distTravelled += _StepSize;
    }

    return lerp(col, fogCol, 1.0 - saturate(transmittance));
    }
    ENDHLSL
    }
    }
    }