diff --git a/03-UnrealEngine/Rendering/RenderingPipeline/Lighting/Lighting.md b/03-UnrealEngine/Rendering/RenderingPipeline/Lighting/Lighting.md index 68da717..d0a3d2e 100644 --- a/03-UnrealEngine/Rendering/RenderingPipeline/Lighting/Lighting.md +++ b/03-UnrealEngine/Rendering/RenderingPipeline/Lighting/Lighting.md @@ -305,7 +305,6 @@ FDeferredLightData InitDeferredLightFromUniforms(uint InLightType) ``` ### DeferredLightPixelMain - ```c++ void DeferredLightPixelMain( #if LIGHT_SOURCE_SHAPE > 0 @@ -435,7 +434,7 @@ void DeferredLightPixelMain( float SurfaceShadow = 1.0f; - float4 LightAttenuation = GetLightAttenuationFromShadow(InputParams, SceneDepth); + float4 LightAttenuation = GetLightAttenuationFromShadow(InputParams, SceneDepth);//根绝是否开启VSM 分别从VirtualShadowMap 或者 LightAttenuationTexture(上一阶段渲染的ShadowProjction) 获取灯光衰减值。 float4 Radiance = GetDynamicLighting(DerivedParams.TranslatedWorldPosition, DerivedParams.CameraVector, ScreenSpaceData.GBuffer, ScreenSpaceData.AmbientOcclusion, ScreenSpaceData.GBuffer.ShadingModelID, LightData, LightAttenuation, Dither, uint2(InputParams.PixelPos), SurfaceShadow); OutColor += Radiance; @@ -454,4 +453,194 @@ void DeferredLightPixelMain( #endif } #endif +``` + +### GetDynamicLighting() => GetDynamicLightingSplit() +```c++ +FDeferredLightingSplit GetDynamicLightingSplit( + float3 TranslatedWorldPosition, float3 CameraVector, FGBufferData GBuffer, float AmbientOcclusion, uint ShadingModelID, + FDeferredLightData LightData, float4 LightAttenuation, float Dither, uint2 SVPos, + inout float SurfaceShadow) +{ + FLightAccumulator LightAccumulator = AccumulateDynamicLighting(TranslatedWorldPosition, CameraVector, GBuffer, AmbientOcclusion, ShadingModelID, LightData, LightAttenuation, Dither, SVPos, SurfaceShadow); + return LightAccumulator_GetResultSplit(LightAccumulator); +} +``` + +LightAccumulator_GetResultSplit():针对Subsurface,`RetDiffuse.a = In.ScatterableLightLuma;` 或者 `RetDiffuse.a = Luminance(In.ScatterableLight);` +```c++ +FDeferredLightingSplit LightAccumulator_GetResultSplit(FLightAccumulator In) +{ + float4 RetDiffuse; + float4 RetSpecular; + + if (VISUALIZE_LIGHT_CULLING == 1) + { + // a soft gradient from dark red to bright white, can be changed to be different + RetDiffuse = 0.1f * float4(1.0f, 0.25f, 0.075f, 0) * In.EstimatedCost; + RetSpecular = 0.1f * float4(1.0f, 0.25f, 0.075f, 0) * In.EstimatedCost; + } + else + { + RetDiffuse = float4(In.TotalLightDiffuse, 0); + RetSpecular = float4(In.TotalLightSpecular, 0); + + //针对Subsurface会额外对RetDiffuse的Alpha设置数值 ScatterableLight的亮度数值 + if (SUBSURFACE_CHANNEL_MODE == 1 ) + { + if (View.bCheckerboardSubsurfaceProfileRendering == 0) + { + // RGB accumulated RGB HDR color, A: specular luminance for screenspace subsurface scattering + RetDiffuse.a = In.ScatterableLightLuma; + } + } + else if (SUBSURFACE_CHANNEL_MODE == 2) + { + // RGB accumulated RGB HDR color, A: view independent (diffuse) luminance for screenspace subsurface scattering + // 3 add, 1 mul, 2 mad, can be optimized to use 2 less temporary during accumulation and remove the 3 add + RetDiffuse.a = Luminance(In.ScatterableLight); + // todo, need second MRT for SUBSURFACE_CHANNEL_MODE==2 + } + } + + FDeferredLightingSplit Ret; + Ret.DiffuseLighting = RetDiffuse; + Ret.SpecularLighting = RetSpecular; + + return Ret; +} +``` +#### AccumulateDynamicLighting +```c++ +FLightAccumulator AccumulateDynamicLighting( + float3 TranslatedWorldPosition, half3 CameraVector, FGBufferData GBuffer, half AmbientOcclusion, uint ShadingModelID, + FDeferredLightData LightData, half4 LightAttenuation, float Dither, uint2 SVPos, + inout float SurfaceShadow) +{ + FLightAccumulator LightAccumulator = (FLightAccumulator)0; + + half3 V = -CameraVector; + half3 N = GBuffer.WorldNormal; + //针对开启CLEAR_COAT_BOTTOM_NORMAL的清漆ShadingModel进行Normal处理 + BRANCH if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT && CLEAR_COAT_BOTTOM_NORMAL) + { + const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 4) - (512.0/255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal); + N = OctahedronToUnitVector(oct1); + } + + float3 L = LightData.Direction; // Already normalized + float3 ToLight = L; + float3 MaskedLightColor = LightData.Color;//灯光颜色 + float LightMask = 1; + // 获取辐射光源的衰减值,衰减方法根据LightData.bInverseSquared,会分别使用新版衰减方法InverseSquared 或者 旧方法。如果是SpotLight与RectLight就乘以SpotLight、RectLight对应的形状衰减数值。 + if (LightData.bRadialLight) + { + LightMask = GetLocalLightAttenuation( TranslatedWorldPosition, LightData, ToLight, L ); + MaskedLightColor *= LightMask; + } + + LightAccumulator.EstimatedCost += 0.3f; // running the PixelShader at all has a cost + + BRANCH + if( LightMask > 0 )//如果不是完全死黑就计算阴影部分逻辑 + { + FShadowTerms Shadow; + Shadow.SurfaceShadow = AmbientOcclusion;//GBuffer中的AO + Shadow.TransmissionShadow = 1; + Shadow.TransmissionThickness = 1; + Shadow.HairTransmittance.OpaqueVisibility = 1; + const float ContactShadowOpacity = GBuffer.CustomData.a;//TODO:修正ToonStandard对应的逻辑 + // + GetShadowTerms(GBuffer.Depth, GBuffer.PrecomputedShadowFactors, GBuffer.ShadingModelID, ContactShadowOpacity, + LightData, TranslatedWorldPosition, L, LightAttenuation, Dither, Shadow); + SurfaceShadow = Shadow.SurfaceShadow; + + LightAccumulator.EstimatedCost += 0.3f; // add the cost of getting the shadow terms + +#if SHADING_PATH_MOBILE + const bool bNeedsSeparateSubsurfaceLightAccumulation = UseSubsurfaceProfile(GBuffer.ShadingModelID); + + FDirectLighting Lighting = (FDirectLighting)0; + + half NoL = max(0, dot(GBuffer.WorldNormal, L)); + #if TRANSLUCENCY_NON_DIRECTIONAL + NoL = 1.0f; + #endif + Lighting = EvaluateBxDF(GBuffer, N, V, L, NoL, Shadow); + + Lighting.Specular *= LightData.SpecularScale; + + LightAccumulator_AddSplit( LightAccumulator, Lighting.Diffuse, Lighting.Specular, Lighting.Diffuse, MaskedLightColor * Shadow.SurfaceShadow, bNeedsSeparateSubsurfaceLightAccumulation ); + LightAccumulator_AddSplit( LightAccumulator, Lighting.Transmission, 0.0f, Lighting.Transmission, MaskedLightColor * Shadow.TransmissionShadow, bNeedsSeparateSubsurfaceLightAccumulation ); +#else // SHADING_PATH_MOBILE + BRANCH + if( Shadow.SurfaceShadow + Shadow.TransmissionShadow > 0 ) + { + const bool bNeedsSeparateSubsurfaceLightAccumulation = UseSubsurfaceProfile(GBuffer.ShadingModelID); + + #if NON_DIRECTIONAL_DIRECT_LIGHTING + float Lighting; + + if( LightData.bRectLight ) + { + FRect Rect = GetRect( ToLight, LightData ); + + Lighting = IntegrateLight( Rect ); + } + else + { + FCapsuleLight Capsule = GetCapsule( ToLight, LightData ); + + Lighting = IntegrateLight( Capsule, LightData.bInverseSquared ); + } + + float3 LightingDiffuse = Diffuse_Lambert( GBuffer.DiffuseColor ) * Lighting; + LightAccumulator_AddSplit(LightAccumulator, LightingDiffuse, 0.0f, 0, MaskedLightColor * Shadow.SurfaceShadow, bNeedsSeparateSubsurfaceLightAccumulation); + #else + FDirectLighting Lighting; + + if (LightData.bRectLight) + { + FRect Rect = GetRect( ToLight, LightData ); + const FRectTexture SourceTexture = ConvertToRectTexture(LightData); + + #if REFERENCE_QUALITY + Lighting = IntegrateBxDF( GBuffer, N, V, Rect, Shadow, SourceTexture, SVPos ); + #else + Lighting = IntegrateBxDF( GBuffer, N, V, Rect, Shadow, SourceTexture); + #endif + } + else + { + FCapsuleLight Capsule = GetCapsule( ToLight, LightData ); + + #if REFERENCE_QUALITY + Lighting = IntegrateBxDF( GBuffer, N, V, Capsule, Shadow, SVPos ); + #else + Lighting = IntegrateBxDF( GBuffer, N, V, Capsule, Shadow, LightData.bInverseSquared ); + #endif + } + + Lighting.Specular *= LightData.SpecularScale; + + LightAccumulator_AddSplit( LightAccumulator, Lighting.Diffuse, Lighting.Specular, Lighting.Diffuse, MaskedLightColor * Shadow.SurfaceShadow, bNeedsSeparateSubsurfaceLightAccumulation ); + LightAccumulator_AddSplit( LightAccumulator, Lighting.Transmission, 0.0f, Lighting.Transmission, MaskedLightColor * Shadow.TransmissionShadow, bNeedsSeparateSubsurfaceLightAccumulation ); + + LightAccumulator.EstimatedCost += 0.4f; // add the cost of the lighting computations (should sum up to 1 form one light) + #endif + } +#endif // SHADING_PATH_MOBILE + } + return LightAccumulator; +} +``` + +光源新衰减公式,相关计算位于`GetLocalLightAttenuation()`: +$$Falloff = \frac{saturate(1-(distance/lightRadius)^4)^2}{distance^2 + 1}$$ + +光源旧衰减公式,相关函数位于DynamicLightingCommon.ush中的`RadialAttenuation()` +$$Falloff = (1 - saturate(length(WorldLightVector)))^ {FalloffExponent}$$ +##### GetShadowTerms() +```c++ + ``` \ No newline at end of file