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