Added UTSPolygonFormFactor and UTSComputeEdgeFactor
This commit is contained in:
@@ -187,3 +187,80 @@ half3 FitWithCurveApprox(half NdotL, half Curvature)
|
||||
}
|
||||
#endif
|
||||
|
||||
// The output is *not* normalized by the factor of 1/TWO_PI (this is done by the PolygonFormFactor function).
|
||||
real3 UTSComputeEdgeFactor(real3 V1, real3 V2)
|
||||
{
|
||||
real subtendedAngle;
|
||||
|
||||
real V1oV2 = dot(V1, V2);
|
||||
real3 V1xV2 = cross(V1, V2); // Plane normal (tangent to the unit sphere)
|
||||
real sqLen = saturate(1 - V1oV2 * V1oV2); // length(V1xV2) = abs(sin(angle))
|
||||
real rcpLen = rsqrt(max(FLT_EPS, sqLen)); // Make sure it is finite
|
||||
#if 0
|
||||
real y = rcpLen * acos(V1oV2);
|
||||
#else
|
||||
// Let y[x_] = ArcCos[x] / Sqrt[1 - x^2].
|
||||
// Range reduction: since ArcCos[-x] == Pi - ArcCos[x], we only need to consider x on [0, 1].
|
||||
real x = abs(V1oV2);
|
||||
// Limit[y[x], x -> 1] == 1,
|
||||
// Limit[y[x], x -> 0] == Pi/2.
|
||||
// The approximation is exact at the endpoints of [0, 1].
|
||||
// Max. abs. error on [0, 1] is 1.33e-6 at x = 0.0036.
|
||||
// Max. rel. error on [0, 1] is 8.66e-7 at x = 0.0037.
|
||||
real y = HALF_PI + x * (-0.99991 + x * (0.783393 + x * (-0.649178 + x * (0.510589 + x * (-0.326137 + x * (0.137528 + x * -0.0270813))))));
|
||||
|
||||
if (V1oV2 < 0)
|
||||
{
|
||||
y = rcpLen * PI - y;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return V1xV2 * y;
|
||||
}
|
||||
|
||||
// Input: 3-5 vertices in the coordinate frame centered at the shaded point.
|
||||
// Output: signed vector irradiance.
|
||||
// No horizon clipping is performed.
|
||||
real3 UTSPolygonFormFactor(real4x3 L, real3 L4, uint n)
|
||||
{
|
||||
// The length cannot be zero since we have already checked
|
||||
// that the light has a non-zero effective area,
|
||||
// and thus its plane cannot pass through the origin.
|
||||
L[0] = normalize(L[0]);
|
||||
L[1] = normalize(L[1]);
|
||||
L[2] = normalize(L[2]);
|
||||
|
||||
switch (n)
|
||||
{
|
||||
case 3:
|
||||
L[3] = L[0];
|
||||
break;
|
||||
case 4:
|
||||
L[3] = normalize(L[3]);
|
||||
L4 = L[0];
|
||||
break;
|
||||
case 5:
|
||||
L[3] = normalize(L[3]);
|
||||
L4 = normalize(L4);
|
||||
break;
|
||||
}
|
||||
|
||||
// If the magnitudes of a pair of edge factors are
|
||||
// nearly the same, catastrophic cancellation may occur:
|
||||
// https://en.wikipedia.org/wiki/Catastrophic_cancellation
|
||||
// For the same reason, the value of the cross product of two
|
||||
// nearly collinear vectors is prone to large errors.
|
||||
// Therefore, the algorithm is inherently numerically unstable
|
||||
// for area lights that shrink to a line (or a point) after
|
||||
// projection onto the unit sphere.
|
||||
real3 F = UTSComputeEdgeFactor(L[0], L[1]);
|
||||
F += UTSComputeEdgeFactor(L[1], L[2]);
|
||||
F += UTSComputeEdgeFactor(L[2], L[3]);
|
||||
if (n >= 4)
|
||||
F += UTSComputeEdgeFactor(L[3], L4);
|
||||
if (n == 5)
|
||||
F += UTSComputeEdgeFactor(L4, L[0]);
|
||||
|
||||
return F; // The output may be projected onto the tangent plane (F.z) to yield signed irradiance.
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
//nobuyuki@unity3d.com
|
||||
//toshiyuki@unity3d.com (Universal RP/HDRP)
|
||||
|
||||
#define APPROXIMATE_POLY_LIGHT_AS_SPHERE_LIGHT
|
||||
|
||||
#if SHADERPASS != SHADERPASS_FORWARD
|
||||
#error SHADERPASS_is_not_correctly_define
|
||||
#endif
|
||||
@@ -530,14 +532,14 @@ void Frag(PackedVaryingsToPS packedInput,
|
||||
float4 distances; // {d, d^2, 1/d, d_proj}
|
||||
GetPunctualLightVectors(posInput.positionWS, s_lightData, lightDirection, distances);
|
||||
float4 lightColor = EvaluateLight_Punctual(context, posInput, s_lightData, lightDirection, distances);
|
||||
float3 additionalLightColor = ApplyCurrentExposureMultiplier(lightColor.rgb) * lightColor.a;
|
||||
float3 additionalLightColor = ApplyCurrentExposureMultiplier(lightColor.rgb);
|
||||
const float notDirectional = 1.0f;
|
||||
|
||||
UTSLightData utsLightData;
|
||||
utsLightData.lightColor = additionalLightColor;
|
||||
utsLightData.lightDirection = lightDirection;
|
||||
utsLightData.diffuseDimmer = s_lightData.diffuseDimmer;
|
||||
utsLightData.specularDimmer = s_lightData.specularDimmer;
|
||||
utsLightData.diffuseDimmer = s_lightData.diffuseDimmer * lightColor.a;
|
||||
utsLightData.specularDimmer = s_lightData.specularDimmer * lightColor.a;
|
||||
utsLightData.shadowTint = s_lightData.shadowTint;
|
||||
utsLightData.penumbraTint = s_lightData.penumbraTint;
|
||||
|
||||
@@ -634,12 +636,25 @@ void Frag(PackedVaryingsToPS packedInput,
|
||||
|
||||
float4 ltcValue;
|
||||
|
||||
float4x3 lightVerts;
|
||||
|
||||
float3x3 invM = transpose(preLightData.ltcTransformDiffuse);
|
||||
float3 A = mul(invM, right);
|
||||
float3 B = mul(invM, up);
|
||||
float3 C = mul(invM, center);
|
||||
lightVerts[0] = C - halfWidth * A - halfHeight * B; // LL
|
||||
lightVerts[1] = lightVerts[0] + (2 * halfHeight) * B; // UL
|
||||
lightVerts[2] = lightVerts[1] + (2 * halfWidth) * A; // UR
|
||||
lightVerts[3] = lightVerts[2] - (2 * halfHeight) * B; // LR
|
||||
|
||||
float3 F = UTSPolygonFormFactor(lightVerts, float3(0,0,1), 4);
|
||||
float l = length(F * PI);
|
||||
float alpha = saturate(max(0, (l * l) / (l + 1)));
|
||||
|
||||
// Diffuse
|
||||
ltcValue = EvaluateLTC_Area(isRectLight, center, right, up, halfWidth, halfHeight, transpose(preLightData.ltcTransformDiffuse), /*bsdfData.perceptualRoughness*/ 1.0f, s_lightData.cookieMode, s_lightData.cookieScaleOffset);
|
||||
utsLightData.diffuseDimmer *= ltcValue.a * intensity;
|
||||
//ltcValue = smoothstep(0.0, 0.05, ltcValue);
|
||||
//utsLightData.lightColor *= ltcValue.rgb * ltcValue.a * intensity;
|
||||
utsLightData.lightColor *= ltcValue.rgb * intensity;
|
||||
utsLightData.diffuseDimmer *= alpha * intensity;
|
||||
utsLightData.lightColor *= ltcValue.rgb;
|
||||
|
||||
// Specular
|
||||
ltcValue = EvaluateLTC_Area(isRectLight, center, right, up, halfWidth, halfHeight, transpose(preLightData.ltcTransformSpecular[0]), bsdfData.perceptualRoughness, s_lightData.cookieMode, s_lightData.cookieScaleOffset);
|
||||
@@ -672,162 +687,6 @@ void Frag(PackedVaryingsToPS packedInput,
|
||||
//utsAggregateLighting.directDiffuse += intensity;
|
||||
#endif
|
||||
|
||||
/*
|
||||
if(s_lightData.lightType == GPULIGHTTYPE_RECTANGLE)
|
||||
{
|
||||
#if SHADEROPTIONS_BARN_DOOR
|
||||
// Apply the barn door modification to the light data
|
||||
RectangularLightApplyBarnDoor(s_lightData, posInput.positionWS);
|
||||
#endif
|
||||
|
||||
if (dot(s_lightData.forward, unL) < FLT_EPS)
|
||||
{
|
||||
float3x3 lightToWorld = float3x3(s_lightData.right, s_lightData.up, -s_lightData.forward);
|
||||
unL = mul(unL, transpose(lightToWorld));
|
||||
|
||||
float halfWidth = s_lightData.size.x * 0.5;
|
||||
float halfHeight = s_lightData.size.y * 0.5;
|
||||
|
||||
float range = s_lightData.range;
|
||||
float3 invHalfDim = rcp(float3(range + halfWidth, range + halfHeight, range));
|
||||
|
||||
float intensity;
|
||||
// Compute the light attenuation.
|
||||
#ifdef ELLIPSOIDAL_ATTENUATION
|
||||
// The attenuation volume is an axis-aligned ellipsoid s.t.
|
||||
// r1 = (r + w / 2), r2 = (r + h / 2), r3 = r.
|
||||
intensity = EllipsoidalDistanceAttenuation(unL, invHalfDim, s_lightData.rangeAttenuationScale, s_lightData.rangeAttenuationBias);
|
||||
#else
|
||||
// The attenuation volume is an axis-aligned box s.t.
|
||||
// hX = (r + w / 2), hY = (r + h / 2), hZ = r.
|
||||
intensity = BoxDistanceAttenuation(unL, invHalfDim, s_lightData.rangeAttenuationScale, s_lightData.rangeAttenuationBias);
|
||||
#endif
|
||||
|
||||
if(intensity != 0.0f)
|
||||
{
|
||||
utsLightData.diffuseDimmer *= intensity;
|
||||
utsLightData.specularDimmer *= intensity;
|
||||
|
||||
// Translate the light s.t. the shaded point is at the origin of the coordinate system.
|
||||
s_lightData.positionRWS -= posInput.positionWS;
|
||||
|
||||
float4x3 lightVerts;
|
||||
|
||||
// TODO: some of this could be precomputed.
|
||||
lightVerts[0] = s_lightData.positionRWS + s_lightData.right * -halfWidth + s_lightData.up * -halfHeight; // LL
|
||||
lightVerts[1] = s_lightData.positionRWS + s_lightData.right * -halfWidth + s_lightData.up * halfHeight; // UL
|
||||
lightVerts[2] = s_lightData.positionRWS + s_lightData.right * halfWidth + s_lightData.up * halfHeight; // UR
|
||||
lightVerts[3] = s_lightData.positionRWS + s_lightData.right * halfWidth + s_lightData.up * -halfHeight; // LR
|
||||
|
||||
// Rotate the endpoints into the local coordinate system.
|
||||
lightVerts = mul(lightVerts, transpose(preLightData.orthoBasisViewNormal));
|
||||
|
||||
float3 ltcValue;
|
||||
|
||||
// Evaluate the diffuse part
|
||||
// Polygon irradiance in the transformed configuration.
|
||||
float4x3 LD = mul(lightVerts, preLightData.ltcTransformDiffuse);
|
||||
float3 formFactorD;
|
||||
|
||||
#ifdef APPROXIMATE_POLY_LIGHT_AS_SPHERE_LIGHT
|
||||
formFactorD = PolygonFormFactor(LD, real3(0,0,1), 4);
|
||||
ltcValue = PolygonIrradianceFromVectorFormFactor(formFactorD);
|
||||
#else
|
||||
ltcValue = PolygonIrradiance(LD);
|
||||
#endif
|
||||
|
||||
utsLightData.diffuseDimmer *= ltcValue;
|
||||
|
||||
// Evaluate the specular part
|
||||
// Polygon irradiance in the transformed configuration.
|
||||
float4x3 LS = mul(lightVerts, preLightData.ltcTransformSpecular);
|
||||
float3 formFactorS;
|
||||
#ifdef APPROXIMATE_POLY_LIGHT_AS_SPHERE_LIGHT
|
||||
formFactorS = PolygonFormFactor(LS, real3(0,0,1), 4);
|
||||
ltcValue = PolygonIrradianceFromVectorFormFactor(formFactorS);
|
||||
#else
|
||||
ltcValue = PolygonIrradiance(LS);
|
||||
#endif
|
||||
|
||||
utsLightData.specularDimmer *= ltcValue;
|
||||
|
||||
//Evaluate the shadow part
|
||||
float shadow;
|
||||
posInput.positionWS = posInput.positionWS + lightDirection * _ShadowBias;
|
||||
#if defined(SCREEN_SPACE_SHADOWS_ON) && !defined(_SURFACE_TYPE_TRANSPARENT)
|
||||
if ((s_lightData.screenSpaceShadowIndex & SCREEN_SPACE_SHADOW_INDEX_MASK) != INVALID_SCREEN_SPACE_SHADOW)
|
||||
{
|
||||
shadow = GetScreenSpaceShadow(posInput, s_lightData.screenSpaceShadowIndex);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
shadow = EvaluateShadow_RectArea(context, posInput, s_lightData, builtinData, GetNormalForShadowBias(bsdfData), normalize(s_lightData.positionRWS), length(s_lightData.positionRWS));
|
||||
}
|
||||
context.shadowValue = shadow;
|
||||
posInput.positionWS = posInput.positionWS - lightDirection * _ShadowBias;
|
||||
|
||||
#if defined(UTS_DEBUG_SELFSHADOW)
|
||||
|
||||
#else
|
||||
UTS_OtherLights(context, input, utsLightData, surfaceData, bsdfData, s_lightData.lightType, i_normalDir, notDirectional, channelAlpha, utsAggregateLighting);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(s_lightData.lightType == GPULIGHTTYPE_TUBE)
|
||||
{
|
||||
float len = s_lightData.size.x;
|
||||
float3 T = s_lightData.right;
|
||||
|
||||
// Pick the major axis of the ellipsoid.
|
||||
float3 axis = s_lightData.right;
|
||||
|
||||
// We define the ellipsoid s.t. r1 = (r + len / 2), r2 = r3 = r.
|
||||
// TODO: This could be precomputed.
|
||||
float range = s_lightData.range;
|
||||
float invAspectRatio = saturate(range / (range + (0.5 * len)));
|
||||
|
||||
// Compute the light attenuation.
|
||||
float intensity = EllipsoidalDistanceAttenuation(unL, axis, invAspectRatio, s_lightData.rangeAttenuationScale, s_lightData.rangeAttenuationBias);
|
||||
|
||||
if(intensity != 0.0f)
|
||||
{
|
||||
utsLightData.diffuseDimmer *= intensity;
|
||||
utsLightData.specularDimmer *= intensity;
|
||||
|
||||
// Translate the light s.t. the shaded point is at the origin of the coordinate system.
|
||||
s_lightData.positionRWS -= posInput.positionWS;
|
||||
|
||||
// TODO: some of this could be precomputed.
|
||||
float3 P1 = s_lightData.positionRWS - T * (0.5 * len);
|
||||
float3 P2 = s_lightData.positionRWS + T * (0.5 * len);
|
||||
|
||||
// Rotate the endpoints into the local coordinate system.
|
||||
P1 = mul(P1, transpose(preLightData.orthoBasisViewNormal));
|
||||
P2 = mul(P2, transpose(preLightData.orthoBasisViewNormal));
|
||||
|
||||
// Compute the binormal in the local coordinate system.
|
||||
float3 B = normalize(cross(P1, P2));
|
||||
|
||||
float ltcValue;
|
||||
|
||||
// Evaluate the diffuse part
|
||||
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcTransformDiffuse);
|
||||
utsLightData.diffuseDimmer *= ltcValue;
|
||||
|
||||
// Evaluate the specular part
|
||||
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcTransformSpecular);
|
||||
utsLightData.specularDimmer *= ltcValue;
|
||||
|
||||
#if defined(UTS_DEBUG_SELFSHADOW)
|
||||
|
||||
#else
|
||||
UTS_OtherLights(context, input, utsLightData, surfaceData, bsdfData, s_lightData.lightType, i_normalDir, notDirectional, channelAlpha, utsAggregateLighting);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
s_lightData = FetchLight(lightStart, min(++i, last));
|
||||
|
||||
@@ -54,23 +54,21 @@ void UTS_OtherLights(LightLoopContext lightLoopContext, FragInputs input, UTSLig
|
||||
float3 addPassLightColor;
|
||||
if (lightType == GPULIGHTTYPE_TUBE)
|
||||
{
|
||||
addPassLightColor = (0.5f * preLightData.diffuseFGD + 0.5f) / PI * additionalLightColor.rgb * utsLightData.diffuseDimmer;
|
||||
addPassLightColor = (0.5f * preLightData.diffuseFGD + 0.5f) / PI * additionalLightColor.rgb;
|
||||
}
|
||||
else if (lightType == GPULIGHTTYPE_RECTANGLE)
|
||||
{
|
||||
addPassLightColor = preLightData.diffuseFGD * additionalLightColor.rgb * utsLightData.diffuseDimmer;
|
||||
//addPassLightColor = (0.5f * preLightData.diffuseFGD + 0.5f) * additionalLightColor.rgb * utsLightData.diffuseDimmer;
|
||||
addPassLightColor = preLightData.diffuseFGD * additionalLightColor.rgb;
|
||||
}
|
||||
else
|
||||
{
|
||||
addPassLightColor = _HalfLambert_var * additionalLightColor.rgb * utsLightData.diffuseDimmer;
|
||||
addPassLightColor = _HalfLambert_var * additionalLightColor.rgb;
|
||||
}
|
||||
|
||||
float pureIntencity = max(0.001, (0.299 * additionalLightColor.r + 0.587 * additionalLightColor.g + 0.114 * additionalLightColor.b));
|
||||
float pureIntencity = max(0.001, (0.299 * additionalLightColor.r + 0.587 * additionalLightColor.g + 0.114 * additionalLightColor.b));
|
||||
float3 lightColor = max(float3(0.0, 0.0, 0.0), lerp(addPassLightColor, lerp(float3(0.0, 0.0, 0.0), min(addPassLightColor, addPassLightColor / pureIntencity), notDirectional), _Is_Filter_LightColor));
|
||||
float3 halfDirection = normalize(viewDirection + lightDirection); // has to be recalced here.
|
||||
//v.2.0.5:
|
||||
//v.2.0.5:
|
||||
_1st_ShadeColor_Step = saturate(_1st_ShadeColor_Step + _StepOffset);
|
||||
_2nd_ShadeColor_Step = saturate(_2nd_ShadeColor_Step + _StepOffset);
|
||||
//
|
||||
@@ -156,8 +154,8 @@ void UTS_OtherLights(LightLoopContext lightLoopContext, FragInputs input, UTSLig
|
||||
channelOutAlpha =
|
||||
lerp(Set_BaseColorAlpha, lerp(Set_1st_ShadeAlpha, Set_2nd_ShadeAlpha, Set_ShadeShadowMask), Set_FinalShadowMask);
|
||||
#endif
|
||||
utsAggregateLighting.directDiffuse = diffuseTerm;
|
||||
return;
|
||||
//utsAggregateLighting.directDiffuse = utsLightData.diffuseDimmer;
|
||||
//return;
|
||||
|
||||
//v.2.0.6: Add HighColor if _Is_Filter_HiCutPointLightColor is False
|
||||
|
||||
@@ -246,7 +244,7 @@ void UTS_OtherLights(LightLoopContext lightLoopContext, FragInputs input, UTSLig
|
||||
specularTerm = specularTerm * (1.0 - Set_FinalShadowMask) * PI * surfaceData.specularColor;
|
||||
diffuseTerm = diffuseTerm * albedoIntensity;
|
||||
|
||||
utsAggregateLighting.directDiffuse += diffuseTerm;
|
||||
utsAggregateLighting.directSpecular += specularTerm;
|
||||
utsAggregateLighting.directDiffuse += diffuseTerm * utsLightData.diffuseDimmer;
|
||||
utsAggregateLighting.directSpecular += specularTerm * utsLightData.specularDimmer;
|
||||
#endif // _SDFShadow
|
||||
}
|
||||
Reference in New Issue
Block a user