浏览代码

Use the Cornette-Shanks phase function for the ambient lighting

/main
Evgenii Golubev 7 年前
当前提交
3d08aa2e
共有 3 个文件被更改,包括 71 次插入58 次删除
  1. 54
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/Resources/VolumetricLighting.compute
  2. 73
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumetricLighting.cs
  3. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderVariables.hlsl

54
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/Resources/VolumetricLighting.compute


float3 radianceNoPhase;
};
struct ZonalHarmonics
{
float coeffs[3]; // 3 bands
};
struct SphericalHarmonics
{
float coeffs[9]; // 3 bands
};
// RGB SphericalHarmonics
struct LightProbe
{

LightProbe GetAmbientProbe()
LightProbe GetPreconvolvedAmbientProbe()
{
LightProbe probe;

case 6: return sqrt(0.3125 / PI) * (3 * Sq(d.z) - 1);
case 7: return -sqrt(3.75 / PI) * d.x * d.z;
case 8: return sqrt(0.9375 / PI) * (Sq(d.x) - Sq(d.y));
default: return -FLT_INF; // Unreachable
}
}
// Ref: "Stupid Spherical Harmonics Tricks", p. 7.
SphericalHarmonics RotateZonalHarmonics(ZonalHarmonics zh, float3 d)
{
SphericalHarmonics sh;
for (int l = 0; l <= 2; l++)
{
float n = sqrt((4 * PI) / (2 * l + 1));
float c = zh.coeffs[l];
float p = n * c;
for (int m = -l; m <= l; m++)
{
int i = l * (l + 1) + m;
sh.coeffs[i] = p * EvaluateSphericalHarmonics(i, d);
}
default: return FLT_INF; // Unreachable
return sh;
float3 EvaluateLightProbe(LightProbe probe, float asymmetry, float3 d)
float3 EvaluateLightProbe(LightProbe probe, float3 d)
float g = asymmetry;
// Represent the Henyey-Greenstein function using the Zonal Harmonics.
ZonalHarmonics zhPhase;
zhPhase.coeffs[0] = 0.5 * sqrt(1 / PI);
zhPhase.coeffs[1] = 0.5 * sqrt(3 / PI) * g;
zhPhase.coeffs[2] = 0.5 * sqrt(5 / PI) * g * g;
// Rotate the coefficients (z -> d).
SphericalHarmonics shPhase = RotateZonalHarmonics(zhPhase, d);
// Evaluate the integral.
radiance += probe.coeffs[i] * shPhase.coeffs[i];
radiance += probe.coeffs[i] * EvaluateSphericalHarmonics(i, d);
}
return max(0, radiance);

#endif
// Sample the light probe.
float3 probeRadiance = EvaluateLightProbe(GetAmbientProbe(), asymmetry, ray.centerDirWS) * TransmittanceIntegralHomogeneousMedium(extinction, dt);
float3 probeRadiance = EvaluateLightProbe(GetPreconvolvedAmbientProbe(), ray.centerDirWS) * TransmittanceIntegralHomogeneousMedium(extinction, dt);
// Integral{a, b}{Transmittance(0, t) * L_s(t) dt} = Transmittance(0, a) * Integral{a, b}{Transmittance(0, t - a) * L_s(t) dt}.
totalRadiance += transmittance * scattering * (phase * blendedRadiance + probeRadiance);

73
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumetricLighting.cs


return depthParams;
}
public unsafe struct ZonalHarmonicsL2
{
public fixed float coeffs[3];
};
public static unsafe ZonalHarmonicsL2 GetHenyeyGreensteinPhaseFunction(float asymmetry)
{
float g = asymmetry;
ZonalHarmonicsL2 zh = new ZonalHarmonicsL2();
zh.coeffs[0] = 0.5f * Mathf.Sqrt(1.0f / Mathf.PI);
zh.coeffs[1] = 0.5f * Mathf.Sqrt(3.0f / Mathf.PI) * g;
zh.coeffs[2] = 0.5f * Mathf.Sqrt(5.0f / Mathf.PI) * g * g;
return zh;
}
public static unsafe ZonalHarmonicsL2 GetCornetteShanksPhaseFunction(float asymmetry)
{
float g = asymmetry;
ZonalHarmonicsL2 zh = new ZonalHarmonicsL2();
zh.coeffs[0] = 0.282095f;
zh.coeffs[1] = 0.293162f * g * (4.0f + (g * g)) / (2.0f + (g * g));
zh.coeffs[2] = (0.126157f + 1.44179f * (g * g) + 0.324403f * (g * g) * (g * g)) / (2.0f + (g * g));
return zh;
}
SphericalHarmonicsL2 DenormalizeSH(SphericalHarmonicsL2 sh)
public unsafe SphericalHarmonicsL2 DenormalizeSH(SphericalHarmonicsL2 sh)
{
float sqrtPi = Mathf.Sqrt(Mathf.PI);

return sh;
}
void SetAmbientLightProbe(CommandBuffer cmd)
// Ref: "Stupid Spherical Harmonics Tricks", p. 6.
public unsafe SphericalHarmonicsL2 Convolve(SphericalHarmonicsL2 sh, ZonalHarmonicsL2 zh)
{
for (int l = 0; l <= 2; l++)
{
float n = Mathf.Sqrt((4.0f * Mathf.PI) / (2 * l + 1));
float k = zh.coeffs[l];
float p = n * k;
for (int m = -l; m <= l; m++)
{
int i = l * (l + 1) + m;
sh[0, i] *= p;
sh[1, i] *= p;
sh[2, i] *= p;
}
}
return sh;
}
void SetPreconvolvedAmbientLightProbe(CommandBuffer cmd, float asymmetry)
ZonalHarmonicsL2 phaseZH = GetCornetteShanksPhaseFunction(asymmetry);
SphericalHarmonicsL2 convolvedSH = Convolve(probeSH, phaseZH);
coeffs[i].x = probeSH[0, i]; // R
coeffs[i].y = probeSH[1, i]; // G
coeffs[i].z = probeSH[2, i]; // B
coeffs[i].w = 0; // Unused
coeffs[i].x = convolvedSH[0, i]; // R
coeffs[i].y = convolvedSH[1, i]; // G
coeffs[i].z = convolvedSH[2, i]; // B
coeffs[i].w = 0; // Unused
}
cmd.SetGlobalVectorArray(HDShaderIDs._AmbientProbeCoeffs, coeffs);

VolumeProperties globalFogProperties = (globalFogComponent != null) ? globalFogComponent.volumeParameters.GetProperties()
: VolumeProperties.GetNeutralVolumeProperties();
float asymmetry = globalFogComponent != null ? globalFogComponent.volumeParameters.asymmetry : 0;
cmd.SetGlobalFloat( HDShaderIDs._GlobalFog_Asymmetry, globalFogComponent != null ? globalFogComponent.volumeParameters.asymmetry : 0);
cmd.SetGlobalFloat( HDShaderIDs._GlobalFog_Asymmetry, asymmetry);
int w = 0, h = 0, d = 0;
Vector2 scale = ComputeVBufferResolutionAndScale(preset, (int)camera.screenSize.x, (int)camera.screenSize.y, ref w, ref h, ref d);

SetAmbientLightProbe(cmd);
SetPreconvolvedAmbientLightProbe(cmd, asymmetry);
cmd.SetGlobalVector( HDShaderIDs._VBufferResolution, new Vector4(w, h, 1.0f / w, 1.0f / h));
cmd.SetGlobalVector( HDShaderIDs._VBufferScaleAndSliceCount, new Vector4(scale.x, scale.y, d, 1.0f / d));
cmd.SetGlobalVector( HDShaderIDs._VBufferDepthEncodingParams, ComputeLogarithmicDepthEncodingParams(m_VBufferNearPlane, m_VBufferFarPlane, k_LogScale));

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderVariables.hlsl


float2 _TaaFrameRotation; // {x = sin(_TaaFrameIndex * PI/2), y = cos(_TaaFrameIndex * PI/2), z = unused}
uint _TaaFrameIndex; // [0, 7]
// Volumetric lighting.
float4 _AmbientProbeCoeffs[9]; // 3 bands of SH. TODO: alpha is unused, pack better?
float4 _AmbientProbeCoeffs[9]; // 3 bands of SH, pre-convolved with the phase function. TODO: alpha is unused, pack better?
float _GlobalFog_Asymmetry;
float3 _GlobalFog_Scattering;
float _GlobalFog_Extinction;

正在加载...
取消
保存