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

@@ -23,12 +23,12 @@ namespace Misaki.HdrpToon.Editor
private static class Styles private static class Styles
{ {
public readonly static GUIContent transparentModeText = new("Transparent Mode", "Enable different modes that allow the simulation of a variety of transparent objects."); public static readonly GUIContent transparentModeText = new("Transparent Mode", "Enable different modes that allow the simulation of a variety of transparent objects.");
public readonly static GUIContent alphaClipEnableText = new("Alpha Clipping", "Enable alpha clipping."); public static readonly GUIContent alphaClipEnableText = new("Alpha Clipping", "Enable alpha clipping.");
public readonly static GUIContent alphaClipText = new("Alpha Clipping Threshold", "Threshold for alpha clipping."); public static readonly GUIContent alphaClipText = new("Alpha Clipping Threshold", "Threshold for alpha clipping.");
public readonly static GUIContent cullingModeText = new("Culling Mode", "Controls the sides of polygons that should not be drawn (culled)."); public static readonly GUIContent cullingModeText = new("Culling Mode", "Controls the sides of polygons that should not be drawn (culled).");
public static readonly GUIContent materialTypeText = new("Material Type", "Specifies the material type."); public static readonly GUIContent materialTypeText = new("Material Type", "Specifies the material type.");
public static readonly GUIContent pbrModeText = new("PBR Mode", "Specifies PBR model mode."); public static readonly GUIContent pbrModeText = new("PBR Mode", "Specifies PBR model mode.");

View File

@@ -265,6 +265,7 @@ Shader "HDRP/Toon"
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Surface Options // Surface Options
[Enum(Off, 0, On, 1)] _TransparentEnabled("Transparent Mode", int) = 0 [Enum(Off, 0, On, 1)] _TransparentEnabled("Transparent Mode", int) = 0
[ToggleUI] _AlphaCutoffEnable("Alpha Cutoff Enable", Float) = 0.0 [ToggleUI] _AlphaCutoffEnable("Alpha Cutoff Enable", Float) = 0.0
_AlphaCutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5 _AlphaCutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
@@ -328,7 +329,7 @@ Shader "HDRP/Toon"
_BumpScale("Normal Scale", Range(0, 1)) = 1 _BumpScale("Normal Scale", Range(0, 1)) = 1
[Toggle(_)] _Is_NormalMapToBase("Is_NormalMapToBase", Float) = 0 [Toggle(_)] _Is_NormalMapToBase("Is_NormalMapToBase", Float) = 0
//v.2.0.4.4 //v.2.0.4.4
[KeywordEnum(NORMAL, SDF)] _Shadow_Mode("Shadow MODE", Float) = 0 [KeywordEnum(NORMAL, SDF)] _Shadow_Mode("Shadow Mode", Float) = 0
_SDFShadowTex("SDFShadowTex", 2D) = "white" {} _SDFShadowTex("SDFShadowTex", 2D) = "white" {}
_SDFSmoothGamma("SDFSmoothGamma", Range(0.0, 0.1)) = 0.02 _SDFSmoothGamma("SDFSmoothGamma", Range(0.0, 0.1)) = 0.02
_SDFShadowLevel("SDFShadowLevel", Range(0.0, 1.0)) = 0.25 _SDFShadowLevel("SDFShadowLevel", Range(0.0, 1.0)) = 0.25
@@ -523,7 +524,10 @@ Shader "HDRP/Toon"
[Toggle(_)] _ComposerMaskMode("", Float) = 0 [Toggle(_)] _ComposerMaskMode("", Float) = 0
[Enum(None, 0, BaseColor, 1, FirstShade, 2, SecondShade,3, Highlight, 4, AngelRing, 5, RimLight, 6)] _ClippingMatteMode("Clipping Matte Mode", int) = 0 [Enum(None, 0, BaseColor, 1, FirstShade, 2, SecondShade,3, Highlight, 4, AngelRing, 5, RimLight, 6)] _ClippingMatteMode("Clipping Matte Mode", int) = 0
[HideInInspector] emissive("to avoid srp batcher error", Color)= (0, 0, 0, 1) // [HideInInspector] emissive("to avoid srp batcher error", Color)= (0, 0, 0, 1)
[KeywordEnum(NONE, SINGLE, FULL)] _Light_Loop_Mode ("Light Loop Mode", Float) = 2
//
// to here parameters for UTS> // to here parameters for UTS>
} }
@@ -982,12 +986,6 @@ Shader "HDRP/Toon"
#pragma multi_compile DECALS_OFF DECALS_3RT DECALS_4RT #pragma multi_compile DECALS_OFF DECALS_3RT DECALS_4RT
#pragma multi_compile SCREEN_SPACE_SHADOWS_OFF SCREEN_SPACE_SHADOWS_ON #pragma multi_compile SCREEN_SPACE_SHADOWS_OFF SCREEN_SPACE_SHADOWS_ON
#pragma multi_compile_fragment _MATERIAL_TYPE_STANDARD _MATERIAL_TYPE_FRONTHAIR _MATERIAL_TYPE_FACE _MATERIAL_TYPE_EYE
#pragma multi_compile_fragment _PBR_MODE_OFF _PBR_MODE_STANDARD _PBR_MODE_ANISOTROPY _PBR_MODE_HAIR _PBR_MODE_TOON
#pragma multi_compile_fragment _INDIRECT_DIFFUSE_OFF _INDIRECT_DIFFUSE_IBL _INDIRECT_DIFFUSE_MATCAP _INDIRECT_DIFFUSE_RAMP
#pragma multi_compile_fragment _INDIRECT_SPECULAR_OFF _INDIRECT_SPECULAR_IBL _INDIRECT_SPECULAR_MATCAP
#pragma multi_compile_fragment USE_FPTL_LIGHTLIST USE_CLUSTERED_LIGHTLIST #pragma multi_compile_fragment USE_FPTL_LIGHTLIST USE_CLUSTERED_LIGHTLIST
#define SHADERPASS SHADERPASS_FORWARD #define SHADERPASS SHADERPASS_FORWARD
// In case of opaque we don't want to perform the alpha test, it is done in depth prepass and we use depth equal for ztest (setup from UI) // In case of opaque we don't want to perform the alpha test, it is done in depth prepass and we use depth equal for ztest (setup from UI)
@@ -1011,12 +1009,19 @@ Shader "HDRP/Toon"
#pragma shader_feature ENABLE_UTS_HAIR_SHAOW #pragma shader_feature ENABLE_UTS_HAIR_SHAOW
#pragma shader_feature ENABLE_UTS_HAIR_BLENDING #pragma shader_feature ENABLE_UTS_HAIR_BLENDING
#pragma shader_feature_local_fragment _SHADOW_MODE_NORMAL _SHADOW_MODE_SDF
#pragma shader_feature_local_fragment _MATERIAL_TYPE_STANDARD _MATERIAL_TYPE_FRONTHAIR _MATERIAL_TYPE_FACE _MATERIAL_TYPE_EYE
#pragma shader_feature_local_fragment _PBR_MODE_OFF _PBR_MODE_STANDARD _PBR_MODE_ANISOTROPY _PBR_MODE_HAIR _PBR_MODE_TOON
#pragma shader_feature_local_fragment _INDIRECT_DIFFUSE_OFF _INDIRECT_DIFFUSE_IBL _INDIRECT_DIFFUSE_MATCAP _INDIRECT_DIFFUSE_RAMP
#pragma shader_feature_local_fragment _INDIRECT_SPECULAR_OFF _INDIRECT_SPECULAR_IBL _INDIRECT_SPECULAR_MATCAP
#pragma shader_feature_local_fragment _MASKMAP #pragma shader_feature_local_fragment _MASKMAP
#pragma shader_feature_local_fragment _NORMALMAP #pragma shader_feature_local_fragment _NORMALMAP
#pragma shader_feature_local_fragment _ANISOTROPYMAP #pragma shader_feature_local_fragment _ANISOTROPYMAP
#pragma shader_feature_local_fragment _SPECULARCOLORMAP #pragma shader_feature_local_fragment _SPECULARCOLORMAP
#pragma shader_feature_local_fragment _SDFShadow
#pragma shader_feature_local_fragment _RECEIVE_HAIR_SHADOW_ON #pragma shader_feature_local_fragment _RECEIVE_HAIR_SHADOW_ON
#define PUNCTUAL_SHADOW_MEDIUM #define PUNCTUAL_SHADOW_MEDIUM

View File

@@ -5,6 +5,8 @@
#define inverselerp(a, b, x) saturate(((x) - (a)) / ((b) - (a))) #define inverselerp(a, b, x) saturate(((x) - (a)) / ((b) - (a)))
#define APPLY_WEIGHT(x, y, t) lerp(x, x * y, t)
float2 GetWHRatio() float2 GetWHRatio()
{ {
return float2(_ScreenParams.y / _ScreenParams.x, 1); return float2(_ScreenParams.y / _ScreenParams.x, 1);

View File

@@ -28,11 +28,6 @@
struct UTSData struct UTSData
{ {
float3 viewDirection;
float3 normalDirection;
fixed cameraDir;
float cameraRoll;
fixed signMirror;
}; };
struct UTSSurfaceData struct UTSSurfaceData
@@ -54,8 +49,7 @@ struct UTSSurfaceData
float3 geomNormalWS; float3 geomNormalWS;
float3 tangentWS; float3 tangentWS;
real3 subsurfaceColor; real4 subsurfaceColor;
real subsurfaceMask;
real anisotropy; real anisotropy;
}; };
@@ -104,8 +98,8 @@ UTSSurfaceData ConvertSurfaceDataToUTSSurfaceData(SurfaceData surfaceData)
output.specularColor = surfaceData.specularColor; output.specularColor = surfaceData.specularColor;
output.geomNormalWS = surfaceData.geomNormalWS; output.geomNormalWS = surfaceData.geomNormalWS;
output.tangentWS = surfaceData.tangentWS; output.tangentWS = surfaceData.tangentWS;
output.subsurfaceColor = surfaceData.transmittanceColor; output.subsurfaceColor.rgb = surfaceData.transmittanceColor;
output.subsurfaceMask = surfaceData.subsurfaceMask; output.subsurfaceColor.a = surfaceData.subsurfaceMask;
output.anisotropy = surfaceData.anisotropy; output.anisotropy = surfaceData.anisotropy;
return output; return output;
@@ -124,8 +118,8 @@ UTSSurfaceData GetUTSSurfaceData(FragInputs input, float3 V, float2 UV)
float4 firstShadingTexture = SAMPLE_TEXTURE2D(_1st_ShadeMap, sampler_BaseColorMap, TRANSFORM_TEX(UV, _BaseColorMap)); float4 firstShadingTexture = SAMPLE_TEXTURE2D(_1st_ShadeMap, sampler_BaseColorMap, TRANSFORM_TEX(UV, _BaseColorMap));
float4 secondShadingTexture = SAMPLE_TEXTURE2D(_1st_ShadeMap, sampler_BaseColorMap, TRANSFORM_TEX(UV, _BaseColorMap)); float4 secondShadingTexture = SAMPLE_TEXTURE2D(_1st_ShadeMap, sampler_BaseColorMap, TRANSFORM_TEX(UV, _BaseColorMap));
output.firstShadingColor = lerp(firstShadingTexture.rgb, mainTexture.rgb, _Use_BaseAs1st) * _1st_ShadeColor; output.firstShadingColor = lerp(firstShadingTexture.rgb, mainTexture.rgb, _Use_BaseAs1st) * _1st_ShadeColor.rgb;
output.secondShadingColor = lerp(secondShadingTexture.rgb, output.firstShadingColor, _Use_1stAs2nd) * _2nd_ShadeColor; output.secondShadingColor = lerp(secondShadingTexture.rgb, output.firstShadingColor, _Use_1stAs2nd) * _2nd_ShadeColor.rgb;
float4 normalLocal = 0; float4 normalLocal = 0;
if (_Use_SSSLut) if (_Use_SSSLut)
@@ -138,8 +132,13 @@ UTSSurfaceData GetUTSSurfaceData(FragInputs input, float3 V, float2 UV)
} }
normalLocal.rgb = UnpackNormalScale(normalLocal, _NormalScale); normalLocal.rgb = UnpackNormalScale(normalLocal, _NormalScale);
float3 normalWS = normalize(mul(normalLocal.rgb, input.tangentToWorld)); float3 normalWS = normalize(mul(normalLocal.rgb, input.tangentToWorld));
#if _PBR_MODE_OFF
float smoothness = 0.0;
float metallic = 0.0;
#else
float smoothness = _Smoothness; float smoothness = _Smoothness;
float metallic = _Metallic; float metallic = _Metallic;
#endif
float ao = 1.0; float ao = 1.0;
float3 specularColor = 1; float3 specularColor = 1;
float anisotropy = 0; float anisotropy = 0;
@@ -189,7 +188,6 @@ UTSSurfaceData GetUTSSurfaceData(FragInputs input, float3 V, float2 UV)
output.tangentWS = Orthonormalize(input.tangentToWorld[0].rgb, normalWS); output.tangentWS = Orthonormalize(input.tangentToWorld[0].rgb, normalWS);
output.subsurfaceColor = SAMPLE_TEXTURE2D(_SSSLutMap, sampler_MainTex, TRANSFORM_TEX(UV, _BaseColorMap)) * _SSSIntensity; output.subsurfaceColor = SAMPLE_TEXTURE2D(_SSSLutMap, sampler_MainTex, TRANSFORM_TEX(UV, _BaseColorMap)) * _SSSIntensity;
output.subsurfaceMask = 1.0;
output.anisotropy = anisotropy; output.anisotropy = anisotropy;
@@ -216,13 +214,9 @@ UtsBSDFData ConvertUTSSurfaceDataToUTSBSDFData(UTSSurfaceData surfaceData)
output.ambientOcclusion = surfaceData.ambientOcclusion; output.ambientOcclusion = surfaceData.ambientOcclusion;
output.specularOcclusion = surfaceData.specularOcclusion; output.specularOcclusion = surfaceData.specularOcclusion;
#if _PBR_MODE_OFF
output.perceptualRoughness = 0.0;
#else
output.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness); output.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness);
#endif
output.subsurfaceColor = surfaceData.subsurfaceColor * surfaceData.subsurfaceMask; output.subsurfaceColor = surfaceData.subsurfaceColor.rgb * surfaceData.subsurfaceColor.a;
output.normalWS = surfaceData.normalWS; output.normalWS = surfaceData.normalWS;
output.geomNormalWS = surfaceData.geomNormalWS; output.geomNormalWS = surfaceData.geomNormalWS;
@@ -230,8 +224,7 @@ UtsBSDFData ConvertUTSSurfaceDataToUTSBSDFData(UTSSurfaceData surfaceData)
output.bitangentWS = normalize(cross(surfaceData.normalWS, surfaceData.tangentWS)); output.bitangentWS = normalize(cross(surfaceData.normalWS, surfaceData.tangentWS));
output.anisotropy = surfaceData.anisotropy; output.anisotropy = surfaceData.anisotropy;
output.roughnessT = output.perceptualRoughness * 0.5; ConvertAnisotropyToRoughness(output.perceptualRoughness, surfaceData.anisotropy, output.roughnessT, output.roughnessB);
output.roughnessB = output.perceptualRoughness * 2.0;
return output; return output;
} }
@@ -312,6 +305,12 @@ PreLightData GetPreLightData_UTS(float3 V, PositionInputs posInput, inout UtsBSD
return preLightData; return preLightData;
} }
void UtsClampRoughness(inout PreLightData preLightData, inout UtsBSDFData bsdfData, float minRoughness)
{
bsdfData.roughnessT = max(minRoughness, bsdfData.roughnessT);
bsdfData.roughnessB = max(minRoughness, bsdfData.roughnessB);
}
// Legacy for compatibility with existing shaders // Legacy for compatibility with existing shaders
inline bool IsGammaSpace() inline bool IsGammaSpace()
{ {
@@ -534,10 +533,6 @@ float3 ShadeSH9 (float4 normal)
return res; return res;
} }
float rateR = 0.299;
float rateG = 0.587;
float rateB = 0.114;
float3 SampleBakedGI_UTS(float3 positionRWS, float3 normalWS, float2 uvStaticLightmap, float2 uvDynamicLightmap, bool needToIncludeAPV = false) float3 SampleBakedGI_UTS(float3 positionRWS, float3 normalWS, float2 uvStaticLightmap, float2 uvDynamicLightmap, bool needToIncludeAPV = false)
{ {
float3 bakeDiffuseLighting = float3(0, 0, 0); float3 bakeDiffuseLighting = float3(0, 0, 0);

View File

@@ -1,8 +1,14 @@
#ifndef UTS_PBR #ifndef UTS_MATERIAL_EVALUATION
#define UTS_PBR #define UTS_MATERIAL_EVALUATION
#define ColorSpaceDielectricSpec half4(0.22, 0.22, 0.22, 0.779) #define ColorSpaceDielectricSpec half4(0.22, 0.22, 0.22, 0.779)
struct UtsShadeMask
{
float baseShadeMask;
float firstShadeMask;
};
float3 GetSpecularColor(float3 albedo, float metalic) float3 GetSpecularColor(float3 albedo, float metalic)
{ {
float3 specColor = lerp(ColorSpaceDielectricSpec.rgb, albedo, metalic); float3 specColor = lerp(ColorSpaceDielectricSpec.rgb, albedo, metalic);
@@ -111,6 +117,104 @@ half3 FitWithCurveApprox(half NdotL, half Curvature)
return lerp(curve0, curve1, mad(oneMinusCurva2, -1.0 * oneMinusCurva2, 1.0)); return lerp(curve0, curve1, mad(oneMinusCurva2, -1.0 * oneMinusCurva2, 1.0));
} }
float3 SampleSDFTexture(float3 L, float2 uv, out float angle)
{
float2 right_uv = float2(1 - uv.x, uv.y);
float3 left_SDFTex = SAMPLE_TEXTURE2D(_SDFShadowTex, sampler_SDFShadowTex, uv).rgb;
float3 right_SDFTex = SAMPLE_TEXTURE2D(_SDFShadowTex, sampler_SDFShadowTex, right_uv).rgb;
float2 leftVector = normalize(mul(UNITY_MATRIX_M, float4(1, 0, 0, 0)).xz);
float2 forwardVector = normalize(mul(UNITY_MATRIX_M, float4(0, 0, 1, 0)).xz);
float2 lightDirection = normalize(L.xz);
angle = 1.0 - (dot(forwardVector, lightDirection) * 0.5 + 0.5);
bool isRightSide = dot(lightDirection, leftVector) > 0;
return isRightSide ? right_SDFTex : left_SDFTex;
}
float GetHairShadow(PositionInputs posInput, float3 L, float2 positionSS)
{
// Push the face fragment view space position towards the light for a little bit
float hairShadowOpacity = saturate(Remap(length(posInput.positionWS), float2(_HairShadowFadeOutDistance, _HairShadowFadeInDistance), float2(0, 1)));
float3 viewLightDir = TransformWorldToViewDir(L); // / posInput.deviceDepth; when linearDepth grows large, the movement amount should be lower since we are getting further from the face.
float3 cameraDirOS = normalize(TransformWorldToObject(GetCameraPositionWS()));
float shadowLengthY = _HairShadowDistance * 5.0 * max(0.5, posInput.linearDepth * _HairShadowDistanceScaleFactor) / posInput.linearDepth;
float2 shadowLength = float2(shadowLengthY * 2.0f, shadowLengthY);
float3 camDirOS = normalize(TransformWorldToObject(GetCameraPositionWS()));
float camDirFactor = 1 - smoothstep(0.1, 0.9, camDirOS.y);
shadowLength.y *= camDirFactor;
float2 samplingPoint = (positionSS + shadowLength * viewLightDir.xy * (_ScreenSize.xy / float2 (1920.0f, 1080.0f))) * _ScreenSize.zw; // Use 1080p as the reference resolution to achieve consistent shadow lengths across various screen resolutions.
// Then sample the hair buffer, to see if the fragment lands in shadow.
float2 scaledUVs = samplingPoint * _HairShadowRTHandleScale; // We have to including the scaling factor for our shadow map since we are not going to allocate new texture if the rendering resolution changed.
float hairDepth = SAMPLE_TEXTURE2D(_HairShadowTex, s_trilinear_clamp_sampler, scaledUVs).r;
float depthCorrect = posInput.deviceDepth <= hairDepth + _HairShadowDepthBias ? 1 : 0; // Hair < Face means Hair are closer to camera
// Note that we have LinearEyeDepth in the buffer. A comparison of depth is needed so that we don't project the shadow of hair behind the face.
float hairShadow = lerp(0,hairShadowOpacity,depthCorrect);
}
UtsShadeMask GetShadeMak(float3 normalWS, float3 L, SHADOW_TYPE shadow, float2 uv, out float additionalSpecular)
{
UtsShadeMask shadeMask;
ZERO_INITIALIZE(UtsShadeMask, shadeMask);
#if _SHADOW_MODE_NORMAL
float NdotL = dot(normalWS, L);
float halfLambert = 0.5 * NdotL + 0.5;
//float systemShadows = saturate(max(0.0, shadow.x + 0.5 - 0.0001 + _Tweak_SystemShadowsLevel));
//float shadingGrade = lerp(halfLambert, halfLambert * systemShadows, _Set_SystemShadowsToBase);
float firstColorFeatherForMask = lerp(_1st_ShadeColor_Feather, 0.0, max(_ComposerMaskMode, _FirstShadeOverridden));
shadeMask.baseShadeMask = saturate((halfLambert - (_1st_ShadeColor_Step - firstColorFeatherForMask)) / (_1st_ShadeColor_Step - (_1st_ShadeColor_Step - firstColorFeatherForMask)));
float secondColorFeatherForMask = lerp(_2nd_ShadeColor_Feather, 0.0, max(_SecondShadeOverridden, _ComposerMaskMode));
shadeMask.firstShadeMask = saturate((halfLambert - (_2nd_ShadeColor_Step - secondColorFeatherForMask)) / (_2nd_ShadeColor_Step - (_2nd_ShadeColor_Step - secondColorFeatherForMask)));
additionalSpecular = 0;
#elif _SHADOW_MODE_SDF
float angle;
float smoothGamma = _SDFSmoothGamma / 10.0f;
float shadowLevel = _SDFShadowLevel / 10.0f;
float3 sdfTexture = SampleSDFTexture(L, uv, angle); // r: sdf shadow, g: sdf noise highlight, b: fixed shadow
float sdfShadowMask = smoothstep(sdfTexture.r - smoothGamma, sdfTexture.r + smoothGamma, angle - shadowLevel);
shadeMask.baseShadeMask = sdfShadowMask * sdfTexture.b;
additionalSpecular = sdfTexture.g;
#endif
shadeMask.baseShadeMask = APPLY_WEIGHT(shadeMask.baseShadeMask, shadow, _Set_SystemShadowsToBase);
return shadeMask;
}
DirectLighting UtsShadeSurface(UtsBSDFData bsdfData, PreLightData preLightData, SHADOW_TYPE shadow,
float3 lightColor, float3 V, float3 L, float2 uv,
float diffuseDimmer, float specularDimmer)
{
DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
if (Max3(lightColor.r, lightColor.g, lightColor.b) > 0.0)
{
float additionalSpecular;
UtsShadeMask shadeMask = GetShadeMak(bsdfData.normalWS, L, shadow, uv, additionalSpecular);
float3 diffuseTerm = lerp(lerp(bsdfData.secondShadingDiffuseColor, bsdfData.firstShadingDiffuseColor, shadeMask.firstShadeMask), bsdfData.diffuseColor, shadeMask.baseShadeMask);
float3 specularTerm = (ComputeSpecularTerm(bsdfData, preLightData, V, L) + additionalSpecular) * shadeMask.baseShadeMask;
lighting.diffuse += diffuseTerm * lightColor * diffuseDimmer;
lighting.specular += specularTerm * lightColor * specularDimmer;
}
return lighting;
}
// Todo: SDF nose high light // Todo: SDF nose high light
// #if define(_SDFShadow) || define(_SDFNoiseHelight) // #if define(_SDFShadow) || define(_SDFNoiseHelight)
#ifdef _SDFShadow #ifdef _SDFShadow

View File

@@ -9,7 +9,9 @@
#define SATURATE_BASE_COLOR_IF_SDR(x) saturate(x) #define SATURATE_BASE_COLOR_IF_SDR(x) saturate(x)
#endif #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 struct UTSLightData
{ {
@@ -22,7 +24,7 @@ struct UTSLightData
SHADOW_TYPE shadowValue; SHADOW_TYPE shadowValue;
}; };
float GetLightAttenuation(float3 lightColor) float GetColorAttenuation(float3 lightColor)
{ {
float lightAttenuation = rateR * lightColor.r + rateG * lightColor.g + rateB * lightColor.b; float lightAttenuation = rateR * lightColor.r + rateG * lightColor.g + rateB * lightColor.b;
return lightAttenuation; return lightAttenuation;
@@ -36,36 +38,53 @@ float3 GetLimitedLightColor(float3 lightColor)
return result; 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; DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting); ZERO_INITIALIZE(DirectLighting, lighting);
float3 L = -lightData.forward; float3 L = -lightData.forward;
float NdotL = dot(bsdfData.normalWS, L); SHADOW_TYPE shadow = EvaluateShadow_Directional(lightLoopContext, posInput, lightData, builtinData, bsdfData.geomNormalWS);
float halfLambert = 0.5 * NdotL + 0.5;
SHADOW_TYPE shadow = EvaluateShadow_Directional(lightLoopContext, posInput, lightData, builtinData, bsdfData.normalWS); if (lightData.lightDimmer > 0.0)
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));
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)
{ {
float secondColorFeatherForMask = lerp(_2nd_ShadeColor_Feather, 0.0f, max(_SecondShadeOverridden, _ComposerMaskMode)); // TODO: Colored shadow will overwrite the first and second shading diffuse color
float shadeShadow = saturate((halfLambert - (_ShadeColor_Step - secondColorFeatherForMask)) / (_ShadeColor_Step - (_ShadeColor_Step - secondColorFeatherForMask))); // 1st and 2nd Shades Mask //float3 shadowColor = ComputeShadowColor(shadow, lightData.shadowTint, lightData.penumbraTint);
float3 diffuseTerm = lerp(lerp(bsdfData.secondShadingDiffuseColor, bsdfData.firstShadingDiffuseColor, shadeShadow), bsdfData.diffuseColor, finalShadow);
float3 specularTerm = ComputeSpecularTerm(bsdfData, preLightData, V, L) * finalShadow;
float4 lightColor = EvaluateLight_Directional(lightLoopContext, posInput, lightData); 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.a * _Light_Intensity_Multiplier);
lightColor.rgb = GetLimitedLightColor(lightColor.rgb);
lighting.diffuse = diffuseTerm * lightColor.rgb * lightData.diffuseDimmer; UtsClampRoughness(preLightData, bsdfData, lightData.minRoughness);
lighting.specular += specularTerm * lightColor.rgb * lightData.specularDimmer;
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; return 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/Macros.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/PhysicalCamera.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/UtsLightEvaluation.hlsl"
#include "Packages/com.misaki.hdrp-toon/Runtime/HDRP/Shaders/Includes/Lighting/UtsEnvLight.hlsl"
// Channel mask enum. // Channel mask enum.
// this must be same to UI cs code // this must be same to UI cs code
@@ -49,7 +48,7 @@ int GetUtsMainLightIndex(BuiltinData builtinData)
if (IsMatchingLightLayer(_DirectionalLightDatas[i].lightLayers, builtinData.renderingLayers)) if (IsMatchingLightLayer(_DirectionalLightDatas[i].lightLayers, builtinData.renderingLayers))
{ {
float3 currentLightColor = _DirectionalLightDatas[i].color; float3 currentLightColor = _DirectionalLightDatas[i].color;
float currentLightAttenuation = GetLightAttenuation(currentLightColor); float currentLightAttenuation = GetColorAttenuation(currentLightColor);
if (mainLightIndex == -1 || (currentLightAttenuation > lightAttenuation)) 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, void UtsLightLoop(FragInputs fragInputs, PositionInputs posInput, UtsBSDFData bsdfData, BuiltinData builtinData,
float3 V, uint featureFlags, out LightLoopOutput lightLoopOutput) float3 V, uint featureFlags, out LightLoopOutput lightLoopOutput)
{ {
AggregateLighting aggregateLighting;
ZERO_INITIALIZE(AggregateLighting, aggregateLighting);
PreLightData preLightData = GetPreLightData_UTS(V, posInput, bsdfData);
LightLoopContext context; LightLoopContext context;
context.shadowContext = InitShadowContext(); context.shadowContext = InitShadowContext();
context.shadowValue = 1; context.shadowValue = 1;
@@ -106,13 +100,13 @@ void UtsLightLoop(FragInputs fragInputs, PositionInputs posInput, UtsBSDFData bs
{ {
DirectionalLightData light = _DirectionalLightDatas[_DirectionalShadowIndex]; 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)) if (UseScreenSpaceShadow(light, bsdfData.normalWS))
{ {
context.shadowValue = GetScreenSpaceColorShadow(posInput, light.screenSpaceShadowIndex).SHADOW_TYPE_SWIZZLE; context.shadowValue = GetScreenSpaceColorShadow(posInput, light.screenSpaceShadowIndex).SHADOW_TYPE_SWIZZLE;
} }
else else
#endif #endif
{ {
float3 L = -light.forward; 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) if (featureFlags & LIGHTFEATUREFLAGS_DIRECTIONAL)
{ {
uint i = 0; // Declare once to avoid the D3D11 compiler warning. 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)) 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); AccumulateDirectLighting(direct, aggregateLighting);
} }
} }
} }
// Evaluate the environment lights.
if (featureFlags & (LIGHTFEATUREFLAGS_ENV | LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_SSREFRACTION | LIGHTFEATUREFLAGS_SSREFLECTION)) if (featureFlags & (LIGHTFEATUREFLAGS_ENV | LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_SSREFRACTION | LIGHTFEATUREFLAGS_SSREFLECTION))
{ {
float reflectionHierarchyWeight = 0.0; // Max: 1.0 float reflectionHierarchyWeight = 0.0; // Max: 1.0
@@ -148,18 +218,18 @@ void UtsLightLoop(FragInputs fragInputs, PositionInputs posInput, UtsBSDFData bs
uint envLightStart, envLightCount; uint envLightStart, envLightCount;
// Fetch first env light to provide the scene proxy for screen space computation // 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); GetCountAndStart(posInput, LIGHTCATEGORY_ENV, envLightStart, envLightCount);
#else // LIGHTLOOP_DISABLE_TILE_AND_CLUSTER #else
envLightCount = _EnvLightCount; envLightCount = _EnvLightCount;
envLightStart = 0; envLightStart = 0;
#endif #endif
bool fastPath = false; bool fastPath = false;
#if SCALARIZE_LIGHT_LOOP #if SCALARIZE_LIGHT_LOOP
uint envStartFirstLane; uint envStartFirstLane;
fastPath = IsFastPath(envLightStart, envStartFirstLane); fastPath = IsFastPath(envLightStart, envStartFirstLane);
#endif #endif
// Reflection hierarchy is // Reflection hierarchy is
// 1. Screen Space Reflection // 1. Screen Space Reflection

View File

@@ -167,7 +167,7 @@ void Frag(PackedVaryingsToPS packedInput,
SurfaceData tempSurfaceData; SurfaceData tempSurfaceData;
BuiltinData builtinData; BuiltinData builtinData;
GetSurfaceAndBuiltinData(input, V, posInput, tempSurfaceData, builtinData); GetSurfaceAndBuiltinData(input, V, posInput, tempSurfaceData, builtinData);
UTSSurfaceData surfaceData = GetUTSSurfaceData(input, V, UV0); UTSSurfaceData surfaceData = GetUTSSurfaceData(input, V, UV0.xy);
UtsBSDFData bsdfData = ConvertUTSSurfaceDataToUTSBSDFData(surfaceData); UtsBSDFData bsdfData = ConvertUTSSurfaceDataToUTSBSDFData(surfaceData);
#define UNITY_PROJ_COORD(a) a #define UNITY_PROJ_COORD(a) a
@@ -243,7 +243,7 @@ void Frag(PackedVaryingsToPS packedInput,
// We directly calculate custome main light during the light loop in upper code to avoid extra calculation // We directly calculate custome main light during the light loop in upper code to avoid extra calculation
//customMainLight = GetCustomMainLightData(builtinData, mainPunctualLight); //customMainLight = GetCustomMainLightData(builtinData, mainPunctualLight);
#if _SDFShadow || (_RECEIVE_HAIR_SHADOW_ON && ENABLE_UTS_HAIR_SHAOW) #if _SHADOW_MODE_SDF || (_RECEIVE_HAIR_SHADOW_ON && ENABLE_UTS_HAIR_SHAOW)
float3 defaultLightDirection = normalize(UNITY_MATRIX_V[2].xyz + UNITY_MATRIX_V[1].xyz); float3 defaultLightDirection = normalize(UNITY_MATRIX_V[2].xyz + UNITY_MATRIX_V[1].xyz);
float3 defaultLightColor = saturate(max(float3(0.05, 0.05, 0.05) * _Unlit_Intensity, max(ShadeSH9(float4(0.0, 0.0, 0.0, 1.0)), ShadeSH9(float4(0.0, -1.0, 0.0, 1.0)).rgb) * _Unlit_Intensity)); float3 defaultLightColor = saturate(max(float3(0.05, 0.05, 0.05) * _Unlit_Intensity, max(ShadeSH9(float4(0.0, 0.0, 0.0, 1.0)), ShadeSH9(float4(0.0, -1.0, 0.0, 1.0)).rgb) * _Unlit_Intensity));
@@ -261,7 +261,7 @@ void Frag(PackedVaryingsToPS packedInput,
float systemShadowValue = lerp(1.0f, saturate(customMainLight.shadowValue * 2.0f), _Set_SystemShadowsToBase); float systemShadowValue = lerp(1.0f, saturate(customMainLight.shadowValue * 2.0f), _Set_SystemShadowsToBase);
#endif #endif
#ifdef _SDFShadow #if _SHADOW_MODE_SDF
// modified by Suomi @ 20230902 - SDFResult is used to sample SDF texture on the correct side // modified by Suomi @ 20230902 - SDFResult is used to sample SDF texture on the correct side
float angle; float angle;