Improved transmission with an integral over slice depth - behaves nic…

This commit is contained in:
Robert Cupisz 2017-04-06 13:53:09 +02:00
parent 6853822b7e
commit 9589c93f77
2 changed files with 23 additions and 19 deletions

View File

@ -455,7 +455,7 @@ public class VolumetricFog : MonoBehaviour
// Compensate for more light and density being injected in per world space meter when near and far are closer. // Compensate for more light and density being injected in per world space meter when near and far are closer.
// TODO: Not quite correct yet. // TODO: Not quite correct yet.
float depthCompensation = (farClip - nearClip) * 0.01f; float depthCompensation = (farClip - nearClip) * 0.01f;
m_InjectLightingAndDensity.SetFloat("_Density", m_GlobalDensityMult * 0.001f * depthCompensation); m_InjectLightingAndDensity.SetFloat("_Density", m_GlobalDensityMult * 0.128f * depthCompensation);
m_InjectLightingAndDensity.SetFloat("_Intensity", m_GlobalIntensityMult); m_InjectLightingAndDensity.SetFloat("_Intensity", m_GlobalIntensityMult);
m_InjectLightingAndDensity.SetFloat("_Anisotropy", m_Anisotropy); m_InjectLightingAndDensity.SetFloat("_Anisotropy", m_Anisotropy);
m_InjectLightingAndDensity.SetTexture(kernel, "_VolumeInject", m_VolumeInject); m_InjectLightingAndDensity.SetTexture(kernel, "_VolumeInject", m_VolumeInject);

View File

@ -2,37 +2,41 @@
// https://bartwronski.com/publications/ // https://bartwronski.com/publications/
#pragma kernel CSMain #pragma kernel CSMain
#define VOLUME_DEPTH 128 #define VOLUME_DEPTH 128.0
Texture3D _VolumeInject; Texture3D _VolumeInject;
RWTexture3D<float4> _VolumeScatter; RWTexture3D<float4> _VolumeScatter;
float Extinction(float density) float4 ScatterStep(float3 accumulatedLight, float accumulatedTransmittance, float3 sliceLight, float sliceDensity)
{ {
return exp(-density); sliceDensity = max(sliceDensity, 0.000001);
} float sliceTransmittance = exp(-sliceDensity / VOLUME_DEPTH);
void WriteOutput(in uint3 pos, in float4 colorAndDensity) // 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
_VolumeScatter[pos] = float4(colorAndDensity.rgb, Extinction(colorAndDensity.a)); // 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;
float4 AccumulateScattering(float4 colorAndDensityFront, float4 colorAndDensityBack) accumulatedLight += sliceLightIntegral * accumulatedTransmittance;
{ accumulatedTransmittance *= sliceTransmittance;
float3 light = colorAndDensityFront.rgb + saturate(Extinction(colorAndDensityFront.a)) * colorAndDensityBack.rgb;
return float4(light.rgb, colorAndDensityFront.a + colorAndDensityBack.a); return float4(accumulatedLight, accumulatedTransmittance);
} }
[numthreads(32, 2, 1)] [numthreads(32, 2, 1)]
void CSMain (uint3 id : SV_DispatchThreadID) void CSMain (uint3 id : SV_DispatchThreadID)
{ {
float4 currentSlice = _VolumeInject[uint3(id.xy, 0)]; // Store transmission in .a, as opposed to density in _VolumeInject
WriteOutput(uint3(id.xy, 0), currentSlice); float4 accum = float4(0, 0, 0, 1);
uint3 pos = uint3(id.xy, 0);
uint steps = VOLUME_DEPTH;
for(uint z = 1; z < VOLUME_DEPTH; z++) for(uint z = 0; z < steps; z++)
{ {
float4 nextValue = _VolumeInject[uint3(id.xy, z)]; pos.z = z;
currentSlice = AccumulateScattering(currentSlice, nextValue); float4 slice = _VolumeInject[pos];
WriteOutput(uint3(id.xy, z), currentSlice); accum = ScatterStep(accum.rgb, accum.a, slice.rgb, slice.a);
_VolumeScatter[pos] = accum;
} }
} }