浏览代码

Implement correct ellipsoidal attenuation for area lights which scales with the area

/main
Evgenii Golubev 8 年前
当前提交
8b44deea
共有 2 个文件被更改,包括 47 次插入9 次删除
  1. 17
      Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl
  2. 39
      Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl

17
Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl


// Pick the axis along which to dilate the attenuation sphere into an ellipsoid.
float3 axis = lightData.right;
// We define the ellipsoid s.t. r1 = r2 = r, r3 = (r + len / 2).
// We define the ellipsoid s.t. r1 = (r + len / 2), r2 = r3 = r.
// TODO: This could be precomputed.
float radius = rsqrt(lightData.invSqrAttenuationRadius);
float invAspectRatio = radius / (radius + (0.5 * len));

// EvaluateBSDF_Area - Approximation with Linearly Transformed Cosines
//-----------------------------------------------------------------------------
#define ELLIPSOIDAL_ATTENUATION
void EvaluateBSDF_Area(LightLoopContext lightLoopContext,
float3 V, float3 positionWS,
PreLightData preLightData, LightData lightData, BSDFData bsdfData,

float3 unL = positionWS - lightData.positionWS;
#ifdef ELLIPSOIDAL_ATTENUATION
// We define the ellipsoid s.t. r1 = (r + w / 2), r2 = (r + h / 2), r3 = r.
// TODO: This could be precomputed.
float radius = rsqrt(lightData.invSqrAttenuationRadius);
float invAspectRatio1 = radius / (radius + halfWidth);
float invAspectRatio2 = radius / (radius + halfHeight);
// Compute the light attenuation.
float intensity = GetEllipsoidalDistanceAttenuation(unL, lightData.invSqrAttenuationRadius,
lightData.right, invAspectRatio1,
lightData.up, invAspectRatio2);
#else
// Rotate the light direction into the light space.
float3x3 lightToWorld = float3x3(lightData.right, lightData.up, lightData.forward);
unL = mul(unL, transpose(lightToWorld));

// Compute the light attenuation.
float intensity = GetBoxToSphereMapDistanceAttenuation(unL, invHalfDiag);
#endif
// Terminate if the shaded point is too far away.
if (intensity == 0.0) return;

39
Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl


return attenuation;
}
// Applies SmoothDistanceAttenuation() after stretching the attenuation sphere of the
// given radius into an ellipsoid with the specified (positive) aspect ratio and the longest axis.
// Applies SmoothDistanceAttenuation() after stretching/shrinking the attenuation sphere
// of the given radius into an ellipsoid. The process is performed along the specified axis, and
// the magnitude of the transformation is controlled by the aspect ratio (the inverse is given).
// Project the unnormalized light vector onto the dilation axis.
// Project the unnormalized light vector onto the stretching/shrinking axis.
// We want 'unL' to shrink along 'axis' by the aspect ratio. Therefore, we compute
// the difference between the length of the original projection and the shrunk one.
// It is equivalent to stretching the attenuation sphere into an ellipsoid.
float scale = projL - projL * invAspectRatio;
unL -= scale * axis;
// We want 'unL' to stretch/shrink along each axis (by the inverse of the aspect ratio).
// It is equivalent to stretching/shrinking the sphere (by the aspect ratio) into an ellipsoid.
float diff = projL - projL * invAspectRatio;
unL -= diff * axis;
return SmoothDistanceAttenuation(dot(unL, unL), invSqrAttenuationRadius);
}
// Applies SmoothDistanceAttenuation() after stretching/shrinking the attenuation sphere
// of the given radius into an ellipsoid. The process is performed along the 2 specified axes, and
// the magnitude of the transformation is controlled by the aspect ratios (the inverses are given).
// Both the ellipsoid (e.i. 'axis1', 'axis2') and 'unL' should be in the same coordinate system.
// 'unL' should be computed from the center of the ellipsoid.
float GetEllipsoidalDistanceAttenuation(float3 unL, float invSqrAttenuationRadius,
float3 axis1, float invAspectRatio1,
float3 axis2, float invAspectRatio2)
{
// Project the unnormalized light vector onto the stretching/shrinking axes.
float projL1 = dot(unL, axis1);
float projL2 = dot(unL, axis2);
// We want 'unL' to stretch/shrink along each axis (by the inverse of the aspect ratio).
// It is equivalent to stretching/shrinking the sphere (by the aspect ratio) into an ellipsoid.
float diff1 = projL1 - projL1 * invAspectRatio1;
float diff2 = projL2 - projL2 * invAspectRatio2;
unL -= diff1 * axis1;
unL -= diff2 * axis2;
return SmoothDistanceAttenuation(dot(unL, unL), invSqrAttenuationRadius);
}

正在加载...
取消
保存