浏览代码

Merge pull request #244 from EvgeniiG/master

Implement an approximated version of PolygonIrradiance()
/Branch_batcher
GitHub 7 年前
当前提交
14263d85
共有 2 个文件被更改,包括 43 次插入18 次删除
  1. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
  2. 59
      Assets/ScriptableRenderPipeline/ShaderLibrary/AreaLighting.hlsl

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl


float3 unL = lightData.positionWS - positionWS;
[branch]
if (dot(lightData.forward, unL) >= 0)
if (dot(lightData.forward, unL) >= 0.0001)
{
// The light is back-facing.
return;

59
Assets/ScriptableRenderPipeline/ShaderLibrary/AreaLighting.hlsl


// N.b.: this function accounts for horizon clipping.
float DiffuseSphereLightIrradiance(float sinSqSigma, float cosOmega)
{
float irradiance;
// Clamp to avoid visual artifacts.
sinSqSigma = min(sinSqSigma, 0.999);
#if 0 // Ref: Area Light Sources for Real-Time Graphics, page 4 (1996).
float sinSqOmega = saturate(1 - cosOmega * cosOmega);

float omega = acos(cosOmega);
float gamma = asin(sinGamma);
if (omega < 0 || omega >= HALF_PI + sigma)
if (omega >= HALF_PI + sigma)
{
// Full horizon occlusion (case #4).
return 0;

if (omega < HALF_PI - sigma)
{
// No horizon occlusion (case #1).
irradiance = e;
return e;
}
else
{

if (omega < HALF_PI)
{
// Partial horizon occlusion (case #2).
irradiance = e + INV_PI * (g - h);
return saturate(e + INV_PI * (g - h));
irradiance = INV_PI * (g + h);
return saturate(INV_PI * (g + h));
#else // Ref: Moving Frostbite to Physically Based Rendering, page 47 (2015).
float cosSqOmega = cosOmega * cosOmega;
#else // Ref: Moving Frostbite to Physically Based Rendering, page 47 (2015, optimized).
float cosSqOmega = cosOmega * cosOmega; // y^2
if (cosSqOmega > sinSqSigma)
if (cosSqOmega > sinSqSigma) // (y^2)>x
irradiance = sinSqSigma * saturate(cosOmega);
return sinSqSigma * saturate(cosOmega); // x*Clip[y,{0,1}]
float cotanOmega = cosOmega * rsqrt(1 - cosSqOmega);
float cotSqSigma = rcp(sinSqSigma) - 1; // 1/x-1
float tanSqSigma = rcp(cotSqSigma); // x/(1-x)
float sinSqOmega = 1 - cosSqOmega; // 1-y^2
float w = sinSqOmega * tanSqSigma; // (1-y^2)*(x/(1-x))
float x = -cosOmega * rsqrt(w); // -y*Sqrt[(1/x-1)/(1-y^2)]
float y = sqrt(sinSqOmega * tanSqSigma - cosSqOmega); // Sqrt[(1-y^2)*(x/(1-x))-y^2]
float z = y * cotSqSigma; // Sqrt[(1-y^2)*(x/(1-x))-y^2]*(1/x-1)
float x = rcp(sinSqSigma) - 1;
float y = -cotanOmega * sqrt(x);
float z = sqrt(1 - cosSqOmega * rcp(sinSqSigma));
float a = cosOmega * acos(x) - z; // y*ArcCos[-y*Sqrt[(1/x-1)/(1-y^2)]]-Sqrt[(1-y^2)*(x/(1-x))-y^2]*(1/x-1)
float b = atan(y); // ArcTan[Sqrt[(1-y^2)*(x/(1-x))-y^2]]
irradiance = INV_PI * ((cosOmega * acos(y) - z * sqrt(x)) * sinSqSigma + atan(z * rsqrt(x)));
// Replacing max() with saturate() results in a 12 cycle SGPR forwarding stall on PS4.
return max(INV_PI * (a * sinSqSigma + b), 0); // (a/Pi)*x+(b/Pi)
return max(irradiance, 0);
}
// Expects non-normalized vertex positions.

for (int i = 0; i < 4; i++)
float h = saturate(L[0].z) + saturate(L[1].z) + saturate(L[2].z) + saturate(L[3].z);
[branch]
if (h == 0) { return 0; } // Perform horizon clipping
[unroll]
for (uint i = 0; i < 4; i++)
{
L[i] = normalize(L[i]);
}

[unroll]
for (uint edge = 0; edge < 4; edge++)
{
float3 V1 = L[edge];

float sinSqSigma = sqrt(f2);
float cosOmega = clamp(F.z * rsqrt(f2), -1, 1);
return DiffuseSphereLightIrradiance(sinSqSigma, cosOmega);
#if 0
return DiffuseSphereLightIrradiance(sinSqSigma, cosOmega);
#else
float x = sinSqSigma;
float y = cosOmega;
float b = x * (0.5 + 0.5 * y); // Bilinear approximation of a sphere light
float z = b * (0.5 + 0.5 * y); // Our approximation of a rectangular light
float r = x * y; // The reference value for an unoccluded light
return max(r, lerp(z * z, z, saturate(h))); // Horizon fade
#endif
#else
// 1. ClipQuadToHorizon

正在加载...
取消
保存