Shader code cleanup;

Added punctual light evaluation in light loop;
This commit is contained in:
Misaki
2025-01-27 17:54:19 +09:00
parent fac66d8694
commit 1a82022a6f
9 changed files with 278 additions and 83 deletions

View File

@@ -9,7 +9,9 @@
#define SATURATE_BASE_COLOR_IF_SDR(x) saturate(x)
#endif
#define APPLY_WEIGHT(x, y, t) lerp(x, x * y, t)
const float rateR = 0.299;
const float rateG = 0.587;
const float rateB = 0.114;
struct UTSLightData
{
@@ -22,7 +24,7 @@ struct UTSLightData
SHADOW_TYPE shadowValue;
};
float GetLightAttenuation(float3 lightColor)
float GetColorAttenuation(float3 lightColor)
{
float lightAttenuation = rateR * lightColor.r + rateG * lightColor.g + rateB * lightColor.b;
return lightAttenuation;
@@ -36,41 +38,58 @@ float3 GetLimitedLightColor(float3 lightColor)
return result;
}
DirectLighting UtsEvaluateShading_Directional(LightLoopContext lightLoopContext, PositionInputs posInput, BuiltinData builtinData, DirectionalLightData lightData, UtsBSDFData bsdfData, PreLightData preLightData, float3 V)
DirectLighting UtsEvaluateBSDF_Directional(LightLoopContext lightLoopContext, PositionInputs posInput, BuiltinData builtinData, DirectionalLightData lightData, UtsBSDFData bsdfData, PreLightData preLightData, float3 V, float2 uv0)
{
DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
float3 L = -lightData.forward;
float NdotL = dot(bsdfData.normalWS, L);
float halfLambert = 0.5 * NdotL + 0.5;
SHADOW_TYPE shadow = EvaluateShadow_Directional(lightLoopContext, posInput, lightData, builtinData, bsdfData.normalWS);
float systemShadows = saturate(shadow + 0.5f + _Tweak_SystemShadowsLevel > 0.0 ? shadow + 0.5f + _Tweak_SystemShadowsLevel : 0.0);
float shadingGrade = lerp(halfLambert, halfLambert * systemShadows, _Set_SystemShadowsToBase);
float firstColorFeatherForMask = lerp(_1st_ShadeColor_Feather, 0.0f, max(_ComposerMaskMode, _FirstShadeOverridden));
SHADOW_TYPE shadow = EvaluateShadow_Directional(lightLoopContext, posInput, lightData, builtinData, bsdfData.geomNormalWS);
float finalShadow = saturate((shadingGrade - (_1st_ShadeColor_Step - firstColorFeatherForMask)) / (_1st_ShadeColor_Step - (_1st_ShadeColor_Step - firstColorFeatherForMask))); // Base and 1st Shade Mask
if (lightData.diffuseDimmer > 0.0 && finalShadow > 0.0)
if (lightData.lightDimmer > 0.0)
{
float secondColorFeatherForMask = lerp(_2nd_ShadeColor_Feather, 0.0f, max(_SecondShadeOverridden, _ComposerMaskMode));
float shadeShadow = saturate((halfLambert - (_ShadeColor_Step - secondColorFeatherForMask)) / (_ShadeColor_Step - (_ShadeColor_Step - secondColorFeatherForMask))); // 1st and 2nd Shades Mask
float3 diffuseTerm = lerp(lerp(bsdfData.secondShadingDiffuseColor, bsdfData.firstShadingDiffuseColor, shadeShadow), bsdfData.diffuseColor, finalShadow);
float3 specularTerm = ComputeSpecularTerm(bsdfData, preLightData, V, L) * finalShadow;
// TODO: Colored shadow will overwrite the first and second shading diffuse color
//float3 shadowColor = ComputeShadowColor(shadow, lightData.shadowTint, lightData.penumbraTint);
float4 lightColor = EvaluateLight_Directional(lightLoopContext, posInput, lightData);
lightColor.rgb *= ComputeShadowColor(systemShadows, lightData.shadowTint, lightData.penumbraTint) * lightColor.a * _Light_Intensity_Multiplier;
lightColor.rgb = GetLimitedLightColor(lightColor.rgb);
lightColor.rgb = GetLimitedLightColor(lightColor.rgb * lightColor.a * _Light_Intensity_Multiplier);
lighting.diffuse = diffuseTerm * lightColor.rgb * lightData.diffuseDimmer;
lighting.specular += specularTerm * lightColor.rgb * lightData.specularDimmer;
UtsClampRoughness(preLightData, bsdfData, lightData.minRoughness);
lighting = UtsShadeSurface(bsdfData, preLightData, shadow, lightColor.rgb, V, L, uv0, lightData.diffuseDimmer, lightData.specularDimmer);
}
return lighting;
}
DirectLighting UtsEvaluateBSDF_Punctual(LightLoopContext lightLoopContext, PositionInputs posInput, BuiltinData builtinData, LightData lightData, UtsBSDFData bsdfData, PreLightData preLightData, float3 V, float2 uv0)
{
DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
float3 L;
float4 distances; // {d, d^2, 1/d, d_proj}
GetPunctualLightVectors(posInput.positionWS, lightData, L, distances);
PositionInputs shadowPositionInputs = posInput;
shadowPositionInputs.positionWS = posInput.positionWS + L * _ShadowBias;
SHADOW_TYPE shadow = EvaluateShadow_Punctual(lightLoopContext, shadowPositionInputs, lightData, builtinData, bsdfData.geomNormalWS, L, distances);
if (lightData.lightDimmer > 0.0)
{
// TODO: Colored shadow will overwrite the first and second shading diffuse color
//float3 shadowColor = ComputeShadowColor(shadow, lightData.shadowTint, lightData.penumbraTint);
float4 lightColor = EvaluateLight_Punctual(lightLoopContext, posInput, lightData, L, distances);
lightColor.rgb = GetLimitedLightColor(lightColor.rgb * lightColor.a * _Light_Intensity_Multiplier);
UtsClampRoughness(preLightData, bsdfData, lightData.minRoughness);
lighting = UtsShadeSurface(bsdfData, preLightData, shadow, lightColor.rgb, V, L, uv0, lightData.diffuseDimmer, lightData.specularDimmer);
}
return lighting;
}
IndirectLighting UtsEvaluateBSDF_ScreenSpaceReflection(PositionInputs posInput, PreLightData preLightData, inout float reflectionHierarchyWeight)
{
IndirectLighting lighting;

View File

@@ -4,9 +4,8 @@
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Macros.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/PhysicalCamera.hlsl"
#include "Packages/com.misaki.hdrp-toon/Runtime/HDRP/Shaders/Includes/Common/UtsPBR.hlsl"
#include "Packages/com.misaki.hdrp-toon/Runtime/HDRP/Shaders/Includes/Common/UtsMaterialEvaluation.hlsl"
#include "Packages/com.misaki.hdrp-toon/Runtime/HDRP/Shaders/Includes/Lighting/UtsLightEvaluation.hlsl"
#include "Packages/com.misaki.hdrp-toon/Runtime/HDRP/Shaders/Includes/Lighting/UtsEnvLight.hlsl"
// Channel mask enum.
// this must be same to UI cs code
@@ -49,7 +48,7 @@ int GetUtsMainLightIndex(BuiltinData builtinData)
if (IsMatchingLightLayer(_DirectionalLightDatas[i].lightLayers, builtinData.renderingLayers))
{
float3 currentLightColor = _DirectionalLightDatas[i].color;
float currentLightAttenuation = GetLightAttenuation(currentLightColor);
float currentLightAttenuation = GetColorAttenuation(currentLightColor);
if (mainLightIndex == -1 || (currentLightAttenuation > lightAttenuation))
{
@@ -82,11 +81,6 @@ bool UtsUseScreenSpaceShadow(DirectionalLightData light, float3 normalWS)
void UtsLightLoop(FragInputs fragInputs, PositionInputs posInput, UtsBSDFData bsdfData, BuiltinData builtinData,
float3 V, uint featureFlags, out LightLoopOutput lightLoopOutput)
{
AggregateLighting aggregateLighting;
ZERO_INITIALIZE(AggregateLighting, aggregateLighting);
PreLightData preLightData = GetPreLightData_UTS(V, posInput, bsdfData);
LightLoopContext context;
context.shadowContext = InitShadowContext();
context.shadowValue = 1;
@@ -106,13 +100,13 @@ void UtsLightLoop(FragInputs fragInputs, PositionInputs posInput, UtsBSDFData bs
{
DirectionalLightData light = _DirectionalLightDatas[_DirectionalShadowIndex];
#if defined(SCREEN_SPACE_SHADOWS_ON) && !defined(_SURFACE_TYPE_TRANSPARENT)
#if defined(SCREEN_SPACE_SHADOWS_ON) && !defined(_SURFACE_TYPE_TRANSPARENT)
if (UseScreenSpaceShadow(light, bsdfData.normalWS))
{
context.shadowValue = GetScreenSpaceColorShadow(posInput, light.screenSpaceShadowIndex).SHADOW_TYPE_SWIZZLE;
}
else
#endif
#endif
{
float3 L = -light.forward;
@@ -128,6 +122,81 @@ void UtsLightLoop(FragInputs fragInputs, PositionInputs posInput, UtsBSDFData bs
}
}
PreLightData preLightData = GetPreLightData_UTS(V, posInput, bsdfData);
AggregateLighting aggregateLighting;
ZERO_INITIALIZE(AggregateLighting, aggregateLighting);
// Evaluate the punctual lights.
if (featureFlags & LIGHTFEATUREFLAGS_PUNCTUAL)
{
uint lightCount, lightStart;
#ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
GetCountAndStart(posInput, LIGHTCATEGORY_PUNCTUAL, lightStart, lightCount);
#else // LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
lightCount = _PunctualLightCount;
lightStart = 0;
#endif
bool fastPath = false;
#if SCALARIZE_LIGHT_LOOP
uint lightStartLane0;
fastPath = IsFastPath(lightStart, lightStartLane0);
if (fastPath)
{
lightStart = lightStartLane0;
}
#endif
// Scalarized loop. All lights that are in a tile/cluster touched by any pixel in the wave are loaded (scalar load), only the one relevant to current thread/pixel are processed.
// For clarity, the following code will follow the convention: variables starting with s_ are meant to be wave uniform (meant for scalar register),
// v_ are variables that might have different value for each thread in the wave (meant for vector registers).
// This will perform more loads than it is supposed to, however, the benefits should offset the downside, especially given that light data accessed should be largely coherent.
// Note that the above is valid only if wave intriniscs are supported.
uint v_lightListOffset = 0;
uint v_lightIdx = lightStart;
#if NEED_TO_CHECK_HELPER_LANE
// On some platform helper lanes don't behave as we'd expect, therefore we prevent them from entering the loop altogether.
// IMPORTANT! This has implications if ddx/ddy is used on results derived from lighting, however given Lightloop is called in compute we should be
// sure it will not happen.
bool isHelperLane = WaveIsHelperLane();
while (!isHelperLane && v_lightListOffset < lightCount)
#else
while (v_lightListOffset < lightCount)
#endif
{
v_lightIdx = FetchIndex(lightStart, v_lightListOffset);
#if SCALARIZE_LIGHT_LOOP
uint s_lightIdx = ScalarizeElementIndex(v_lightIdx, fastPath);
#else
uint s_lightIdx = v_lightIdx;
#endif
if (s_lightIdx == -1)
{
break;
}
LightData s_lightData = FetchLight(s_lightIdx);
// If current scalar and vector light index match, we process the light. The v_lightListOffset for current thread is increased.
// Note that the following should really be ==, however, since helper lanes are not considered by WaveActiveMin, such helper lanes could
// end up with a unique v_lightIdx value that is smaller than s_lightIdx hence being stuck in a loop. All the active lanes will not have this problem.
if (s_lightIdx >= v_lightIdx)
{
v_lightListOffset++;
if (IsMatchingLightLayer(s_lightData.lightLayers, builtinData.renderingLayers))
{
DirectLighting lighting = UtsEvaluateBSDF_Punctual(context, posInput, builtinData, s_lightData, bsdfData, preLightData, V, fragInputs.texCoord0.xy);
AccumulateDirectLighting(lighting, aggregateLighting);
}
}
}
}
// Evaluate the directional lights.
if (featureFlags & LIGHTFEATUREFLAGS_DIRECTIONAL)
{
uint i = 0; // Declare once to avoid the D3D11 compiler warning.
@@ -135,12 +204,13 @@ void UtsLightLoop(FragInputs fragInputs, PositionInputs posInput, UtsBSDFData bs
{
if (IsMatchingLightLayer(_DirectionalLightDatas[i].lightLayers, builtinData.renderingLayers))
{
DirectLighting direct = UtsEvaluateShading_Directional(context, posInput, builtinData, _DirectionalLightDatas[i], bsdfData, preLightData, V);
DirectLighting direct = UtsEvaluateBSDF_Directional(context, posInput, builtinData, _DirectionalLightDatas[i], bsdfData, preLightData, V, fragInputs.texCoord0.xy);
AccumulateDirectLighting(direct, aggregateLighting);
}
}
}
// Evaluate the environment lights.
if (featureFlags & (LIGHTFEATUREFLAGS_ENV | LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_SSREFRACTION | LIGHTFEATUREFLAGS_SSREFLECTION))
{
float reflectionHierarchyWeight = 0.0; // Max: 1.0
@@ -148,18 +218,18 @@ void UtsLightLoop(FragInputs fragInputs, PositionInputs posInput, UtsBSDFData bs
uint envLightStart, envLightCount;
// Fetch first env light to provide the scene proxy for screen space computation
#ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
#ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
GetCountAndStart(posInput, LIGHTCATEGORY_ENV, envLightStart, envLightCount);
#else // LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
#else
envLightCount = _EnvLightCount;
envLightStart = 0;
#endif
#endif
bool fastPath = false;
#if SCALARIZE_LIGHT_LOOP
uint envStartFirstLane;
fastPath = IsFastPath(envLightStart, envStartFirstLane);
#endif
#if SCALARIZE_LIGHT_LOOP
uint envStartFirstLane;
fastPath = IsFastPath(envLightStart, envStartFirstLane);
#endif
// Reflection hierarchy is
// 1. Screen Space Reflection