// Based on 'Volumetric fog: Unified, compute shader based solution to atmospheric scattering, ACM Siggraph 2014'
// https://bartwronski.com/publications/

#pragma kernel CSMain
#define VOLUME_DEPTH 128.0

Texture3D _VolumeInject;
RWTexture3D<float4> _VolumeScatter;

float4 ScatterStep(float3 accumulatedLight, float accumulatedTransmittance, float3 sliceLight, float sliceDensity)
{
	sliceDensity = max(sliceDensity, 0.000001);
	float  sliceTransmittance = exp(-sliceDensity / VOLUME_DEPTH);

	// 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 = VOLUME_DEPTH;

	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;
	}
}