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++
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;
FDirectLighting Lighting = (FDirectLighting)0;
Context.LightColor *= PI_INV; // default(EV100=0) light intensity == PI
float3 LightColorAndAttenuation = AreaLight.FalloffColor * Context.LightColor * Falloff;
FMooaToonContext MooaToonContext = GBuffer.MooaToonContext;
FToonGBufferData ToonGBuffer = GBuffer.MooaToonContext.ToonGBuffer;
FDirectLighting Lighting = (FDirectLighting)0;
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
* 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);
const float3 H = normalize(V + L);
const float NoH = saturate(dot(N, H));
const float halfNoL = dot(N, L) * 0.5f + 0.5f;
const float2 BufferUV = SvPositionToBufferUV(float4(Context.PixelPos, 0, 0));
const float3 L_ClipSpace = mul(L, (float3x3)View.TranslatedWorldToClip).xyz;
const float2 L_ViewportSpace = normalize(L_ClipSpace.xy * float2(0.5, -0.5));
const float3 N_ClipSpace = mul(N, (float3x3)View.TranslatedWorldToClip).xyz;
const float2 N_ViewportSpace = normalize(N_ClipSpace.xy * float2(0.5, -0.5));
const float WorldUnitLengthInBufferSizePixels = ComputeWorldUnitLengthInBufferSizePixels(GBuffer.Depth);
/* Tips:
* SvPosition == PixelPos (0 ~ View.BufferSizeAndInvSize.xy)
* SceneTextureUV == BufferUV == ScreenUV (0 ~ 1), used to GetScreenSpaceData() / GetGBufferData()
*
* ScreenPosition = ClipPosition.xy / ClipPosition.w
* ViewportUV = ScreenPosition * float2(0.5, -0.5) + 0.5
* ViewportUV is the visible part of Buffer's UV (0 ~ 1)
*/
const float NoL_Full = dot(N, L);
const float NoL_Half = NoL_Full * 0.5f + 0.5f;
const float3 H = normalize(V + L);
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
BRANCH if (Context.IsMainLight)
{ // Screen Space Depth Test Hair Shadow
float HairShadowValueOffset = 0;
BRANCH if(MooaToonData.RayTracingShadowFlag == MOOA_RAY_TRACING_SHADOW_FLAG_FACE_SCREEN_SPACE_HAIR_SHADOW &&
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));
// Diffuse
{
float HairShadowOffset = 0;
float DiffuseColorRampUVOffset = (ToonGBuffer.DiffuseColorRampUVOffset * 2.0f - 1.0f) * View.MooaDiffuseColorRampUVOffsetMaxRange;
float ShadowGradient = saturate(NoL_Half + DiffuseColorRampUVOffset);
if (HairGbuffer.ShadingModelID == SHADINGMODELID_TOON &&
HairGbuffer.MooaToonContext.MooaToonData.RayTracingShadowFlag == MOOA_RAY_TRACING_SHADOW_FLAG_HAIR)
{ HairShadowValueOffset = -1 * MooaToonData.HairShadowIntensity * DepthFade;
} }
Shadow.SurfaceShadow = saturate(Shadow.SurfaceShadow + HairShadowValueOffset + MooaToonData.MainLightShadowValueOffset * 2.0f - 1.0f);
LightColorAndAttenuation *= Shadow.SurfaceShadow;
Lighting.Diffuse = lerp(MooaToonData.MainLightShadowColor * lerp(1, Context.LightColor, MooaToonData.MainLightShadowApplyLightColor) * View.MooaIsGlobalIlluminationEnabled,
GBuffer.DiffuseColor * Context.LightColor, Shadow.SurfaceShadow);
} else
{
float OtherLightShadowValue = ToonStep(halfNoL, MooaToonData.OtherLightDiffuseFeather, MooaToonData.OtherLightDiffuseThreshold);
// Non-Directional light's SurfaceShadow contains distance attenuation, not just shadowmap
Shadow.SurfaceShadow *= OtherLightShadowValue;
LightColorAndAttenuation *= Shadow.SurfaceShadow;
Lighting.Diffuse = GBuffer.DiffuseColor * LightColorAndAttenuation;
}
// Anisotropy Context
#if SHADING_PATH_DEFERRED && defined(MOOA_TOON_DEFERRED_LIGHTING) && !SUBSTRATE_ENABLED
{
// Screen Space Depth Test Hair Shadow
const float HairShadowWidth = 2.0f * View.MooaHairShadowWidth;
const float HairShadowIntensity = View.MooaHairShadowIntensity;
BRANCH if(ToonGBuffer.RayTracingShadowFlag == MOOA_RAY_TRACING_SHADOW_FLAG_FACE_SCREEN_SPACE_HAIR_SHADOW &&
HairShadowWidth > 0 && HairShadowIntensity > 0)
{
float2 ViewportUVOffset = L_ViewportSpace * ViewportSpaceToWorldSpaceDir * HairShadowWidth;
float2 TargetBufferUV = ViewportUVToBufferUV(saturate(ViewportUV + ViewportUVOffset));
FGBufferData HairGbuffer = GetGBufferData(TargetBufferUV);
float DepthFade = saturate(max(0, GBuffer.Depth - HairGbuffer.Depth - View.MooaHairShadowDepthTestThreshold) / max(1e-5, View.MooaHairShadowDepthTestFadeDistance));
if (HairGbuffer.ShadingModelID == SHADINGMODELID_TOON &&
HairGbuffer.MooaToonContext.ToonGBuffer.RayTracingShadowFlag == MOOA_RAY_TRACING_SHADOW_FLAG_HAIR)
{
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
bool bHasAnisotropy = HasAnisotropy(GBuffer.SelectiveOutputMask);
#else
bool bHasAnisotropy = false;
BRANCH if (bHasAnisotropy)
{
Lighting.Specular = LightColorAndAttenuation * Shadow.SurfaceShadow * NoL * SpecularGGX(GBuffer.Roughness, GBuffer.Anisotropy, GBuffer.SpecularColor, Context, NoL, AreaLight);
}
else
#endif
BxDFContext AnisotropyContext = (BxDFContext)0;
{ half3 X = GBuffer.WorldTangent;
half3 Y = normalize(cross(N, X));
Init(AnisotropyContext, N, X, Y, V, L);
AnisotropyContext.NoV = saturate(abs( AnisotropyContext.NoV ) + 1e-5);
if (!bHasAnisotropy) GBuffer.Anisotropy = 0;
}
// Specular
BRANCH if (MooaToonData.IsPBRSpecular)
{ Lighting.Specular = LightColorAndAttenuation * NoL *
max(0, SpecularGGX(GBuffer.Roughness, GBuffer.Anisotropy, GBuffer.SpecularColor, AnisotropyContext, NoL, AreaLight));
} else
{
// Anisotropy
float2 XY = normalize(float2(1.0f + GBuffer.Anisotropy, 1.0f - GBuffer.Anisotropy));
float AnisotropyGradient = length(float2(XY.y * AnisotropyContext.XoH, XY.x * AnisotropyContext.YoH));
// Toon Specular: https://www.desmos.com/calculator/qecziyizl1
float SpecularGradient = 1.0f - AnisotropyGradient;
float SpecularThreshold = 1.0f - Pow2(MooaToonData.SpecularThreshold);
float SpecularFeather = Pow2(MooaToonData.SpecularFeather) * SpecularThreshold * 0.5f;
{
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 = saturate(ToonStep(SpecularGradient, SpecularFeather, SpecularThreshold + SpecularFeather, 1.0f, false, false))
* 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;
Lighting.Specular = GBuffer.SpecularColor * ToonGBuffer.SpecularColor * MaxSpecularValue * SpecularColor * LightColorAndAttenuation * Shadow.SurfaceShadow;
}
// TODO: AA
float SubPixelFade = 1;
float2 UVOffset = L_ViewportSpace * WorldUnitLengthInBufferSizePixels * MaxRimLightWidth * WidthScaleByAngle * Pow2(MooaToonData.RimLightWidth);
float2 TargetBufferUV = BufferUV + UVOffset;
// Rimlight
float3 RimLight = GetScreenSpaceDepthTestRimlightColor(GBuffer, ToonGBuffer, ViewportUV, L_ViewportSpace, ViewportSpaceToWorldSpaceDir) * LightColorAndAttenuation * Shadow.SurfaceShadow;
ColorSaturationPowerAndScale(RimLight, View.MooaRimLightSaturationScale, View.MooaRimLightIntensity);
Lighting.Specular += RimLight;
#if MATERIALBLENDING_TRANSLUCENT || MATERIALBLENDING_ADDITIVE || MATERIALBLENDING_MODULATE
// 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
float DepthFade = saturate(max(0, NewDepth - GBuffer.Depth - MaxDepthTestDistance * Pow2(MooaToonData.RimLightDepthThreshold))
/ max(1e-5, MaxDepthFadeDistance * Pow2(MooaToonData.RimLightDepthThreshold)));
Lighting.Specular = max(Lighting.Specular, DepthFade * MooaToonData.RimLightIntensity * LightColorAndAttenuation);
}
return Lighting;
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);
}
}
```