// Based on 'Volumetric fog: Unified, compute shader based solution to atmospheric scattering, ACM Siggraph 2014' // https://bartwronski.com/publications/ #pragma kernel CSMain float3 _FroxelResolution; Texture3D _VolumeInject; RWTexture3D _VolumeScatter; float4 ScatterStep(float3 accumulatedLight, float accumulatedTransmittance, float3 sliceLight, float sliceDensity) { sliceDensity = max(sliceDensity, 0.000001); float sliceTransmittance = exp(-sliceDensity / _FroxelResolution.z); // Seb Hillaire's improved transmission by calculating an integral over slice depth instead of // constant per slice value. Light still constant per slice, but that's acceptable. See slide 28 of // Physically-based & Unified Volumetric Rendering in Frostbite // http://www.frostbite.com/2015/08/physically-based-unified-volumetric-rendering-in-frostbite/ float3 sliceLightIntegral = sliceLight * (1.0 - sliceTransmittance) / sliceDensity; accumulatedLight += sliceLightIntegral * accumulatedTransmittance; accumulatedTransmittance *= sliceTransmittance; return float4(accumulatedLight, accumulatedTransmittance); } [numthreads(32, 2, 1)] void CSMain (uint3 id : SV_DispatchThreadID) { // Store transmission in .a, as opposed to density in _VolumeInject float4 accum = float4(0, 0, 0, 1); uint3 pos = uint3(id.xy, 0); uint steps = _FroxelResolution.z; for(uint z = 0; z < steps; z++) { pos.z = z; float4 slice = _VolumeInject[pos]; accum = ScatterStep(accum.rgb, accum.a, slice.rgb, slice.a); _VolumeScatter[pos] = accum; } }