浏览代码

Optimize attenuation functions for ALU

/main
Evgenii Golubev 7 年前
当前提交
2680050a
共有 4 个文件被更改,包括 89 次插入52 次删除
  1. 80
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonLighting.hlsl
  2. 19
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightEvaluation.hlsl
  3. 17
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/Resources/VolumetricLighting.compute
  4. 25
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl

80
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonLighting.hlsl


// Attenuation functions
//-----------------------------------------------------------------------------
// Ref: Moving Frostbite to PBR
real SmoothDistanceAttenuation(real squaredDistance, real invSqrAttenuationRadius)
// Ref: Moving Frostbite to PBR.
real QuadraticAttenuation(float attenuation)
{
return attenuation * attenuation;
}
// Non physically based hack to limit light influence to attenuationRadius.
real DistanceAttenuation(real squaredDistance, real invSqrAttenuationRadius)
real smoothFactor = saturate(1.0 - factor * factor);
return smoothFactor * smoothFactor;
return saturate(1.0 - factor * factor);
}
real SmoothDistanceAttenuation(real squaredDistance, real invSqrAttenuationRadius)
{
real smoothFactor = DistanceAttenuation(squaredDistance, invSqrAttenuationRadius);
return QuadraticAttenuation(smoothFactor);
real GetDistanceAttenuation(real sqrDist, real invSqrAttenuationRadius)
real SmoothQuadraticDistanceAttenuation(real distSq, real distRcp, real invSqrAttenuationRadius)
real attenuation = 1.0 / (max(PUNCTUAL_LIGHT_THRESHOLD * PUNCTUAL_LIGHT_THRESHOLD, sqrDist));
// Non physically based hack to limit light influence to attenuationRadius.
attenuation *= SmoothDistanceAttenuation(sqrDist, invSqrAttenuationRadius);
return attenuation;
// Becomes quadratic after the call to QuadraticAttenuation().
real attenuation = min(distRcp, 1.0 / PUNCTUAL_LIGHT_THRESHOLD);
attenuation *= DistanceAttenuation(distSq, invSqrAttenuationRadius);
return QuadraticAttenuation(attenuation);
real GetDistanceAttenuation(real3 unL, real invSqrAttenuationRadius)
real SmoothQuadraticDistanceAttenuation(real3 unL, real invSqrAttenuationRadius)
real sqrDist = dot(unL, unL);
return GetDistanceAttenuation(sqrDist, invSqrAttenuationRadius);
real distSq = dot(unL, unL);
real distRcp = rsqrt(distSq);
return SmoothQuadraticDistanceAttenuation(distSq, distRcp, invSqrAttenuationRadius);
real GetAngleAttenuation(real3 L, real3 lightDir, real lightAngleScale, real lightAngleOffset)
real AngleAttenuation(real cosFwd, real lightAngleScale, real lightAngleOffset)
real cd = dot(lightDir, L);
real attenuation = saturate(cd * lightAngleScale + lightAngleOffset);
// smooth the transition
attenuation *= attenuation;
return saturate(cosFwd * lightAngleScale + lightAngleOffset);
}
return attenuation;
real SmoothAngleAttenuation(real cosFwd, real lightAngleScale, real lightAngleOffset)
{
real attenuation = AngleAttenuation(cosFwd, lightAngleScale, lightAngleOffset);
return QuadraticAttenuation(attenuation);
}
real SmoothAngleAttenuation(real3 L, real3 lightFwdDir, real lightAngleScale, real lightAngleOffset)
{
real cosFwd = dot(-L, lightFwdDir);
return SmoothAngleAttenuation(cosFwd, lightAngleScale, lightAngleOffset);
}
// Combines SmoothQuadraticDistanceAttenuation() and SmoothAngleAttenuation() in an efficient manner.
// distances = {d, d^2, 1/d, d_proj}, where d_proj = dot(lightToSample, lightData.forward).
float SmoothPunctualLightAttenuation(float4 distances, real invSqrAttenuationRadius,
real lightAngleScale, real lightAngleOffset)
{
float distSq = distances.y;
float distRcp = distances.z;
float distProj = distances.w;
float cosFwd = distProj * distRcp;
real attenuation = min(distRcp, 1.0 / PUNCTUAL_LIGHT_THRESHOLD);
attenuation *= DistanceAttenuation(distSq, invSqrAttenuationRadius);
attenuation *= AngleAttenuation(cosFwd, lightAngleScale, lightAngleOffset);
return QuadraticAttenuation(attenuation);
}
// Applies SmoothDistanceAttenuation() after transforming the attenuation ellipsoid into a sphere.

// 'unL' should be computed from the center of the ellipsoid.
real GetEllipsoidalDistanceAttenuation(real3 unL, real invSqRadius,
real3 axis, real invAspectRatio)
real EllipsoidalDistanceAttenuation(real3 unL, real invSqRadius,
real3 axis, real invAspectRatio)
{
// Project the unnormalized light vector onto the axis.
real projL = dot(unL, axis);

// Applies SmoothDistanceAttenuation() using the axis-aligned ellipsoid of the given dimensions.
// Both the ellipsoid and 'unL' should be in the same coordinate system.
// 'unL' should be computed from the center of the ellipsoid.
real GetEllipsoidalDistanceAttenuation(real3 unL, real3 invHalfDim)
real EllipsoidalDistanceAttenuation(real3 unL, real3 invHalfDim)
{
// Transform the light vector so that we can work with
// with the ellipsoid as if it was a unit sphere.

// If the diagonal of the box is 'd', invHalfDim = rcp(0.5 * d).
// Both the box and 'unL' should be in the same coordinate system.
// 'unL' should be computed from the center of the box.
real GetBoxDistanceAttenuation(real3 unL, real3 invHalfDim)
real BoxDistanceAttenuation(real3 unL, real3 invHalfDim)
{
// Transform the light vector so that we can work with
// with the box as if it was a [-1, 1]^2 cube.

19
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightEvaluation.hlsl


return cookie;
}
float GetPunctualShapeAttenuation(LightData lightData, float3 L, float distSq)
{
// Note: lightData.invSqrAttenuationRadius is 0 when applyRangeAttenuation is false
float attenuation = GetDistanceAttenuation(distSq, lightData.invSqrAttenuationRadius);
// Reminder: lights are oriented backward (-Z)
return attenuation * GetAngleAttenuation(L, -lightData.forward, lightData.angleScale, lightData.angleOffset);
}
// distances = {d, d^2, 1/d, d_proj}, where d_proj = dot(lightToSample, lightData.forward).
float3 N, float3 L, float3 lightToSample, float dist, float distSq,
float3 N, float3 L, float3 lightToSample, float4 distances,
out float3 color, out float attenuation)
{
float3 positionWS = posInput.positionWS;

color = lightData.color;
attenuation = GetPunctualShapeAttenuation(lightData, L, distSq);
attenuation = SmoothPunctualLightAttenuation(distances, lightData.invSqrAttenuationRadius,
lightData.angleScale, lightData.angleOffset);
float distProj = dot(lightToSample, lightData.forward);
float distVol = (lightData.lightType == GPULIGHTTYPE_PROJECTOR_BOX) ? distProj : dist;
float distVol = (lightData.lightType == GPULIGHTTYPE_PROJECTOR_BOX) ? distances.w : distances.x;
attenuation *= TransmittanceHomogeneousMedium(_GlobalFog_Extinction, distVol);
#endif

{
// TODO: make projector lights cast shadows.
float3 offset = float3(0.0, 0.0, 0.0); // GetShadowPosOffset(nDotL, normal);
float4 L_dist = float4(L, dist);
float4 L_dist = float4(L, distances.x);
shadow = GetPunctualShadowAttenuation(lightLoopContext.shadowContext, positionWS + offset, N, lightData.shadowIndex, L_dist, posInput.positionSS);
#ifdef SHADOWS_SHADOWMASK
// Note: Legacy Unity have two shadow mask mode. ShadowMask (ShadowMask contain static objects shadow and ShadowMap contain only dynamic objects shadow, final result is the minimun of both value)

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


posInput.positionWS = GetPointAtDistance(ray, t);
float3 lightToSample = posInput.positionWS - light.positionWS;
float dist = sqrt(distSq);
float3 L = -lightToSample * rsqrt(distSq);
float distRcp = rsqrt(distSq);
float dist = distSq * distRcp;
float distProj = dot(lightToSample, light.forward);
float4 distances = float4(dist, distSq, distRcp, distProj);
float3 L = -lightToSample * distRcp;
EvaluateLight_Punctual(context, posInput, light, unused, 0, L, lightToSample, dist, distSq,
color, attenuation);
EvaluateLight_Punctual(context, posInput, light, unused, 0, L, lightToSample,
distances, color, attenuation);
float intensity = attenuation * rcpPdf;

float3 L = -light.forward;
float3 lightToSample = posInput.positionWS - light.positionWS;
float distProj = dot(lightToSample, light.forward);
float4 distances = float4(1, 1, 1, distProj);
EvaluateLight_Punctual(context, posInput, light, unused, 0, L, lightToSample, 1, 1,
color, attenuation);
EvaluateLight_Punctual(context, posInput, light, unused, 0, L, lightToSample,
distances, color, attenuation);
// Note: the 'weight' accounts for transmittance from 'tEntr' to 't'.
float intensity = attenuation * weight;

25
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl


int lightType = lightData.lightType;
float3 L;
float dist, distSq, distProj;
float4 distances; // {d, d^2, 1/d, d_proj}
distances.w = dot(lightToSample, lightData.forward);
dist = distSq = 1; // No distance attenuation
L = -lightData.forward; // No angle attenuation
L = -lightData.forward;
distances.xyz = 1; // No distance or angle attenuation
distSq = dot(unL, unL);
float distSq = dot(unL, unL);
dist = distSq * distRcp;
L = unL * distRcp;
float dist = distSq * distRcp;
L = unL * distRcp;
distances.xyz = float3(dist, distSq, distRcp);
}
float3 N = bsdfData.normalWS;

float3 color;
float attenuation;
EvaluateLight_Punctual(lightLoopContext, posInput, lightData, bakeLightingData, N, L,
lightToSample, dist, distSq, color, attenuation);
lightToSample, distances, color, attenuation);
float intensity = saturate(attenuation * NdotL);

float invAspectRatio = radius / (radius + (0.5 * len));
// Compute the light attenuation.
float intensity = GetEllipsoidalDistanceAttenuation(unL, lightData.invSqrAttenuationRadius,
axis, invAspectRatio);
float intensity = EllipsoidalDistanceAttenuation(unL, lightData.invSqrAttenuationRadius,
axis, invAspectRatio);
// Terminate if the shaded point is too far away.
if (intensity == 0.0)

#ifdef ELLIPSOIDAL_ATTENUATION
// The attenuation volume is an axis-aligned ellipsoid s.t.
// r1 = (r + w / 2), r2 = (r + h / 2), r3 = r.
float intensity = GetEllipsoidalDistanceAttenuation(unL, invHalfDim);
float intensity = EllipsoidalDistanceAttenuation(unL, invHalfDim);
float intensity = GetBoxDistanceAttenuation(unL, invHalfDim);
float intensity = BoxDistanceAttenuation(unL, invHalfDim);
#endif
// Terminate if the shaded point is too far away.

正在加载...
取消
保存