您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

193 行
6.9 KiB

#ifndef UNITY_VOLUME_RENDERING_INCLUDED
#define UNITY_VOLUME_RENDERING_INCLUDED
// Reminder:
// Optical_Depth(x, y) = Integral{x, y}{Extinction(t) dt}
// Transmittance(x, y) = Exp(-Optical_Depth(x, y))
// Transmittance(x, z) = Transmittance(x, y) * Transmittance(y, z)
// Integral{a, b}{Transmittance(0, t) * Li(t) dt} = Transmittance(0, a) * Integral{a, b}{Transmittance(0, t - a) * Li(t) dt}.
float OpticalDepthHomogeneousMedium(float extinction, float intervalLength)
{
return extinction * intervalLength;
}
float3 OpticalDepthHomogeneousMedium(float3 extinction, float intervalLength)
{
return extinction * intervalLength;
}
float Transmittance(float opticalDepth)
{
return exp(-opticalDepth);
}
float3 Transmittance(float3 opticalDepth)
{
return exp(-opticalDepth);
}
float TransmittanceHomogeneousMedium(float extinction, float intervalLength)
{
return Transmittance(OpticalDepthHomogeneousMedium(extinction, intervalLength));
}
float3 TransmittanceHomogeneousMedium(float3 extinction, float intervalLength)
{
return Transmittance(OpticalDepthHomogeneousMedium(extinction, intervalLength));
}
// Integral{a, b}{Transmittance(0, t - a) dt}.
float TransmittanceIntegralHomogeneousMedium(float extinction, float intervalLength)
{
return rcp(extinction) - rcp(extinction) * exp(-extinction * intervalLength);
}
// Integral{a, b}{Transmittance(0, t - a) dt}.
float3 TransmittanceIntegralHomogeneousMedium(float3 extinction, float intervalLength)
{
return rcp(extinction) - rcp(extinction) * exp(-extinction * intervalLength);
}
float IsotropicPhaseFunction()
{
return INV_FOUR_PI;
}
float HenyeyGreensteinPhasePartConstant(float asymmetry)
{
float g = asymmetry;
return INV_FOUR_PI * (1 - g * g);
}
float HenyeyGreensteinPhasePartVarying(float asymmetry, float LdotD)
{
float g = asymmetry;
return pow(abs(1 + g * g - 2 * g * LdotD), -1.5);
}
float HenyeyGreensteinPhaseFunction(float asymmetry, float LdotD)
{
return HenyeyGreensteinPhasePartConstant(asymmetry) *
HenyeyGreensteinPhasePartVarying(asymmetry, LdotD);
}
// Samples the interval of homogeneous participating medium using the closed-form tracking approach
// (proportionally to the transmittance).
// Returns the offset from the start of the interval and the weight = (transmittance / pdf).
// Ref: Production Volume Rendering, 3.6.1.
void ImportanceSampleHomogeneousMedium(float rndVal, float extinction, float intervalLength,
out float offset, out float weight)
{
// pdf = extinction * exp(-extinction * t) / (1 - exp(-intervalLength * extinction))
// weight = exp(-extinction * t) / pdf
// weight = (1 - exp(-extinction * intervalLength)) / extinction;
float x = 1 - exp(-extinction * intervalLength);
weight = x * rcp(extinction);
offset = -log(1 - rndVal * x) * rcp(extinction);
}
// Implements equiangular light sampling.
// Returns the distance from the origin of the ray, the squared (radial) distance from the light,
// and the reciprocal of the PDF.
// Ref: Importance Sampling of Area Lights in Participating Medium.
void ImportanceSamplePunctualLight(float rndVal, float3 lightPosition,
float3 rayOrigin, float3 rayDirection,
float tMin, float tMax,
out float dist, out float rSq, out float rcpPdf,
float minDistSq = FLT_EPS)
{
float3 originToLight = lightPosition - rayOrigin;
float originToLightProj = dot(originToLight, rayDirection);
float originToLightDistSq = dot(originToLight, originToLight);
float rayToLightDistSq = max(originToLightDistSq - originToLightProj * originToLightProj, minDistSq);
float a = tMin - originToLightProj;
float b = tMax - originToLightProj;
float dSq = rayToLightDistSq;
float dRcp = rsqrt(dSq);
float d = dSq * dRcp;
// TODO: optimize me. :-(
float theta0 = FastATan(a * dRcp);
float theta1 = FastATan(b * dRcp);
float gamma = theta1 - theta0;
float theta = lerp(theta0, theta1, rndVal);
float t = d * tan(theta);
dist = originToLightProj + t;
rSq = dSq + t * t;
rcpPdf = gamma * rSq * dRcp;
}
// Absorption coefficient from Disney: http://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf
float3 TransmittanceColorAtDistanceToAbsorption(float3 transmittanceColor, float atDistance)
{
return -log(transmittanceColor + FLT_EPS) / max(atDistance, FLT_EPS);
}
#define VOLUMETRIC_LIGHTING_ENABLED
#ifdef PRESET_ULTRA
// E.g. for 1080p: (1920/4)x(1080/4)x(256) = 33,177,600 voxels
#define VBUFFER_TILE_SIZE 4
#define VBUFFER_SLICE_COUNT 256
#else
// E.g. for 1080p: (1920/8)x(1080/8)x(128) = 4,147,200 voxels
#define VBUFFER_TILE_SIZE 8
#define VBUFFER_SLICE_COUNT 128
#endif // PRESET_ULTRA
#include "Random.hlsl"
// Returns linearly interpolated {volumetric radiance, opacity}. The sampler clamps to edge.
float4 SampleInScatteredRadianceAndTransmittance(TEXTURE3D_ARGS(VBufferLighting, linearClampSampler),
float2 positionNDC, float linearDepth,
float2 VBufferScale, float4 VBufferDepthEncodingParams)
{
int k = VBUFFER_SLICE_COUNT;
float z = linearDepth;
float d = EncodeLogarithmicDepth(z, VBufferDepthEncodingParams);
// TODO: Add some kind of jitter to the look-up.
// TODO: Also add some kind of animated 3D noise to the sampled result.
// d -= GenerateHashedRandomFloat(asuint(positionNDC)) / (2 * k);
// Account for the visible area of the V-Buffer.
float2 uv = positionNDC * VBufferScale;
float4 L;
[branch] if (d != saturate(d))
{
// We are in front of the near or behind the far plane of the V-buffer.
// The sampler will clamp to edge.
L = SAMPLE_TEXTURE3D_LOD(VBufferLighting, linearClampSampler, float3(uv, d), 0);
}
else
{
// We cannot use hardware trilinear interpolation since the distance between slices is log-encoded.
// Therefore, we perform 2 bilinear taps.
// TODO: test the visual difference in practice.
float s0 = floor(d * k - 0.5);
float s1 = ceil(d * k - 0.5);
float d0 = saturate(s0 * rcp(k) + (0.5 * rcp(k)));
float d1 = saturate(s1 * rcp(k) + (0.5 * rcp(k)));
float z0 = DecodeLogarithmicDepth(d0, VBufferDepthEncodingParams);
float z1 = DecodeLogarithmicDepth(d1, VBufferDepthEncodingParams);
// The sampler will clamp to edge.
float4 L0 = SAMPLE_TEXTURE3D_LOD(VBufferLighting, linearClampSampler, float3(uv, d0), 0);
float4 L1 = SAMPLE_TEXTURE3D_LOD(VBufferLighting, linearClampSampler, float3(uv, d1), 0);
L = lerp(L0, L1, saturate((z - z0) / (z1 - z0)));
}
return float4(L.rgb, 1 - Transmittance(L.a));
}
#endif // UNITY_VOLUME_RENDERING_INCLUDED