25 KiB
25 KiB
title, date, excerpt, tags, rating
title | date | excerpt | tags | rating |
---|---|---|---|---|
Untitled | 2025-02-11 11:30:34 | ⭐ |
FSortedLightSetSceneInfo
有序的光源集合相关定义:
/** Data for a simple dynamic light. */
class FSimpleLightEntry
{
public:
FVector3f Color;
float Radius;
float Exponent;
float InverseExposureBlend = 0.0f;
float VolumetricScatteringIntensity;
bool bAffectTranslucency;
};
struct FSortedLightSceneInfo
{
union
{
struct
{
// Note: the order of these members controls the light sort order!
// Currently bHandledByLumen is the MSB and LightType is LSB /** The type of light. */ uint32 LightType : LightType_NumBits;
/** Whether the light has a texture profile. */
uint32 bTextureProfile : 1;
/** Whether the light uses a light function. */
uint32 bLightFunction : 1;
/** Whether the light uses lighting channels. */
uint32 bUsesLightingChannels : 1;
/** Whether the light casts shadows. */
uint32 bShadowed : 1;
/** Whether the light is NOT a simple light - they always support tiled/clustered but may want to be selected separately. */
uint32 bIsNotSimpleLight : 1;
/* We want to sort the lights that write into the packed shadow mask (when enabled) to the front of the list so we don't waste slots in the packed shadow mask. */
uint32 bDoesNotWriteIntoPackedShadowMask : 1;
/**
* True if the light doesn't support clustered deferred, logic is inverted so that lights that DO support clustered deferred will sort first in list
* Super-set of lights supporting tiled, so the tiled lights will end up in the first part of this range.
*/
uint32 bClusteredDeferredNotSupported : 1;
/** Whether the light should be handled by Lumen's Final Gather, these will be sorted to the end so they can be skipped */
uint32 bHandledByLumen : 1;
} Fields;
/** Sort key bits packed into an integer. */
int32 Packed;
} SortKey;
const FLightSceneInfo* LightSceneInfo;
int32 SimpleLightIndex;
/** Initialization constructor. */
explicit FSortedLightSceneInfo(const FLightSceneInfo* InLightSceneInfo)
: LightSceneInfo(InLightSceneInfo),
SimpleLightIndex(-1)
{
SortKey.Packed = 0;
SortKey.Fields.bIsNotSimpleLight = 1;
}
explicit FSortedLightSceneInfo(int32 InSimpleLightIndex)
: LightSceneInfo(nullptr),
SimpleLightIndex(InSimpleLightIndex)
{
SortKey.Packed = 0;
SortKey.Fields.bIsNotSimpleLight = 0;
}};
/**
* Stores info about sorted lights and ranges.
* The sort-key in FSortedLightSceneInfo gives rise to the following order:
* [SimpleLights,Clustered,UnbatchedLights,LumenLights] * Note that some shadowed lights can be included in the clustered pass when virtual shadow maps and one pass projection are used. */struct FSortedLightSetSceneInfo
{
int32 SimpleLightsEnd;
int32 ClusteredSupportedEnd;
/** First light with shadow map or */
int32 UnbatchedLightStart;
int32 LumenLightStart;
FSimpleLightArray SimpleLights;
TArray<FSortedLightSceneInfo, SceneRenderingAllocator> SortedLights;
};
开始获取有序光源集合
UE的光源分配由FDeferredShadingSceneRenderer::Render
内的bComputeLightGrid
变量决定的,bComputeLightGrid的赋值逻辑如下:
void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) {
...
bool bComputeLightGrid = false;
if (RendererOutput == ERendererOutput::FinalSceneColor)
{
if (bUseVirtualTexturing)
{
// Note, should happen after the GPU-Scene update to ensure rendering to runtime virtual textures is using the correctly updated scene
FVirtualTextureSystem::Get().EndUpdate(GraphBuilder, MoveTemp(VirtualTextureUpdater), FeatureLevel);
}
#if RHI_RAYTRACING
GatherRayTracingWorldInstancesForView(GraphBuilder, ReferenceView, RayTracingScene, InitViewTaskDatas.RayTracingRelevantPrimitives);
#endif // RHI_RAYTRACING
bool bAnyLumenEnabled = false;
{
if (bUseGBuffer)
{
bComputeLightGrid = bRenderDeferredLighting;
}
else
{
bComputeLightGrid = ViewFamily.EngineShowFlags.Lighting;
}
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
FViewInfo& View = Views[ViewIndex];
bAnyLumenEnabled = bAnyLumenEnabled
|| GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen
|| GetViewPipelineState(View).ReflectionsMethod == EReflectionsMethod::Lumen;
}
bComputeLightGrid |= (
ShouldRenderVolumetricFog() ||
VolumetricCloudWantsToSampleLocalLights(Scene, ViewFamily.EngineShowFlags) ||
ViewFamily.ViewMode != VMI_Lit ||
bAnyLumenEnabled ||
VirtualShadowMapArray.IsEnabled() ||
ShouldVisualizeLightGrid());
}
}
...
}
获取有序的光源集合
void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) {
...
// 有序的光源集合.
FSortedLightSetSceneInfo& SortedLightSet = *GraphBuilder.AllocObject<FSortedLightSetSceneInfo>();
{
RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, SortLights);
RDG_GPU_STAT_SCOPE(GraphBuilder, SortLights);
ComputeLightGridOutput = GatherLightsAndComputeLightGrid(GraphBuilder, bComputeLightGrid, SortedLightSet);
}
...
}
PS. 简单光源都可以被分块或分簇渲染,但对于非简单光源,只有满足以下条件的光源才可被分块或分簇渲染:
- 没有使用光源的附加特性(TextureProfile、LightFunction、LightingChannel)。
- 没有开启阴影。
- 非平行光或矩形光。
另外,是否支持分块渲染,还需要光源场景代理的IsTiledDeferredLightingSupported
返回true,长度为0的点光源才支持分块渲染。
GatherLightsAndComputeLightGrid
FComputeLightGridOutput FDeferredShadingSceneRenderer::GatherLightsAndComputeLightGrid(FRDGBuilder& GraphBuilder, bool bNeedLightGrid, FSortedLightSetSceneInfo& SortedLightSet)
{
SCOPED_NAMED_EVENT(GatherLightsAndComputeLightGrid, FColor::Emerald);
FComputeLightGridOutput Result = {};
bool bShadowedLightsInClustered = ShouldUseClusteredDeferredShading()
&& CVarVirtualShadowOnePassProjection.GetValueOnRenderThread()
&& VirtualShadowMapArray.IsEnabled();
const bool bUseLumenDirectLighting = ShouldRenderLumenDirectLighting(Scene, Views[0]);
GatherAndSortLights(SortedLightSet, bShadowedLightsInClustered, bUseLumenDirectLighting);
if (!bNeedLightGrid)
{
SetDummyForwardLightUniformBufferOnViews(GraphBuilder, ShaderPlatform, Views);
return Result;
}
bool bAnyViewUsesForwardLighting = false;
bool bAnyViewUsesLumen = false;
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
bAnyViewUsesForwardLighting |= View.bTranslucentSurfaceLighting || ShouldRenderVolumetricFog() || View.bHasSingleLayerWaterMaterial || VolumetricCloudWantsToSampleLocalLights(Scene, ViewFamily.EngineShowFlags) || ShouldVisualizeLightGrid();
bAnyViewUsesLumen |= GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen || GetViewPipelineState(View).ReflectionsMethod == EReflectionsMethod::Lumen;
}
const bool bCullLightsToGrid = GLightCullingQuality
&& (IsForwardShadingEnabled(ShaderPlatform) || bAnyViewUsesForwardLighting || IsRayTracingEnabled() || ShouldUseClusteredDeferredShading() ||
bAnyViewUsesLumen || ViewFamily.EngineShowFlags.VisualizeMeshDistanceFields || VirtualShadowMapArray.IsEnabled());
// Store this flag if lights are injected in the grids, check with 'AreLightsInLightGrid()'
bAreLightsInLightGrid = bCullLightsToGrid;
Result = ComputeLightGrid(GraphBuilder, bCullLightsToGrid, SortedLightSet);
return Result;
}
- GatherAndSortLights:收集与排序当前场景中所有的可见光源(当前View)。
- ComputeLightGrid:是在锥体空间(frustum space)裁剪局部光源和反射探针到3D格子中,构建每个视图相关的光源列表和格子。
RenderLights() -> RenderLight()
InternalRenderLight()
DeferredLightVertexShaders
// 输入参数.
struct FInputParams
{
float2 PixelPos;
float4 ScreenPosition;
float2 ScreenUV;
float3 ScreenVector;
};
// 派生参数.
struct FDerivedParams
{
float3 CameraVector;
float3 WorldPosition;
};
// 获取派生参数.
FDerivedParams GetDerivedParams(in FInputParams Input, in float SceneDepth)
{
FDerivedParams Out;
#if LIGHT_SOURCE_SHAPE > 0
// With a perspective projection, the clip space position is NDC * Clip.w
// With an orthographic projection, clip space is the same as NDC
float2 ClipPosition = Input.ScreenPosition.xy / Input.ScreenPosition.w * (View.ViewToClip[3][3] < 1.0f ? SceneDepth : 1.0f);
Out.WorldPosition = mul(float4(ClipPosition, SceneDepth, 1), View.ScreenToWorld).xyz;
Out.CameraVector = normalize(Out.WorldPosition - View.WorldCameraOrigin);
#else
Out.WorldPosition = Input.ScreenVector * SceneDepth + View.WorldCameraOrigin;
Out.CameraVector = normalize(Input.ScreenVector);
#endif
return Out;
}
Texture2D<uint> LightingChannelsTexture;
uint GetLightingChannelMask(float2 UV)
{
uint2 IntegerUV = UV * View.BufferSizeAndInvSize.xy;
return LightingChannelsTexture.Load(uint3(IntegerUV, 0)).x;
}
float GetExposure()
{
return View.PreExposure;
}
向往文章中的SetupLightDataForStandardDeferred()变为InitDeferredLightFromUniforms()。位于LightDataUniform.ush。
FDeferredLightData InitDeferredLightFromUniforms(uint InLightType)
{
const bool bIsRadial = InLightType != LIGHT_TYPE_DIRECTIONAL;
FDeferredLightData Out;
Out.TranslatedWorldPosition = GetDeferredLightTranslatedWorldPosition();
Out.InvRadius = DeferredLightUniforms.InvRadius;
Out.Color = DeferredLightUniforms.Color;
Out.FalloffExponent = DeferredLightUniforms.FalloffExponent;
Out.Direction = DeferredLightUniforms.Direction;
Out.Tangent = DeferredLightUniforms.Tangent;
Out.SpotAngles = DeferredLightUniforms.SpotAngles;
Out.SourceRadius = DeferredLightUniforms.SourceRadius;
Out.SourceLength = bIsRadial ? DeferredLightUniforms.SourceLength : 0;
Out.SoftSourceRadius = DeferredLightUniforms.SoftSourceRadius;
Out.SpecularScale = DeferredLightUniforms.SpecularScale;
Out.ContactShadowLength = abs(DeferredLightUniforms.ContactShadowLength);
Out.ContactShadowLengthInWS = DeferredLightUniforms.ContactShadowLength < 0.0f;
Out.ContactShadowCastingIntensity = DeferredLightUniforms.ContactShadowCastingIntensity;
Out.ContactShadowNonCastingIntensity = DeferredLightUniforms.ContactShadowNonCastingIntensity;
Out.DistanceFadeMAD = DeferredLightUniforms.DistanceFadeMAD;
Out.ShadowMapChannelMask = DeferredLightUniforms.ShadowMapChannelMask;
Out.ShadowedBits = DeferredLightUniforms.ShadowedBits;
Out.bInverseSquared = bIsRadial && DeferredLightUniforms.FalloffExponent == 0; // Directional lights don't use 'inverse squared attenuation'
Out.bRadialLight = bIsRadial;
Out.bSpotLight = InLightType == LIGHT_TYPE_SPOT;
Out.bRectLight = InLightType == LIGHT_TYPE_RECT;
Out.RectLightData.BarnCosAngle = DeferredLightUniforms.RectLightBarnCosAngle;
Out.RectLightData.BarnLength = DeferredLightUniforms.RectLightBarnLength;
Out.RectLightData.AtlasData.AtlasMaxLevel = DeferredLightUniforms.RectLightAtlasMaxLevel;
Out.RectLightData.AtlasData.AtlasUVOffset = DeferredLightUniforms.RectLightAtlasUVOffset;
Out.RectLightData.AtlasData.AtlasUVScale = DeferredLightUniforms.RectLightAtlasUVScale;
Out.HairTransmittance = InitHairTransmittanceData();
return Out;
}
DeferredLightPixelMain
void DeferredLightPixelMain(
#if LIGHT_SOURCE_SHAPE > 0
float4 InScreenPosition : TEXCOORD0,
#else
float2 ScreenUV : TEXCOORD0,
float3 ScreenVector : TEXCOORD1,
#endif
float4 SVPos : SV_POSITION,
out float4 OutColor : SV_Target0
#if STRATA_OPAQUE_ROUGH_REFRACTION_ENABLED
, out float3 OutOpaqueRoughRefractionSceneColor : SV_Target1
, out float3 OutSubSurfaceSceneColor : SV_Target2
#endif
)
{
const float2 PixelPos = SVPos.xy;
OutColor = 0;
#if STRATA_OPAQUE_ROUGH_REFRACTION_ENABLED
OutOpaqueRoughRefractionSceneColor = 0;
OutSubSurfaceSceneColor = 0;
#endif
// Convert input data (directional/local light)
// 计算屏幕UV
FInputParams InputParams = (FInputParams)0;
InputParams.PixelPos = SVPos.xy;
#if LIGHT_SOURCE_SHAPE > 0
InputParams.ScreenPosition = InScreenPosition;
InputParams.ScreenUV = InScreenPosition.xy / InScreenPosition.w * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz;
InputParams.ScreenVector = 0;
#else
InputParams.ScreenPosition = 0;
InputParams.ScreenUV = ScreenUV;
InputParams.ScreenVector = ScreenVector;
#endif
#if STRATA_ENABLED
FStrataAddressing StrataAddressing = GetStrataPixelDataByteOffset(PixelPos, uint2(View.BufferSizeAndInvSize.xy), Strata.MaxBytesPerPixel);
FStrataPixelHeader StrataPixelHeader = UnpackStrataHeaderIn(Strata.MaterialTextureArray, StrataAddressing, Strata.TopLayerTexture);
BRANCH
if (StrataPixelHeader.BSDFCount > 0 // This test is also enough to exclude sky pixels
#if USE_LIGHTING_CHANNELS
//灯光通道逻辑
&& (GetLightingChannelMask(InputParams.ScreenUV) & DeferredLightUniforms.LightingChannelMask)
#endif
)
{
//通过SceneDepth获取的CameraVector以及当前像素的世界坐标
const float SceneDepth = CalcSceneDepth(InputParams.ScreenUV);
const FDerivedParams DerivedParams = GetDerivedParams(InputParams, SceneDepth);
//设置获取光源各种信息
FDeferredLightData LightData = InitDeferredLightFromUniforms(CURRENT_LIGHT_TYPE);
UpdateLightDataColor(LightData, InputParams, DerivedParams);//根据当前世界坐标计算LightData.Color *= 大气&云&阴影的衰减值 * IES灯亮度(非IES灯数值为1)
float3 V =-DerivedParams.CameraVector;
float3 L = LightData.Direction; // Already normalized
float3 ToLight = L;
float LightMask = 1;
if (LightData.bRadialLight)
{
LightMask = GetLocalLightAttenuation(DerivedParams.TranslatedWorldPosition, LightData, ToLight, L);
}
if (LightMask > 0)
{
FShadowTerms ShadowTerms = { StrataGetAO(StrataPixelHeader), 1.0, 1.0, InitHairTransmittanceData() };
float4 LightAttenuation = GetLightAttenuationFromShadow(InputParams, SceneDepth);
float Dither = InterleavedGradientNoise(InputParams.PixelPos, View.StateFrameIndexMod8);
const uint FakeShadingModelID = 0;
const float FakeContactShadowOpacity = 1.0f;
float4 PrecomputedShadowFactors = StrataReadPrecomputedShadowFactors(StrataPixelHeader, PixelPos, SceneTexturesStruct.GBufferETexture);
GetShadowTerms(SceneDepth, PrecomputedShadowFactors, FakeShadingModelID, FakeContactShadowOpacity,
LightData, DerivedParams.TranslatedWorldPosition, L, LightAttenuation, Dither, ShadowTerms);
FStrataDeferredLighting StrataLighting = StrataDeferredLighting(
LightData,
V,
L,
ToLight,
LightMask,
ShadowTerms,
Strata.MaterialTextureArray,
StrataAddressing,
StrataPixelHeader);
OutColor += StrataLighting.SceneColor;
#if STRATA_OPAQUE_ROUGH_REFRACTION_ENABLED
OutOpaqueRoughRefractionSceneColor += StrataLighting.OpaqueRoughRefractionSceneColor;
OutSubSurfaceSceneColor += StrataLighting.SubSurfaceSceneColor;
#endif
}
}
#else // STRATA_ENABLED
//取得屏幕空间数据(FGbufferData、AO)
FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(InputParams.ScreenUV);
// Only light pixels marked as using deferred shading
BRANCH if (ScreenSpaceData.GBuffer.ShadingModelID > 0
#if USE_LIGHTING_CHANNELS
&& (GetLightingChannelMask(InputParams.ScreenUV) & DeferredLightUniforms.LightingChannelMask)
#endif
)
{
//通过SceneDepth获取的CameraVector以及当前像素的世界坐标
const float SceneDepth = CalcSceneDepth(InputParams.ScreenUV);
const FDerivedParams DerivedParams = GetDerivedParams(InputParams, SceneDepth);
//设置获取光源各种信息
FDeferredLightData LightData = InitDeferredLightFromUniforms(CURRENT_LIGHT_TYPE);
UpdateLightDataColor(LightData, InputParams, DerivedParams);//根据当前世界坐标计算LightData.Color *= 大气&云&阴影的衰减值 * IES灯亮度(非IES灯数值为1)
#if USE_HAIR_COMPLEX_TRANSMITTANCE
//针对ShadingModel Hair(同时需要CustomData.a > 0)计算头发散射结果
if (ScreenSpaceData.GBuffer.ShadingModelID == SHADINGMODELID_HAIR && ShouldUseHairComplexTransmittance(ScreenSpaceData.GBuffer))
{
LightData.HairTransmittance = EvaluateDualScattering(ScreenSpaceData.GBuffer, DerivedParams.CameraVector, -DeferredLightUniforms.Direction);
}
#endif
//计算当前像素的抖动值
float Dither = InterleavedGradientNoise(InputParams.PixelPos, View.StateFrameIndexMod8);
float SurfaceShadow = 1.0f;
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;
}
#endif // STRATA_ENABLED
// RGB:SceneColor Specular and Diffuse
// A:Non Specular SceneColor Luminance
// So we need PreExposure for both color and alpha
OutColor.rgba *= GetExposure();
#if STRATA_OPAQUE_ROUGH_REFRACTION_ENABLED
// Idem
OutOpaqueRoughRefractionSceneColor *= GetExposure();
OutSubSurfaceSceneColor *= GetExposure();
#endif
}
#endif
GetDynamicLighting() => GetDynamicLightingSplit()
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);
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
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()