vault backup: 2025-02-06 21:31:49

This commit is contained in:
BlueRose 2025-02-06 21:31:49 +08:00
parent c21c070784
commit 8e9daf7717

View File

@ -311,111 +311,167 @@ else
``` ```
```c++ ```c++
FDirectLighting ToonBxDF(FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, float NoL, FAreaLight AreaLight, FShadowTerms Shadow) FDirectLighting ToonBxDF(FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, float NoL, FAreaLight AreaLight, FShadowTerms Shadow)
{ {
FMooaToonContext Context = GBuffer.MooaToonContext; FMooaToonContext MooaToonContext = GBuffer.MooaToonContext;
FMooaToonData MooaToonData = GBuffer.MooaToonContext.MooaToonData; FToonGBufferData ToonGBuffer = GBuffer.MooaToonContext.ToonGBuffer;
FDirectLighting Lighting = (FDirectLighting)0; FDirectLighting Lighting = (FDirectLighting)0;
Context.LightColor *= PI_INV; // default(EV100=0) light intensity == PI float3 LightColorAndAttenuation = AreaLight.FalloffColor * MooaToonContext.LightColor * Falloff;
float3 LightColorAndAttenuation = AreaLight.FalloffColor * Context.LightColor * Falloff; ColorSaturationPowerAndScale(LightColorAndAttenuation, View.MooaLightSaturationScale);
/* Tips: /* Tips:
* SvPosition == PixelPos (0 ~ View.BufferSizeAndInvSize.xy) * SceneTextureUV == BufferUV == ScreenUV (0 ~ 1), used to GetScreenSpaceData() / GetGBufferData() * * ScreenPosition = ClipPosition.xy / ClipPosition.w * SvPosition == PixelPos (0 ~ View.BufferSizeAndInvSize.xy)
* ViewportUV = ScreenPosition * float2(0.5, -0.5) + 0.5 * ViewportUV is the visible part of Buffer's UV (0 ~ 1) */ const float SpecularIntensity = Pow2(GBuffer.Specular * 2); * SceneTextureUV == BufferUV == ScreenUV (0 ~ 1), used to GetScreenSpaceData() / GetGBufferData()
const float3 H = normalize(V + L); *
const float NoH = saturate(dot(N, H)); * ScreenPosition = ClipPosition.xy / ClipPosition.w
const float halfNoL = dot(N, L) * 0.5f + 0.5f; * ViewportUV = ScreenPosition * float2(0.5, -0.5) + 0.5
const float2 BufferUV = SvPositionToBufferUV(float4(Context.PixelPos, 0, 0)); * ViewportUV is the visible part of Buffer's UV (0 ~ 1)
const float3 L_ClipSpace = mul(L, (float3x3)View.TranslatedWorldToClip).xyz; */
const float2 L_ViewportSpace = normalize(L_ClipSpace.xy * float2(0.5, -0.5)); const float NoL_Full = dot(N, L);
const float3 N_ClipSpace = mul(N, (float3x3)View.TranslatedWorldToClip).xyz; const float NoL_Half = NoL_Full * 0.5f + 0.5f;
const float2 N_ViewportSpace = normalize(N_ClipSpace.xy * float2(0.5, -0.5)); const float3 H = normalize(V + L);
const float WorldUnitLengthInBufferSizePixels = ComputeWorldUnitLengthInBufferSizePixels(GBuffer.Depth); const float2 BufferUV = SvPositionToBufferUV(float4(MooaToonContext.PixelPos, 0, 0));
const float2 ViewportUV = BufferUVToViewportUV(BufferUV);
const float3 L_ClipSpace = mul(L, (float3x3)View.TranslatedWorldToClip).xyz;
const float2 L_ViewportSpace = (L_ClipSpace.xy * float2(0.5, -0.5));
const float3 N_ClipSpace = mul(N, (float3x3)View.TranslatedWorldToClip).xyz;
const float2 N_ViewportSpace = (N_ClipSpace.xy * float2(0.5, -0.5));
const float ViewportSpaceToWorldSpaceDir = rcp(GBuffer.Depth);
// Diffuse // Diffuse
BRANCH if (Context.IsMainLight) {
{ // Screen Space Depth Test Hair Shadow float HairShadowOffset = 0;
float HairShadowValueOffset = 0; float DiffuseColorRampUVOffset = (ToonGBuffer.DiffuseColorRampUVOffset * 2.0f - 1.0f) * View.MooaDiffuseColorRampUVOffsetMaxRange;
BRANCH if(MooaToonData.RayTracingShadowFlag == MOOA_RAY_TRACING_SHADOW_FLAG_FACE_SCREEN_SPACE_HAIR_SHADOW && float ShadowGradient = saturate(NoL_Half + DiffuseColorRampUVOffset);
MooaToonData.HairShadowWidth > 0 && MooaToonData.HairShadowIntensity > 0)
{ float2 UVOffset = L_ViewportSpace * WorldUnitLengthInBufferSizePixels * Pow2(MooaToonData.HairShadowWidth) * View.MooaHairShadowMaxScreenSpaceDistance;
FGBufferData HairGbuffer = GetGBufferData(BufferUV + UVOffset);
float DepthFade = 1 - saturate(max(0, HairGbuffer.Depth - GBuffer.Depth - View.MooaHairShadowDepthTestThreshold) / max(1e-5, View.MooaHairShadowDepthFadeDistance));
if (HairGbuffer.ShadingModelID == SHADINGMODELID_TOON && #if SHADING_PATH_DEFERRED && defined(MOOA_TOON_DEFERRED_LIGHTING) && !SUBSTRATE_ENABLED
HairGbuffer.MooaToonContext.MooaToonData.RayTracingShadowFlag == MOOA_RAY_TRACING_SHADOW_FLAG_HAIR) {
{ HairShadowValueOffset = -1 * MooaToonData.HairShadowIntensity * DepthFade; // Screen Space Depth Test Hair Shadow
} } const float HairShadowWidth = 2.0f * View.MooaHairShadowWidth;
Shadow.SurfaceShadow = saturate(Shadow.SurfaceShadow + HairShadowValueOffset + MooaToonData.MainLightShadowValueOffset * 2.0f - 1.0f); const float HairShadowIntensity = View.MooaHairShadowIntensity;
LightColorAndAttenuation *= Shadow.SurfaceShadow; BRANCH if(ToonGBuffer.RayTracingShadowFlag == MOOA_RAY_TRACING_SHADOW_FLAG_FACE_SCREEN_SPACE_HAIR_SHADOW &&
Lighting.Diffuse = lerp(MooaToonData.MainLightShadowColor * lerp(1, Context.LightColor, MooaToonData.MainLightShadowApplyLightColor) * View.MooaIsGlobalIlluminationEnabled, HairShadowWidth > 0 && HairShadowIntensity > 0)
GBuffer.DiffuseColor * Context.LightColor, Shadow.SurfaceShadow); {
} else float2 ViewportUVOffset = L_ViewportSpace * ViewportSpaceToWorldSpaceDir * HairShadowWidth;
{ float2 TargetBufferUV = ViewportUVToBufferUV(saturate(ViewportUV + ViewportUVOffset));
float OtherLightShadowValue = ToonStep(halfNoL, MooaToonData.OtherLightDiffuseFeather, MooaToonData.OtherLightDiffuseThreshold); FGBufferData HairGbuffer = GetGBufferData(TargetBufferUV);
// Non-Directional light's SurfaceShadow contains distance attenuation, not just shadowmap float DepthFade = saturate(max(0, GBuffer.Depth - HairGbuffer.Depth - View.MooaHairShadowDepthTestThreshold) / max(1e-5, View.MooaHairShadowDepthTestFadeDistance));
Shadow.SurfaceShadow *= OtherLightShadowValue;
LightColorAndAttenuation *= Shadow.SurfaceShadow; if (HairGbuffer.ShadingModelID == SHADINGMODELID_TOON &&
Lighting.Diffuse = GBuffer.DiffuseColor * LightColorAndAttenuation; HairGbuffer.MooaToonContext.ToonGBuffer.RayTracingShadowFlag == MOOA_RAY_TRACING_SHADOW_FLAG_HAIR)
} {
// Anisotropy Context HairShadowOffset = -1 * HairShadowIntensity * DepthFade;
}
}
}
#endif
GetDistanceFieldFacialShadow(GBuffer, ToonGBuffer, L, DiffuseColorRampUVOffset,
ShadowGradient);
float DiffuseColorRampU = min3(saturate(Shadow.SurfaceShadow + HairShadowOffset), GBuffer.GBufferAO, ShadowGradient);
half4 DiffuseColorRamp = SampleGlobalRamp(View.MooaGlobalDiffuseColorRampAtlas, DiffuseColorRampU, ToonGBuffer.DiffuseColorRampIndex, View.MooaGlobalDiffuseColorRampAtlasHeight);
Shadow.SurfaceShadow = DiffuseColorRampU;
half3 ToonDiffuseColor = GBuffer.DiffuseColor;
half3 ToonShadowColor = ToonGBuffer.MainLightShadowColor * (1 - GBuffer.Metallic) * GetShadowColorIntensity(MooaToonContext);
#if USE_DEVELOPMENT_SHADERS
ToonShadowColor *= View.DiffuseOverrideParameter.w + View.DiffuseOverrideParameter.xyz;
#endif
ToonDiffuseColor = lerp(ToonShadowColor, ToonDiffuseColor, DiffuseColorRamp.a);
Lighting.Diffuse = Diffuse_Lambert(ToonDiffuseColor) * DiffuseColorRamp.rgb * LightColorAndAttenuation;
}
// Anisotropy Specular BxDF Context
bool bHasAnisotropy;
BxDFContext Context = (BxDFContext)0;
{
#if SUPPORTS_ANISOTROPIC_MATERIALS
bHasAnisotropy = true;// HasAnisotropy(GBuffer.SelectiveOutputMask);
#else
bHasAnisotropy = false;
#endif
if (ToonGBuffer.ShadingFeatureID == MOOA_SHADING_FEATURE_ID_DISTANCE_FIELD_FACIAL_SHADOW)
bHasAnisotropy = false;
BRANCH if (bHasAnisotropy)
{
half3 X = GBuffer.WorldTangent;
half3 Y = normalize(cross(N, X));
Init(Context, N, X, Y, V, L);
}
else
{
Init(Context, N, V, L);
GBuffer.Anisotropy = 0;
}
Context.NoV = saturate(abs( Context.NoV ) + 1e-5);
}
// Specular
BRANCH if (ToonGBuffer.ShadingFeatureID == MOOA_SHADING_FEATURE_ID_PBR_SPECULAR)
{
#if SUPPORTS_ANISOTROPIC_MATERIALS #if SUPPORTS_ANISOTROPIC_MATERIALS
bool bHasAnisotropy = HasAnisotropy(GBuffer.SelectiveOutputMask); BRANCH if (bHasAnisotropy)
#else {
bool bHasAnisotropy = false; Lighting.Specular = LightColorAndAttenuation * Shadow.SurfaceShadow * NoL * SpecularGGX(GBuffer.Roughness, GBuffer.Anisotropy, GBuffer.SpecularColor, Context, NoL, AreaLight);
}
else
#endif #endif
BxDFContext AnisotropyContext = (BxDFContext)0; {
{ half3 X = GBuffer.WorldTangent; BRANCH if( IsRectLight(AreaLight) )
half3 Y = normalize(cross(N, X)); {
Init(AnisotropyContext, N, X, Y, V, L); Lighting.Specular = MooaToonContext.LightColor * Shadow.SurfaceShadow * RectGGXApproxLTC(GBuffer.Roughness, GBuffer.SpecularColor, N, V, AreaLight.Rect, AreaLight.Texture);
AnisotropyContext.NoV = saturate(abs( AnisotropyContext.NoV ) + 1e-5); }
if (!bHasAnisotropy) GBuffer.Anisotropy = 0; else
} {
// Specular Lighting.Specular = LightColorAndAttenuation * Shadow.SurfaceShadow * NoL * SpecularGGX(GBuffer.Roughness, GBuffer.SpecularColor, Context, NoL, AreaLight);
BRANCH if (MooaToonData.IsPBRSpecular) }
{ Lighting.Specular = LightColorAndAttenuation * NoL * }
max(0, SpecularGGX(GBuffer.Roughness, GBuffer.Anisotropy, GBuffer.SpecularColor, AnisotropyContext, NoL, AreaLight)); }
} else else
{ {
// Anisotropy float MaxSpecularValue;
float2 XY = normalize(float2(1.0f + GBuffer.Anisotropy, 1.0f - GBuffer.Anisotropy)); float SpecularColorRampU = GetSpecularColorRampUAndMaxSpecularValue(GBuffer, Context, N, H,
float AnisotropyGradient = length(float2(XY.y * AnisotropyContext.XoH, XY.x * AnisotropyContext.YoH)); MaxSpecularValue);
// Toon Specular: https://www.desmos.com/calculator/qecziyizl1 float SpecularColorRampUVOffset = (ToonGBuffer.SpecularColorRampUVOffset * 2.0f - 1.0f) * View.MooaSpecularColorRampUVOffsetMaxRange;
float SpecularGradient = 1.0f - AnisotropyGradient; half3 SpecularColor = SampleGlobalRamp(View.MooaGlobalSpecularColorRampAtlas, SpecularColorRampU + SpecularColorRampUVOffset, ToonGBuffer.SpecularColorRampIndex, View.MooaGlobalSpecularColorRampAtlasHeight).rgb;
float SpecularThreshold = 1.0f - Pow2(MooaToonData.SpecularThreshold);
float SpecularFeather = Pow2(MooaToonData.SpecularFeather) * SpecularThreshold * 0.5f;
Lighting.Specular = saturate(ToonStep(SpecularGradient, SpecularFeather, SpecularThreshold + SpecularFeather, 1.0f, false, false)) Lighting.Specular = GBuffer.SpecularColor * ToonGBuffer.SpecularColor * MaxSpecularValue * SpecularColor * LightColorAndAttenuation * Shadow.SurfaceShadow;
* MooaToonData.SpecularColor * SpecularIntensity * LightColorAndAttenuation; }
}
// Screen Space Depth Test Rim Light
// Recompute Normals to override DCC Normals on Face/Hair const float3 WorldNormalFromDepth = normalize(ReconstructNormalFromDepthBuffer_Copy(Context.PixelPos));
const float3 DepthToN_ClipSpace = mul(WorldNormalFromDepth, (float3x3)View.TranslatedWorldToClip).xyz;
const float2 DepthToN_ViewportSpace = DepthToN_ClipSpace.xy * float2(0.5, -0.5);
BRANCH if (MooaToonData.RimLightIntensity > 0 && MooaToonData.RimLightWidth > 0)
{ float NoL_ClipSpaceAngle01 = (dot(normalize(DepthToN_ClipSpace.xy), normalize(L_ClipSpace.xy)) * 0.5 + 0.5);
float WidthScaleByAngle = saturate(lerp(NoL_ClipSpaceAngle01, 1, MooaToonData.RimLightAngle));
const float MaxRimLightWidth = 0.0003 * View.MooaRimLightMaxWidth;
const float MaxDepthTestDistance = 100 * View.MooaRimLightMaxDepthTestDistance;
const float MaxDepthFadeDistance = 100 * View.MooaRimLightMaxDepthFadeDistance;
// TODO: AA // Rimlight
float SubPixelFade = 1; float3 RimLight = GetScreenSpaceDepthTestRimlightColor(GBuffer, ToonGBuffer, ViewportUV, L_ViewportSpace, ViewportSpaceToWorldSpaceDir) * LightColorAndAttenuation * Shadow.SurfaceShadow;
float2 UVOffset = L_ViewportSpace * WorldUnitLengthInBufferSizePixels * MaxRimLightWidth * WidthScaleByAngle * Pow2(MooaToonData.RimLightWidth); ColorSaturationPowerAndScale(RimLight, View.MooaRimLightSaturationScale, View.MooaRimLightIntensity);
float2 TargetBufferUV = BufferUV + UVOffset; Lighting.Specular += RimLight;
#if MATERIALBLENDING_TRANSLUCENT || MATERIALBLENDING_ADDITIVE || MATERIALBLENDING_MODULATE return Lighting;
// TranslucentBasePass.SceneDepth include Translucent First Layer Depth }
// see UseFrontLayerReflection() float SingleLayerDeviceZ = Texture2DSampleLevel( TranslucentBasePass.SceneDepth, GlobalPointClampedSampler, TargetBufferUV, 0).r;
float NewDepth = ConvertFromDeviceZ(SingleLayerDeviceZ); ```
#else
float NewDepth = GetGBufferData(TargetBufferUV).Depth; # 实用函数
#endif 如果需要脸部SDF阴影就覆盖ShadowGradient。
float DepthFade = saturate(max(0, NewDepth - GBuffer.Depth - MaxDepthTestDistance * Pow2(MooaToonData.RimLightDepthThreshold)) ```c++
/ max(1e-5, MaxDepthFadeDistance * Pow2(MooaToonData.RimLightDepthThreshold))); void GetDistanceFieldFacialShadow(FGBufferData GBuffer, FToonGBufferData ToonGBuffer, float3 L, float DiffuseColorRampUVOffset,
Lighting.Specular = max(Lighting.Specular, DepthFade * MooaToonData.RimLightIntensity * LightColorAndAttenuation); inout float ShadowGradient)
} {
return Lighting; BRANCH if (ToonGBuffer.ShadingFeatureID == MOOA_SHADING_FEATURE_ID_DISTANCE_FIELD_FACIAL_SHADOW)
{
float3 FaceForwardDir = GBuffer.WorldTangent;
float LightAngle = RadianToDegree(FastACos(dot(FaceForwardDir, L)));
float RampUVOffsetByLightAngle = (1.0 - clamp(LightAngle / 180.0f, 1e-4, 1 - 1e-4)) - 0.5f;
bool bLightAtRight = cross(FaceForwardDir, L).z >= 0; // TODO: Fix the numerical accuracy issue of extreme angles
float shadowSdf = bLightAtRight ? ToonGBuffer.FacialShadowSdfRight : ToonGBuffer.FacialShadowSdfLeft;
ShadowGradient = saturate(RampUVOffsetByLightAngle + shadowSdf + DiffuseColorRampUVOffset);
}
} }
``` ```