From 598d61b281d12f7e8aed27cb7d8b1a56b3b88cb5 Mon Sep 17 00:00:00 2001 From: BlueRose <378100977@qq.com> Date: Thu, 25 Jan 2024 20:10:54 +0800 Subject: [PATCH] vault backup: 2024-01-25 20:10:54 --- .../演讲笔记/JasonMa/JasonMa渲染方案分析.md | 112 +++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/03-UnrealEngine/卡通渲染相关资料/演讲笔记/JasonMa/JasonMa渲染方案分析.md b/03-UnrealEngine/卡通渲染相关资料/演讲笔记/JasonMa/JasonMa渲染方案分析.md index e2f2cb6..7f098fd 100644 --- a/03-UnrealEngine/卡通渲染相关资料/演讲笔记/JasonMa/JasonMa渲染方案分析.md +++ b/03-UnrealEngine/卡通渲染相关资料/演讲笔记/JasonMa/JasonMa渲染方案分析.md @@ -275,7 +275,7 @@ FMooaToonData DecodeMooaToonDataFromBuffer(uint4 ToonBufferA, float4 CustomData) - MooaToonDataC(**GBufferD CustomData**) = MainLightShadowColor(8 8 8) + MainLightShadowValueOffset(8) -# LightModel +# ShaderMoodel ```c++ /* ================================== Mooa Toon Deferred Lighting Model ====================================================================================================== * IndirectColor                (DiffuseIndirectComposite.usf)    = IndirectDiffuse + IndirectSpecular @@ -308,4 +308,114 @@ else Material.bNeedsSeparateLightAccumulation); OutAddColor = LightAccumulator_GetResult(LightAccumulator); } +``` + +```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; + + /* 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); + + + // 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)); + + 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 SUPPORTS_ANISOTROPIC_MATERIALS + bool bHasAnisotropy = HasAnisotropy(GBuffer.SelectiveOutputMask); +#else + bool bHasAnisotropy = false; +#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; + + 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; + + // TODO: AA + float SubPixelFade = 1; + float2 UVOffset = L_ViewportSpace * WorldUnitLengthInBufferSizePixels * MaxRimLightWidth * WidthScaleByAngle * Pow2(MooaToonData.RimLightWidth); + float2 TargetBufferUV = BufferUV + UVOffset; + +#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; +} ``` \ No newline at end of file