421 lines
21 KiB
Markdown
Raw Normal View History

2024-01-25 19:31:07 +08:00
---
title: JasonMa渲染方案分析
date: 2024-01-25 16:02:26
excerpt:
tags:
rating: ⭐
---
# 前言
截止版本UE5.3.2。添加了一种新的GBuffer精度格式GBT_Uint_32_32_32_32以及RT7。
修改内容:
- GBufferPostDecode.ush在GBufferPostDecode中给FGBufferData添加InitMooaToonContext()逻辑
- SceneRendering.cppDebug用的渲染变量调节并且在FViewInfo::SetupUniformBufferParameters()添加设置相关变量的逻辑。
- 其他:
- MaterialBakingExportMaterialProxy.h
- MaterialEditorMaterialEditor.cpp
- PixelInspectorPixelInspectorResult.cpp、PixelInspectorResult.h
# ToonShadingCommon.ush
除了一下工具函数,主要实现:
1. GBuffer的一些Encode / Decode Helper函数。
2. 用于存储数据的struct FMooaToonData、FMooaToonContext。
3. 针对上面2个结构体编码与解码的函数。FMooaCustomPayload用于光追Shader。
## 数据结构体
```c++
struct FMooaToonContext
{
FMooaToonData MooaToonData;
bool IsMainLight;
float3 LightColor;
bool IsEditorPreviewWorldType;
float Exposure;
uint2 PixelPos; // SVPos.xy
};
struct FMooaToonData
{
// Diffuse
float3 MainLightShadowColor;
float MainLightShadowValueOffset;
float MainLightShadowApplyLightColor;
float OtherLightDiffuseThreshold;
float OtherLightDiffuseFeather;
float GlobalIlluminationIntensity;
float GlobalIlluminationDirectionality;
// Specular
float3 SpecularColor;
float SpecularThreshold;
float SpecularFeather;
float ReflectionIntensity;
bool IsPBRSpecular;
float RimLightIntensity;
float RimLightWidth;
float RimLightAngle;
float RimLightDepthThreshold;
// Ray Tracing Shadow
uint Stencil;
uint RayTracingShadowFlag;
float HairShadowWidth;
float HairShadowIntensity;
// Unused
float CustomData3;
};
```
## Encode/Decode
这里推荐使用计算器进行计算更加好理解。
```c++
//取得指定Bits位数的最大数值8位 => 255
uint GetBitsMaxValue(int Bits = 8) {return (1L << Bits) - 1;}
//将2个uint合并1个uint将Src1移动Scr2的位数后将2者进行或运算合并到一起。
uint EncodeUint2ToUint(uint Src1, uint Src2, int BitsSrc1 = 8, int BitsSrc2 = 8)
{
return ((Src1 & GetBitsMaxValue(BitsSrc1)) << BitsSrc2) |
(Src2 & GetBitsMaxValue(BitsSrc2));
}
//将2个uint合并1个uint后转换成浮点数0~1
float EncodeUint2ToFloat(uint Src1, uint Src2, int BitsSrc1 = 8, int BitsSrc2 = 8)
{
return float(EncodeUint2ToUint(Src1, Src2, BitsSrc1, BitsSrc2)) / GetBitsMaxValue(BitsSrc1 + BitsSrc2);
}
//将合并后Uint还原成2个uint
void DecodeUint2FromUint(uint Src, out uint Dst1, out uint Dst2, int BitsDst1 = 8, int BitsDst2 = 8)
{
Dst1 = (Src >> BitsDst2) & GetBitsMaxValue(BitsDst1);
Dst2 = Src & GetBitsMaxValue(BitsDst2);
}
//将合并后float0~1还原成2个uint
void DecodeUint2FromFloat(float Src, out uint Dst1, out uint Dst2, int BitsDst1 = 8, int BitsDst2 = 8)
{
uint FloatToUint = uint(Src * GetBitsMaxValue(BitsDst1 + BitsDst2));
DecodeUint2FromUint(FloatToUint, Dst1, Dst2, BitsDst1, BitsDst2);
}
//将float0~1编码成uint
uint EncodeFloatToUint(float Src1, int BitsSrc1 = 8)
{
return saturate(Src1) * GetBitsMaxValue(BitsSrc1);
}
uint EncodeFloat2ToUint(float Src1, float Src2, int BitsSrc1 = 8, int BitsSrc2 = 8)
{
return EncodeUint2ToUint(EncodeFloatToUint(Src1, BitsSrc1), EncodeFloatToUint(Src2, BitsSrc2), BitsSrc1, BitsSrc2);
}
float EncodeFloat2ToFloat(float Src1, float Src2, int BitsSrc1 = 8, int BitsSrc2 = 8)
{
return EncodeUint2ToFloat(EncodeFloatToUint(Src1, BitsSrc1), EncodeFloatToUint(Src2, BitsSrc2), BitsSrc1, BitsSrc2);
}
//将uint还原成float0~1
float DecodeFloatFromUint(uint Src, int BitsDst1 = 8)
{
return float(Src & GetBitsMaxValue(BitsDst1)) / GetBitsMaxValue(BitsDst1);
}
void DecodeFloat2FromUint(uint Src, out float Dst1, out float Dst2, int BitsDst1 = 8, int BitsDst2 = 8)
{
uint OutUint1, OutUint2;
DecodeUint2FromUint(Src, OutUint1, OutUint2, BitsDst1, BitsDst2);
Dst1 = DecodeFloatFromUint(OutUint1, BitsDst1);
Dst2 = DecodeFloatFromUint(OutUint2, BitsDst2);
}
void DecodeFloat2FromFloat(float Src, out float Dst1, out float Dst2, int BitsDst1 = 8, int BitsDst2 = 8)
{
uint OutUint1, OutUint2;
DecodeUint2FromFloat(Src, OutUint1, OutUint2, BitsDst1, BitsDst2);
Dst1 = DecodeFloatFromUint(OutUint1, BitsDst1);
Dst2 = DecodeFloatFromUint(OutUint2, BitsDst2);
```
## 结构体与GBuffer Encode/Decode
```c++
void EncodeMooaToonData(FMooaToonData MooaToonData, out float4 MooaToonDataA, out float4 MooaToonDataB, out float4 MooaToonDataC)
{
MooaToonDataA = (float4)0;
MooaToonDataB = (float4)0;
MooaToonDataC = (float4)0;
MooaToonDataA.x = EncodeFloat2ToUint(MooaToonData.OtherLightDiffuseThreshold, MooaToonData.OtherLightDiffuseFeather);
MooaToonDataA.y = EncodeFloat2ToUint(MooaToonData.GlobalIlluminationIntensity, MooaToonData.GlobalIlluminationDirectionality, 6, 6);
MooaToonDataA.z = EncodeFloat2ToUint(MooaToonData.MainLightShadowApplyLightColor, MooaToonData.CustomData3, 6, 4);
MooaToonDataA.w = EncodeUint2ToUint(
EncodeFloatToUint(MooaToonData.HairShadowWidth, 6),
EncodeUint2ToUint(
MooaToonData.Stencil,
EncodeUint2ToUint(MooaToonData.RayTracingShadowFlag, MooaToonData.IsPBRSpecular ? 1 : 0, 2, 1),
5, 3),
6, 8);
MooaToonDataB.x = EncodeFloat2ToUint(MooaToonData.SpecularColor.r, MooaToonData.SpecularColor.g);
MooaToonDataB.y = EncodeUint2ToUint(
EncodeFloatToUint(MooaToonData.SpecularColor.b),
EncodeFloat2ToUint(MooaToonData.ReflectionIntensity, MooaToonData.HairShadowIntensity, 6, 6),
8, 12);
MooaToonDataB.z = EncodeUint2ToUint(
EncodeFloat2ToUint(MooaToonData.SpecularThreshold, MooaToonData.SpecularFeather),
EncodeFloatToUint(MooaToonData.RimLightIntensity, 6),
16, 6);
MooaToonDataB.w = EncodeUint2ToUint(
EncodeFloat2ToUint(MooaToonData.RimLightWidth, MooaToonData.RimLightAngle, 6, 6),
EncodeFloatToUint(MooaToonData.RimLightDepthThreshold, 6),
12, 6);
MooaToonDataC.rgb = saturate(MooaToonData.MainLightShadowColor);
MooaToonDataC.a = saturate(MooaToonData.MainLightShadowValueOffset);
}
FMooaToonData DecodeMooaToonData(float4 MooaToonDataA, float4 MooaToonDataB, float4 MooaToonDataC)
{
FMooaToonData MooaToonData = (FMooaToonData)0;
uint Out0, Out1, Out2, Out3;
DecodeFloat2FromUint(MooaToonDataA.x, MooaToonData.OtherLightDiffuseThreshold, MooaToonData.OtherLightDiffuseFeather);
DecodeFloat2FromUint(MooaToonDataA.y, MooaToonData.GlobalIlluminationIntensity, MooaToonData.GlobalIlluminationDirectionality, 6, 6);
DecodeFloat2FromUint(MooaToonDataA.z, MooaToonData.MainLightShadowApplyLightColor, MooaToonData.CustomData3, 6, 4);
DecodeUint2FromUint(MooaToonDataA.w, Out0, Out1, 6, 8);
MooaToonData.HairShadowWidth = DecodeFloatFromUint(Out0, 6);
DecodeUint2FromUint(Out1, MooaToonData.Stencil, Out2, 5, 3);
DecodeUint2FromUint(Out2, MooaToonData.RayTracingShadowFlag, MooaToonData.IsPBRSpecular, 2, 1);
DecodeFloat2FromUint(MooaToonDataB.x, MooaToonData.SpecularColor.r, MooaToonData.SpecularColor.g);
DecodeUint2FromUint(MooaToonDataB.y, Out0, Out1, 8, 12);
MooaToonData.SpecularColor.b = DecodeFloatFromUint(Out0);
DecodeFloat2FromUint(Out1, MooaToonData.ReflectionIntensity, MooaToonData.HairShadowIntensity, 6, 6);
DecodeUint2FromUint(MooaToonDataB.z, Out0, Out1, 16, 6);
DecodeFloat2FromUint(Out0, MooaToonData.SpecularThreshold, MooaToonData.SpecularFeather);
MooaToonData.RimLightIntensity = DecodeFloatFromUint(Out1, 6);
DecodeUint2FromUint(MooaToonDataB.w, Out0, Out1, 12, 6);
DecodeFloat2FromUint(Out0, MooaToonData.RimLightWidth, MooaToonData.RimLightAngle, 6, 6);
MooaToonData.RimLightDepthThreshold = DecodeFloatFromUint(Out1, 6);
MooaToonData.MainLightShadowColor = MooaToonDataC.rgb;
MooaToonData.MainLightShadowValueOffset = MooaToonDataC.a;
return MooaToonData;
}
uint4 EncodeMooaToonDataToBuffer(FMooaToonData MooaToonData)
{
MooaToonData.SpecularColor = LinearToSrgb(saturate(MooaToonData.SpecularColor));
float4 MooaToonDataA, MooaToonDataB, MooaToonDataC;
uint4 Out;
EncodeMooaToonData(MooaToonData, MooaToonDataA, MooaToonDataB, MooaToonDataC);
Out.x = EncodeUint2ToUint(MooaToonDataA.x, MooaToonDataB.x, 16, 16);
Out.y = EncodeUint2ToUint(MooaToonDataA.y, MooaToonDataB.y, 12, 20);
Out.z = EncodeUint2ToUint(MooaToonDataA.z, MooaToonDataB.z, 10, 22);
Out.w = EncodeUint2ToUint(MooaToonDataA.w, MooaToonDataB.w, 14, 18);
return Out;
}
FMooaToonData DecodeMooaToonDataFromBuffer(uint4 ToonBufferA, float4 CustomData)
{
uint4 Out0, Out1;
DecodeUint2FromUint(ToonBufferA.x, Out0.x, Out1.x, 16, 16);
DecodeUint2FromUint(ToonBufferA.y, Out0.y, Out1.y, 12, 20);
DecodeUint2FromUint(ToonBufferA.z, Out0.z, Out1.z, 10, 22);
DecodeUint2FromUint(ToonBufferA.w, Out0.w, Out1.w, 14, 18);
float4 MooaToonDataA = Out0;
float4 MooaToonDataB = Out1;
FMooaToonData MooaToonData = DecodeMooaToonData(MooaToonDataA, MooaToonDataB, CustomData);
MooaToonData.MainLightShadowColor = sRGBToLinear(MooaToonData.MainLightShadowColor);
MooaToonData.SpecularColor = sRGBToLinear(MooaToonData.SpecularColor);
return MooaToonData;
}
```
# BasePassPixelShader.usf
## GBuffer
```c++
/*
* CustomData (GBufferD) (MP_MooaToonDataC) (0~1) = MainLightShadowColor(8 8 8) MainLightShadowValueOffset(8)
*
* ToonBufferA (RGBA Uint 32)
* xyzw: MooaToonDataA.xyzw | MooaToonDataB.xyzw (32 bits total)
*
* MP_MooaToonDataA (float4, max storage 23 bits uint)
* x: OtherLightDiffuseThreshold(8) OtherLightDiffuseFeather(8)
* y: GlobalIlluminationIntensity(6) GlobalIlluminationDirectionality(6)
* z: MainLightShadowApplyLightColor(6) CustomData3(4)
* w: HairShadowWidth(6) Stencil(5) RayTracingShadowFlag(2) IsPBRSpecular(1)
*
* MP_MooaToonDataB (float4, max storage 23 bits uint)
* x: SpecularColor.x(8) SpecularColor.y(8)
* y: SpecularColor.z(8) ReflectionIntensity(6) HairShadowIntensity(6)
* z: SpecularThreshold(8) SpecularFeather(8) RimLightIntensity(6)
* w: RimLightWidth(6) RimLightAngle(6) RimLightDepthThreshold(6)
*
*
* Tips: store sRGB Color to maximize accuracy
*/
```
>PS.float4, max storage 23 bits uint
>Jason自己添加了GBT_Uint_32_32_32_32的GBuffer格式。
- MooaToonDataA (RGBA Uint 32 **ToonBufferA**)
- R4+4OtherLightDiffuseThreshold + OtherLightDiffuseFeather
- G4+4GlobalIlluminationIntensity + GlobalIlluminationDirectionality
- B4+4MainLightShadowApplyLightColor + CustomData3
- A 6+5+2+1HairShadowWidth + Stencil + RayTracingShadowFlag + IsPBRSpecular
- MooaToonDataB (RGBA Uint 32从材质直接传递到FGBuffer结构体中位置位于BasePassPixelShader.usf的InitMooaToonData与InitMooaToonContext其他可能位置位于GBufferHelpers.ush的GBufferPostDecode()、DeferredShadingCommon.ush的DecodeGBufferData())
- R8+8SpecularColor.x + SpecularColor.y
- G8+6+6SpecularColor.z + ReflectionIntensity + HairShadowIntensity
- B8+8+6SpecularThreshold + SpecularFeather + RimLightIntensity
- A6+6+6RimLightWidth + RimLightAngle + RimLightDepthThreshold(6)
- MooaToonDataC(**GBufferD CustomData**) = MainLightShadowColor(8 8 8) + MainLightShadowValueOffset(8)
2024-01-25 20:10:54 +08:00
# ShaderMoodel
2024-01-25 19:31:07 +08:00
```c++
/* ================================== Mooa Toon Deferred Lighting Model ======================================================================================================
* IndirectColor                (DiffuseIndirectComposite.usf)    = IndirectDiffuse + IndirectSpecular
* DirectionalLightShadingColor (DeferredLightPixelShaders.usf)    = (lerp(ShadowColor, Diffuse * LightColor, min(ShadowValue, LightAttenuation)) + Specular * LightColor) * MooaExposure
* OtherLightShadingColor        (DeferredLightPixelShaders.usf)    = (Diffuse + Specular) * LightColor * min(ShadowValue, LightAttenuation) * OtherLightCount
* FinalColor                                                    = IndirectColor + DirectionalLightShadingColor + OtherLightShadingColor
* ==================================================================================================================================================================
*/
// Mooa Indirect Lighting
if (Material.GBufferData.ShadingModelID == SHADINGMODELID_TOON)
{
float3 SHDiffuseAverage = GetSkySHDiffuse(0.0f) * View.SkyLightColor.rgb * View.PreExposure;
float3 LumenGiDiffuse = IndirectLighting.Diffuse;
FMooaToonData MooaToonData = Material.GBufferData.MooaToonContext.MooaToonData;
OutAddColor.rgb = //MooaToonData.MainLightShadowColor +
lerp(SHDiffuseAverage * Material.GBufferData.BaseColor, LumenGiDiffuse, MooaToonData.GlobalIlluminationDirectionality) * MooaToonData.GlobalIlluminationIntensity;
OutAddColor.rgb += IndirectLighting.Specular * Pow2(MooaToonData.ReflectionIntensity);
OutAddColor.rgb *= View.MooaExposureScale;
OutAddColor.a = Luminance(OutAddColor.rgb);
}
else
{
IndirectLighting.Specular *= GetSSSCheckerboadSpecularScale(PixelPos, Material.bNeedsSeparateLightAccumulation);
FLightAccumulator LightAccumulator = (FLightAccumulator)0;
LightAccumulator_Add(
LightAccumulator,
IndirectLighting.Diffuse + IndirectLighting.Specular,
IndirectLighting.Diffuse,
1.0f,
Material.bNeedsSeparateLightAccumulation);
OutAddColor = LightAccumulator_GetResult(LightAccumulator);
}
2024-01-25 20:10:54 +08:00
```
```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;
}
2024-01-25 19:31:07 +08:00
```