3 Commits

Author SHA1 Message Date
Misaki
e6b58cb321 Added UtsAreaLight.hlsl;
Fixed the problem that the appearence of direct diffuse is incorrect when area light intensity is low.

Changed the file name of PBR.hlsl to UtsPBR.hlsl
Changed the file name of EnvLighting.hlsl to UtsEnvLighting.hlsl
2025-01-18 14:14:00 +09:00
Misaki
12a03e9c3c Added UTSPolygonFormFactor and UTSComputeEdgeFactor 2025-01-17 18:47:37 +09:00
Misaki
b838223551 Changed area light calculation, need feature clean up 2025-01-17 18:45:41 +09:00
10 changed files with 257 additions and 213 deletions

View File

@@ -16,6 +16,10 @@ namespace Misaki.HdrpToon.Editor
private SerializedObject _customSettings;
private SerializedProperty _hairShadowSetting;
private SerializedProperty _hairBlendingSetting;
private SerializedProperty _outlineSetting;
public UTSRendererSettingProvider(string path, SettingsScope scopes, IEnumerable<string> keywords = null) : base(path, scopes, keywords)
{
}
@@ -23,15 +27,19 @@ namespace Misaki.HdrpToon.Editor
public override void OnActivate(string searchContext, VisualElement rootElement)
{
_customSettings = UTSRenderPassSettings.GetSerializedSettings();
_hairShadowSetting = _customSettings.FindProperty("hairShadowSetting");
_hairBlendingSetting = _customSettings.FindProperty("hairBlendingSetting");
_outlineSetting = _customSettings.FindProperty("outlineSetting");
}
public override void OnGUI(string searchContext)
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(_customSettings.FindProperty("hairShadowSetting"), Styles.hairShadow);
EditorGUILayout.PropertyField(_customSettings.FindProperty("hairBlendingSetting"), Styles.hairBlending);
EditorGUILayout.PropertyField(_customSettings.FindProperty("outlineSetting"), Styles.outline);
EditorGUILayout.PropertyField(_hairShadowSetting, Styles.hairShadow);
EditorGUILayout.PropertyField(_hairBlendingSetting, Styles.hairBlending);
EditorGUILayout.PropertyField(_outlineSetting, Styles.outline);
_customSettings.ApplyModifiedPropertiesWithoutUndo();
if (EditorGUI.EndChangeCheck())

View File

@@ -17,11 +17,16 @@ namespace Misaki.HdrpToon
private bool _initialized = false;
private bool _srpCallbackInitialized = false;
[SerializeField]
private HDAdditionalLightData _bindingSourceLightData;
[SerializeField]
private HDAdditionalLightData _targetBoxLightData;
[SerializeField]
private uint _layerMask;
[SerializeField]
private Light _bindingSourceLight;
[SerializeField]
private Light _targetBoxLight;
public Transform trackedTransform;
@@ -159,11 +164,6 @@ namespace Misaki.HdrpToon
Release();
}
private void UpdateObjectLightLayers()
{
Initialize();
}
internal static GameObject CreateBoxLight(Transform transform)
{
if (transform == null)

View File

@@ -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
@@ -14,7 +16,8 @@
#endif
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoopDef.hlsl"
#include "EnvLighting.hlsl"
#include "UtsEnvLighting.hlsl"
#include "UtsAreaLight.hlsl"
#include "HDRPToonFunction.hlsl"
#ifdef _WRITE_TRANSPARENT_MOTION_VECTOR
@@ -503,7 +506,6 @@ void Frag(PackedVaryingsToPS packedInput,
uint v_lightListOffset = 0;
uint v_lightIdx = lightStart;
float channelAlpha = 0.0f;
[loop] // vulkan shader compiler can not unroll.
while (v_lightListOffset < lightCount)
{
@@ -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 = saturate(s_lightData.diffuseDimmer * lightColor.a);
utsLightData.specularDimmer = saturate(s_lightData.specularDimmer * lightColor.a);
utsLightData.shadowTint = s_lightData.shadowTint;
utsLightData.penumbraTint = s_lightData.penumbraTint;
@@ -635,13 +637,13 @@ void Frag(PackedVaryingsToPS packedInput,
float4 ltcValue;
// 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;
utsLightData.lightColor *= ltcValue.rgb * ltcValue.a * intensity;
ltcValue = UTS_EvaluateLTC_Area(isRectLight, center, right, up, halfWidth, halfHeight, transpose(preLightData.ltcTransformDiffuse), /*bsdfData.perceptualRoughness*/ 1.0f, true, s_lightData.cookieMode, s_lightData.cookieScaleOffset);
utsLightData.diffuseDimmer *= saturate(ltcValue.a * 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);
utsLightData.specularDimmer *= ltcValue.a * intensity;
ltcValue = UTS_EvaluateLTC_Area(isRectLight, center, right, up, halfWidth, halfHeight, transpose(preLightData.ltcTransformSpecular[0]), bsdfData.perceptualRoughness, false, s_lightData.cookieMode, s_lightData.cookieScaleOffset);
utsLightData.specularDimmer *= saturate(ltcValue.a * intensity);
if (isRectLight)
{
@@ -670,162 +672,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));
@@ -940,8 +786,8 @@ void Frag(PackedVaryingsToPS packedInput,
#endif
// Ambient
utsAggregateLighting.indirectDiffuse = ComputeIndirectDiffuse(posInput, bsdfData, V) * _ID_Intensity;
utsAggregateLighting.indirectSpecular = ComputeIndirectSpecular(context, posInput, preLightData, bsdfData, surfaceData, builtinData, V) * _IR_Intensity;
utsAggregateLighting.indirectDiffuse = EvaluateIndirectDiffuse(posInput, bsdfData, V) * _ID_Intensity;
utsAggregateLighting.indirectSpecular = EvaluateIndirectSpecular(context, posInput, preLightData, bsdfData, surfaceData, builtinData, V) * _IR_Intensity;
float3 finalColorWoEmissive = AccumulateAggregateLighting(utsAggregateLighting);

View File

@@ -2,8 +2,9 @@
//nobuyuki@unity3d.com
//toshiyuki@unity3d.com (Universal RP/HDRP)
#include "PBR.hlsl"
void UTS_OtherLights(LightLoopContext lightLoopContext, FragInputs input, UTSLightData utsLightData, SurfaceData surfaceData, BSDFData bsdfData, int lightType, float3 i_normalDir, float notDirectional, out float channelOutAlpha, inout UTSAggregateLighting utsAggregateLighting)
#include "UtsPBR.hlsl"
void UTS_OtherLights(LightLoopContext lightLoopContext, FragInputs input, UTSLightData utsLightData, SurfaceData surfaceData, BSDFData bsdfData, int lightType, float3 i_normalDir, float notDirectional,
out float channelOutAlpha, inout UTSAggregateLighting utsAggregateLighting)
{
channelOutAlpha = 1.0f;
@@ -48,35 +49,38 @@ void UTS_OtherLights(LightLoopContext lightLoopContext, FragInputs input, UTSLig
shadowAttenuation = saturate(shadowAttenuation);
#endif
float _HalfLambert_var = 0.5 * dot(lerp(i_normalDir, normalDirection, _Is_NormalMapToBase), lightDirection) + 0.5;
//v.2.0.5:
float3 addPassLightColor;
if (lightType == GPULIGHTTYPE_TUBE)
{
addPassLightColor = (0.5f * (preLightData.diffuseFGD * utsLightData.diffuseDimmer) + 0.5f) / PI * additionalLightColor.rgb;
addPassLightColor = (0.5f * preLightData.diffuseFGD + 0.5f) / PI * additionalLightColor.rgb;
}
else if (lightType == GPULIGHTTYPE_RECTANGLE)
{
addPassLightColor = ((preLightData.diffuseFGD * utsLightData.diffuseDimmer)) * additionalLightColor.rgb;
addPassLightColor = preLightData.diffuseFGD * additionalLightColor.rgb;
}
else
{
addPassLightColor = (0.5f * dot(lerp(i_normalDir, normalDirection, _Is_NormalMapToBase), lightDirection) + 0.5f) * additionalLightColor.rgb ;
addPassLightColor = _HalfLambert_var * additionalLightColor.rgb;
}
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));
float pureIntensity = 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 / pureIntensity), 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);
//
//v.2.0.5: If Added lights is directional, set 0 as _LightIntensity
float _LightIntensity = lerp(0, (0.299 * additionalLightColor.r + 0.587 * additionalLightColor.g + 0.114 * additionalLightColor.b), notDirectional);
float _LightIntensity = lerp(0, pureIntensity, notDirectional);
//v.2.0.5: Filtering the high intensity zone of PointLights
float3 Set_LightColor = lightColor;
//
float3 Set_BaseColor = lerp((_BaseColor.rgb * _MainTex_var.rgb * _LightIntensity), ((_BaseColor.rgb * _MainTex_var.rgb) * Set_LightColor), _Is_LightColor_Base);
#ifdef UTS_LAYER_VISIBILITY
float Set_BaseColorAlpha = _BaseColorVisible;
float4 overridingColor = lerp(_BaseColorMaskColor, float4(_BaseColorMaskColor.w, _BaseColorMaskColor.w, _BaseColorMaskColor.w, 1.0f), _ComposerMaskMode);
@@ -85,6 +89,7 @@ void UTS_OtherLights(LightLoopContext lightLoopContext, FragInputs input, UTSLig
Set_BaseColor *= _BaseColorVisible;
#endif //#ifdef UTS_LAYER_VISIBILITY
//v.2.0.5
float4 _1st_ShadeMap_var = lerp(SAMPLE_TEXTURE2D(_1st_ShadeMap, sampler_BaseColorMap, TRANSFORM_TEX(Set_UV0, _1st_ShadeMap)), _MainTex_var, _Use_BaseAs1st);
float3 Set_1st_ShadeColor = lerp((_1st_ShadeColor.rgb * _1st_ShadeMap_var.rgb * _LightIntensity), ((_1st_ShadeColor.rgb * _1st_ShadeMap_var.rgb) * Set_LightColor), _Is_LightColor_1st_Shade);
@@ -97,6 +102,7 @@ void UTS_OtherLights(LightLoopContext lightLoopContext, FragInputs input, UTSLig
}
float Set_1st_ShadeAlpha = _FirstShadeVisible;
#endif //#ifdef UTS_LAYER_VISIBILITY //v.2.0.5
//v.2.0.5
float4 _2nd_ShadeMap_var = lerp(SAMPLE_TEXTURE2D(_2nd_ShadeMap, sampler_BaseColorMap, TRANSFORM_TEX(Set_UV0, _2nd_ShadeMap)), _1st_ShadeMap_var, _Use_1stAs2nd);
float3 Set_2nd_ShadeColor = lerp((_2nd_ShadeColor.rgb * _2nd_ShadeMap_var.rgb * _LightIntensity), ((_2nd_ShadeColor.rgb * _2nd_ShadeMap_var.rgb) * Set_LightColor), _Is_LightColor_2nd_Shade);
@@ -110,8 +116,6 @@ void UTS_OtherLights(LightLoopContext lightLoopContext, FragInputs input, UTSLig
}
#endif //#ifdef UTS_LAYER_VISIBILITY
float _HalfLambert_var = 0.5 * dot(lerp(i_normalDir, normalDirection, _Is_NormalMapToBase), lightDirection) + 0.5;
// //v.2.0.5:
//SGM
//v.2.0.6
@@ -131,8 +135,8 @@ void UTS_OtherLights(LightLoopContext lightLoopContext, FragInputs input, UTSLig
float _2ndColorFeatherForMask = lerp(_2nd_ShadeColor_Feather, 0.0f, max(_SecondShadeOverridden, _ComposerMaskMode));
//
float Set_FinalShadowMask = saturate((1.0 + ((Set_ShadingGrade - (_1st_ShadeColor_Step - _1stColorFeatherForMask)) * (0.0 - 1.0)) / (_1st_ShadeColor_Step - (_1st_ShadeColor_Step - _1stColorFeatherForMask))));
float Set_ShadeShadowMask = saturate((1.0 + ((Set_ShadingGrade - (_2nd_ShadeColor_Step - _2ndColorFeatherForMask)) * (0.0 - 1.0)) / (_2nd_ShadeColor_Step - (_2nd_ShadeColor_Step - _2ndColorFeatherForMask)))); // 1st and 2nd Shades Mask
float Set_FinalShadowMask = saturate(1.0 + (Set_ShadingGrade - (_1st_ShadeColor_Step - _1stColorFeatherForMask)) * (0.0 - 1.0) / (_1st_ShadeColor_Step - (_1st_ShadeColor_Step - _1stColorFeatherForMask)));
float Set_ShadeShadowMask = saturate(1.0 + (Set_ShadingGrade - (_2nd_ShadeColor_Step - _2ndColorFeatherForMask)) * (0.0 - 1.0) / (_2nd_ShadeColor_Step - (_2nd_ShadeColor_Step - _2ndColorFeatherForMask))); // 1st and 2nd Shades Mask
//SGM
@@ -147,11 +151,13 @@ void UTS_OtherLights(LightLoopContext lightLoopContext, FragInputs input, UTSLig
Set_ShadeShadowMask
),
Set_FinalShadowMask);
#ifdef UTS_LAYER_VISIBILITY
float Set_2nd_ShadeAlpha = _SecondShadeVisible;
channelOutAlpha =
lerp(Set_BaseColorAlpha, lerp(Set_1st_ShadeAlpha, Set_2nd_ShadeAlpha, Set_ShadeShadowMask), Set_FinalShadowMask);
#endif
//v.2.0.6: Add HighColor if _Is_Filter_HiCutPointLightColor is False
float4 _Set_HighColorMask_var = tex2D(_Set_HighColorMask, TRANSFORM_TEX(Set_UV0, _Set_HighColorMask));
@@ -224,22 +230,25 @@ void UTS_OtherLights(LightLoopContext lightLoopContext, FragInputs input, UTSLig
//Specular Term
float3 specularTerm = 0;
#ifndef _PBR_Mode_OFF
if(lightType == GPULIGHTTYPE_RECTANGLE || lightType == GPULIGHTTYPE_TUBE)
{
specularTerm = preLightData.specularFGD * Set_LightColor * utsLightData.specularDimmer;
specularTerm = preLightData.specularFGD * Set_LightColor;
#ifdef _PBR_Mode_TOON
specularTerm = StepFeatherToon(specularTerm, _ToonSpecularStep, _ToonSpecularFeather);
#endif
}
else
{
specularTerm = ComputeSpecularTerm(V, lightDirection, bsdfData) * Set_LightColor * utsLightData.specularDimmer;
specularTerm = ComputeSpecularTerm(V, lightDirection, bsdfData) * Set_LightColor;
}
#endif
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
}

View File

@@ -0,0 +1,165 @@
#ifndef UTS_AREA_LIGHT_INLCUDE
#define UTS_AREA_LIGHT_INLCUDE
// The output is *not* normalized by the factor of 1/TWO_PI (this is done by the PolygonFormFactor function).
real3 UTS_ComputeEdgeFactor(real3 V1, real3 V2)
{
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 UTS_PolygonFormFactor(real4x3 L, real3 L4, uint n, bool isDiffuse)
{
// 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 = UTS_ComputeEdgeFactor(L[0], L[1]);
F += UTS_ComputeEdgeFactor(L[1], L[2]);
F += UTS_ComputeEdgeFactor(L[2], L[3]);
if (n >= 4)
F += UTS_ComputeEdgeFactor(L[3], L4);
if (n == 5)
F += UTS_ComputeEdgeFactor(L4, L[0]);
return lerp(INV_TWO_PI * F, PI * F, isDiffuse); // The output may be projected onto the tangent plane (F.z) to yield signed irradiance.
}
// See "Real-Time Area Lighting: a Journey from Research to Production", slide 102.
// Turns out, despite the authors claiming that this function "calculates an approximation of
// the clipped sphere form factor", that is simply not true.
// First of all, above horizon, the function should then just return 'F.z', which it does not.
// Secondly, if we use the correct function called DiffuseSphereLightIrradiance(), it results
// in severe light leaking if the light is placed vertically behind the camera.
// So this function is clearly a hack designed to work around these problems.
real UTS_PolygonIrradianceFromVectorFormFactor(float3 F)
{
float l = length(F);
return max(0, (l * l) / (l + 1));
}
// Expects non-normalized vertex positions.
// Output: F is the signed vector irradiance.
real UTS_PolygonIrradiance(real4x3 L, bool isDiffuse, out real3 F)
{
//APPROXIMATE_POLY_LIGHT_AS_SPHERE_LIGHT
F = UTS_PolygonFormFactor(L, float3(0,0,1), 4, isDiffuse);
return UTS_PolygonIrradianceFromVectorFormFactor(F); // Accounts for the horizon.
}
float4 UTS_EvaluateLTC_Area(bool isRectLight, float3 center, float3 right, float3 up, float halfLength, float halfHeight,
float3x3 invM, float perceptualRoughness, bool isDiffuse, int cookieMode, float4 cookieScaleOffset)
{
float3 ortho = cross(center, right);
float orthoSq = dot(ortho, ortho);
// Check whether the light is in a vertical orientation.
bool quit = (orthoSq == 0);
// Check whether the light is entirely below the surface.
// We must test twice, since a linear transformation
// may bring the light above the surface (a side-effect).
quit = quit || (center.z + halfLength * abs(right.z) + halfHeight * abs(up.z) <= 0);
float4 ltcValue = float4(1, 1, 1, 0);
if (quit && !isDiffuse)
{
return ltcValue;
}
// Perform a sparse matrix multiplication.
float3 C = mul(invM, center);
float3 A = mul(invM, right);
float3 B = mul(invM, up);
// Check whether the light is entirely below the surface.
// We must test twice, since a linear transformation
// may bring the light below the surface (as expected).
if (C.z + halfLength * abs(A.z) + halfHeight * abs(B.z) <= 0 && !isDiffuse)
{
return ltcValue;
}
if (isRectLight)
{
float4x3 lightVerts;
lightVerts[0] = C - halfLength * A - halfHeight * B; // LL
lightVerts[1] = lightVerts[0] + (2 * halfHeight) * B; // UL
lightVerts[2] = lightVerts[1] + (2 * halfLength) * A; // UR
lightVerts[3] = lightVerts[2] - (2 * halfHeight) * B; // LR
float3 formFactor;
// Polygon irradiance in the transformed configuration.
ltcValue.a = UTS_PolygonIrradiance(lightVerts, isDiffuse, formFactor);
if (cookieMode != COOKIEMODE_NONE)
{
ltcValue.rgb = SampleAreaLightCookie(cookieScaleOffset, lightVerts, formFactor, perceptualRoughness);
}
}
else // Line light
{
float w = ComputeLineWidthFactor(invM, ortho, orthoSq);
ltcValue.a = I_diffuse_line(C, A, halfLength) * w;
}
return ltcValue;
}
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: afada69a218dd594ea0f17e7c639c533
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,3 +1,6 @@
#ifndef UTS_ENV
#define UTS_ENV
// _preIntegratedFGD and _CubemapLD are unique for each BRDF
IndirectLighting EvaluateBSDF_Env(LightLoopContext lightLoopContext,
float3 V, PositionInputs posInput,
@@ -127,7 +130,7 @@ float3 ComputeFresnelLerp(float3 c0, float3 c1, float cosA)
return lerp(c0, c1, t);
}
float3 ComputeIndirectDiffuse(PositionInputs posInput, BSDFData bsdfData, float3 V)
float3 EvaluateIndirectDiffuse(PositionInputs posInput, BSDFData bsdfData, float3 V)
{
float3 indirectDiffuse = 0.0;
@@ -184,7 +187,7 @@ float3 ComputeIndirectDiffuse(PositionInputs posInput, BSDFData bsdfData, float3
return indirectDiffuse;
}
float3 ComputeIndirectSpecular(LightLoopContext lightLoopContext, PositionInputs posInput, PreLightData preLightData, BSDFData bsdfData, SurfaceData surfaceData, BuiltinData builtinData, float3 V)
float3 EvaluateIndirectSpecular(LightLoopContext lightLoopContext, PositionInputs posInput, PreLightData preLightData, BSDFData bsdfData, SurfaceData surfaceData, BuiltinData builtinData, float3 V)
{
#if defined(_PBR_Mode_OFF) || defined(_PBR_Mode_TOON)
return 0;
@@ -235,3 +238,5 @@ float3 ComputeIndirectSpecular(LightLoopContext lightLoopContext, PositionInputs
return indirectSpecular;
#endif
}
#endif

View File

@@ -1,9 +1,12 @@
#ifndef UTS_PBR
#define UTS_PBR
#define ColorSpaceDielectricSpec half4(0.22, 0.22, 0.22, 0.779)
float3 schlick(float f0, float hl) {
real x = 1.0 - hl;
real x2 = x * x;
real x5 = x * x2 * x2;
float x = 1.0 - hl;
float x2 = x * x;
float x5 = x * x2 * x2;
return (1.0 - f0) * x5 + f0;
}
@@ -187,3 +190,4 @@ half3 FitWithCurveApprox(half NdotL, half Curvature)
}
#endif
#endif