DeferredLightPixelShader.usf里,ps执行的main函数:
```
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
)
{
OutColor = 0;
#if LIGHT_SOURCE_SHAPE > 0
float2 ScreenUV = InScreenPosition.xy / InScreenPosition.w * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz;
#else
float3 CameraVector = normalize(ScreenVector);
#endif
FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(ScreenUV);
// Only light pixels marked as using deferred shading
BRANCH if( ScreenSpaceData.GBuffer.ShadingModelID > 0
#if USE_LIGHTING_CHANNELS
&& (GetLightingChannelMask(ScreenUV) & DeferredLightUniforms.LightingChannelMask)
#endif
)
{
float SceneDepth = CalcSceneDepth(ScreenUV);
#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 = InScreenPosition.xy / InScreenPosition.w * (View.ViewToClip[3][3] < 1.0f ? SceneDepth : 1.0f);
float3 WorldPosition = mul(float4(ClipPosition, SceneDepth, 1), View.ScreenToWorld).xyz;
float3 CameraVector = normalize(WorldPosition - View.WorldCameraOrigin);
#else
float3 WorldPosition = ScreenVector * SceneDepth + View.WorldCameraOrigin;
#endif
FDeferredLightData LightData = SetupLightDataForStandardDeferred(); //获得light direction, light color, falloff等数据
float Dither = InterleavedGradientNoise( SVPos.xy, View.StateFrameIndexMod8 );
FRectTexture RectTexture = InitRectTexture(DeferredLightUniforms.SourceTexture);
// 核心函数
OutColor = GetDynamicLighting(WorldPosition, CameraVector, ScreenSpaceData.GBuffer, ScreenSpaceData.AmbientOcclusion, ScreenSpaceData.GBuffer.ShadingModelID, LightData, GetPerPixelLightAttenuation(ScreenUV), Dither, uint2( SVPos.xy ), RectTexture);
OutColor *= ComputeLightProfileMultiplier(WorldPosition, DeferredLightUniforms.Position, -DeferredLightUniforms.Direction, DeferredLightUniforms.Tangent);
#if USE_PREEXPOSURE
OutColor *= View.PreExposure;
#endif
}
}
```
SetupLightDataForStandardDeferred函数也在DeferredLightPixelShader.usf里,根据cpp传过来的DegerredLightUniforms这个结构,填充FDeferredLightData这个结构:
```
FDeferredLightData SetupLightDataForStandardDeferred()
{
// Build the light data struct using the DeferredLightUniforms and light defines
// We are heavily relying on the shader compiler to optimize out constant subexpressions in GetDynamicLighting()
FDeferredLightData LightData;
LightData.Position = DeferredLightUniforms.Position;
LightData.InvRadius = DeferredLightUniforms.InvRadius;
LightData.Color = DeferredLightUniforms.Color;
LightData.FalloffExponent = DeferredLightUniforms.FalloffExponent;
LightData.Direction = DeferredLightUniforms.Direction;
LightData.Tangent = DeferredLightUniforms.Tangent;
LightData.SpotAngles = DeferredLightUniforms.SpotAngles;
LightData.SourceRadius = DeferredLightUniforms.SourceRadius,
LightData.SourceLength = DeferredLightUniforms.SourceLength;
LightData.SoftSourceRadius = DeferredLightUniforms.SoftSourceRadius;
LightData.SpecularScale = DeferredLightUniforms.SpecularScale;
LightData.ContactShadowLength = abs(DeferredLightUniforms.ContactShadowLength);
LightData.ContactShadowLengthInWS = DeferredLightUniforms.ContactShadowLength < 0.0f;
LightData.DistanceFadeMAD = DeferredLightUniforms.DistanceFadeMAD;
LightData.ShadowMapChannelMask = DeferredLightUniforms.ShadowMapChannelMask;
LightData.ShadowedBits = DeferredLightUniforms.ShadowedBits;
LightData.bInverseSquared = INVERSE_SQUARED_FALLOFF;
LightData.bRadialLight = LIGHT_SOURCE_SHAPE > 0; //非平行光
//@todo - permutation opportunity
LightData.bSpotLight = LIGHT_SOURCE_SHAPE > 0;
LightData.bRectLight = LIGHT_SOURCE_SHAPE == 2;
LightData.RectLightBarnCosAngle = DeferredLightUniforms.RectLightBarnCosAngle;
LightData.RectLightBarnLength = DeferredLightUniforms.RectLightBarnLength;
return LightData;
}
```
这个结构FDeferredLightData的定义在DeferredLightingCommon.ush文件中:
```
struct FDeferredLightData
{
float3 Position;
float InvRadius;
float3 Color;
float FalloffExponent;
float3 Direction;
float3 Tangent;
float SoftSourceRadius;
float2 SpotAngles;
float SourceRadius;
float SourceLength;
float SpecularScale;
float ContactShadowLength;
float2 DistanceFadeMAD;
float4 ShadowMapChannelMask;
/** Whether ContactShadowLength is in World Space or in Screen Space. */
bool ContactShadowLengthInWS;
/** Whether to use inverse squared falloff. */
bool bInverseSquared;
/** Whether this is a light with radial attenuation, aka point or spot light. */
bool bRadialLight;
/** Whether this light needs spotlight attenuation. */
bool bSpotLight;
bool bRectLight;
/** Whether the light should apply shadowing. */
uint ShadowedBits;
float RectLightBarnCosAngle;
float RectLightBarnLength;
};
```
cpu传过来的DeferredLightUniforms结构,对应的是cpu端的FDeferredLightUniformStruct结构。
另外这个结构的定义:
```
BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FDeferredLightUniformStruct,)
SHADER_PARAMETER(FVector4,ShadowMapChannelMask)
SHADER_PARAMETER(FVector2D,DistanceFadeMAD)
SHADER_PARAMETER(float, ContactShadowLength)
SHADER_PARAMETER(float, VolumetricScatteringIntensity)
SHADER_PARAMETER(uint32,ShadowedBits)
SHADER_PARAMETER(uint32,LightingChannelMask)
SHADER_PARAMETER_STRUCT_INCLUDE(FLightShaderParameters, LightParameters)
END_GLOBAL_SHADER_PARAMETER_STRUCT()
```
```
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FDeferredLightUniformStruct, "DeferredLightUniforms");
```
在LightRendering.cpp文件中,FDeferredLightPS:
```
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FLightSceneInfo* LightSceneInfo, IPooledRenderTarget* ScreenShadowMaskTexture)
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
SetParametersBase(RHICmdList, ShaderRHI, View, ScreenShadowMaskTexture, LightSceneInfo->Proxy->GetIESTextureResource());
SetDeferredLightParameters(RHICmdList, ShaderRHI, GetUniformBufferParameter<FDeferredLightUniformStruct>(), LightSceneInfo, View);
}
```
另外, TDeferredLightOverlapPS 类里也有设置参数。
```
template<typename ShaderRHIParamRef>
void SetDeferredLightParameters(
FRHICommandList& RHICmdList,
const ShaderRHIParamRef ShaderRHI,
const TShaderUniformBufferParameter<FDeferredLightUniformStruct>& DeferredLightUniformBufferParameter,
const FLightSceneInfo* LightSceneInfo,
const FSceneView& View)
{
FDeferredLightUniformStruct DeferredLightUniformsValue;
LightSceneInfo->Proxy->GetLightShaderParameters(DeferredLightUniformsValue.LightParameters);
const FVector2D FadeParams = LightSceneInfo->Proxy->GetDirectionalLightDistanceFadeParameters(View.GetFeatureLevel(), LightSceneInfo->IsPrecomputedLightingValid(), View.MaxShadowCascades);
// use MAD for efficiency in the shader
DeferredLightUniformsValue.DistanceFadeMAD = FVector2D(FadeParams.Y, -FadeParams.X * FadeParams.Y);
int32 ShadowMapChannel = LightSceneInfo->Proxy->GetShadowMapChannel();
static const auto AllowStaticLightingVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting"));
const bool bAllowStaticLighting = (!AllowStaticLightingVar || AllowStaticLightingVar->GetValueOnRenderThread() != 0);
if (!bAllowStaticLighting)
{
ShadowMapChannel = INDEX_NONE;
}
DeferredLightUniformsValue.ShadowMapChannelMask = FVector4(
ShadowMapChannel == 0 ? 1 : 0,
ShadowMapChannel == 1 ? 1 : 0,
ShadowMapChannel == 2 ? 1 : 0,
ShadowMapChannel == 3 ? 1 : 0);
const bool bDynamicShadows = View.Family->EngineShowFlags.DynamicShadows && GetShadowQuality() > 0;
const bool bHasLightFunction = LightSceneInfo->Proxy->GetLightFunctionMaterial() != NULL;
DeferredLightUniformsValue.ShadowedBits = LightSceneInfo->Proxy->CastsStaticShadow() || bHasLightFunction ? 1 : 0;
DeferredLightUniformsValue.ShadowedBits |= LightSceneInfo->Proxy->CastsDynamicShadow() && View.Family->EngineShowFlags.DynamicShadows ? 3 : 0;
DeferredLightUniformsValue.VolumetricScatteringIntensity = LightSceneInfo->Proxy->GetVolumetricScatteringIntensity();
static auto* ContactShadowsCVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ContactShadows"));
DeferredLightUniformsValue.ContactShadowLength = 0;
if (ContactShadowsCVar && ContactShadowsCVar->GetValueOnRenderThread() != 0 && View.Family->EngineShowFlags.ContactShadows)
{
DeferredLightUniformsValue.ContactShadowLength = LightSceneInfo->Proxy->GetContactShadowLength();
// Sign indicates if contact shadow length is in world space or screen space.
// Multiply by 2 for screen space in order to preserve old values after introducing multiply by View.ClipToView[1][1] in shader.
DeferredLightUniformsValue.ContactShadowLength *= LightSceneInfo->Proxy->IsContactShadowLengthInWS() ? -1.0f : 2.0f;
}
// When rendering reflection captures, the direct lighting of the light is actually the indirect specular from the main view
if (View.bIsReflectionCapture)
{
DeferredLightUniformsValue.LightParameters.Color *= LightSceneInfo->Proxy->GetIndirectLightingScale();
}
const ELightComponentType LightType = (ELightComponentType)LightSceneInfo->Proxy->GetLightType();
if ((LightType == LightType_Point || LightType == LightType_Spot || LightType == LightType_Rect) && View.IsPerspectiveProjection())
{
DeferredLightUniformsValue.LightParameters.Color *= GetLightFadeFactor(View, LightSceneInfo->Proxy);
}
DeferredLightUniformsValue.LightingChannelMask = LightSceneInfo->Proxy->GetLightingChannelMask();
SetUniformBufferParameterImmediate(RHICmdList, ShaderRHI,DeferredLightUniformBufferParameter,DeferredLightUniformsValue);
}
```
分析上面函数LightSceneInfo->Proxy->GetLightShaderParameters(DeferredLightUniformsValue.LightParameters);
这个FLightShaderParameters又是一个结构:
```
/** Shader paraneter structure for rendering lights. */
BEGIN_SHADER_PARAMETER_STRUCT(FLightShaderParameters, ENGINE_API)
// Position of the light in the world space.
SHADER_PARAMETER(FVector, Position)
// 1 / light's falloff radius from Position.
SHADER_PARAMETER(float, InvRadius)
// Color of the light.
SHADER_PARAMETER(FVector, Color)
// The exponent for the falloff of the light intensity from the distance.
SHADER_PARAMETER(float, FalloffExponent)
// Direction of the light if applies.
SHADER_PARAMETER(FVector, Direction)
// Factor to applies on the specular.
SHADER_PARAMETER(float, SpecularScale)
// One tangent of the light if applies.
// Note: BiTangent is on purpose not stored for memory optimisation purposes.
SHADER_PARAMETER(FVector, Tangent)
// Radius of the point light.
SHADER_PARAMETER(float, SourceRadius)
// Dimensions of the light, for spot light, but also
SHADER_PARAMETER(FVector2D, SpotAngles)
// Radius of the soft source.
SHADER_PARAMETER(float, SoftSourceRadius)
// Other dimensions of the light source for rect light specifically.
SHADER_PARAMETER(float, SourceLength)
// Barn door angle for rect light
SHADER_PARAMETER(float, RectLightBarnCosAngle)
// Barn door length for rect light
SHADER_PARAMETER(float, RectLightBarnLength)
// Texture of the rect light.
SHADER_PARAMETER_TEXTURE(Texture2D, SourceTexture)
END_SHADER_PARAMETER_STRUCT()
```
不同的光照proxy设置这个参数的函数是虚函数,平行光的:
```
virtual void GetLightShaderParameters(FLightShaderParameters& LightParameters) const override
{
LightParameters.Position = FVector::ZeroVector;
LightParameters.InvRadius = 0.0f;
LightParameters.Color = FVector(GetColor());
LightParameters.FalloffExponent = 0.0f;
LightParameters.Direction = -GetDirection();
LightParameters.Tangent = -GetDirection();
LightParameters.SpotAngles = FVector2D(0, 0);
LightParameters.SpecularScale = SpecularScale;
LightParameters.SourceRadius = FMath::Sin( 0.5f * FMath::DegreesToRadians( LightSourceAngle ) );
LightParameters.SoftSourceRadius = FMath::Sin( 0.5f * FMath::DegreesToRadians( LightSourceSoftAngle ) );
LightParameters.SourceLength = 0.0f;
LightParameters.SourceTexture = GWhiteTexture->TextureRHI;
}
```
继续看
FLightSceneInfo::FLightSceneInfo(FLightSceneProxy* InProxy, bool InbVisible)
: Proxy(InProxy)
, DynamicInteractionOftenMovingPrimitiveList(NULL)
, DynamicInteractionStaticPrimitiveList(NULL)
, Id(INDEX_NONE)
, TileIntersectionResources(nullptr)
, DynamicShadowMapChannel(-1)
, bPrecomputedLightingIsValid(InProxy->GetLightComponent()->IsPrecomputedLightingValid())
```
bool ULightComponent::IsPrecomputedLightingValid() const
{
return GetLightComponentMapBuildData() != NULL && HasStaticShadowing();
}
```
ULevel类里包含UMapBuildDataRegistry* MapBuildData;
他能根据lightId找light对应的buildData:
```
FLightComponentMapBuildData* UMapBuildDataRegistry::GetLightBuildData(FGuid LightId)
{
return LightBuildData.Find(LightId);
}
```
```
class FLightComponentMapBuildData
{
public:
FLightComponentMapBuildData() :
ShadowMapChannel(INDEX_NONE)
{}
ENGINE_API ~FLightComponentMapBuildData();
ENGINE_API void FinalizeLoad();
/**
* Shadow map channel which is used to match up with the appropriate static shadowing during a deferred shading pass.
* This is generated during a lighting build.
*/
int32 ShadowMapChannel;
FStaticShadowDepthMapData DepthMap;
friend FArchive& operator<<(FArchive& Ar, FLightComponentMapBuildData& ShadowMap);
};
```
Depthmap定义:
```
class FStaticShadowDepthMapData
{
public:
/** Transform from world space to the coordinate space that DepthSamples are stored in. */
FMatrix WorldToLight;
/** Dimensions of the generated shadow map. */
int32 ShadowMapSizeX;
int32 ShadowMapSizeY;
/** Shadowmap depth values */
TArray<FFloat16> DepthSamples;
FStaticShadowDepthMapData() :
WorldToLight(FMatrix::Identity),
ShadowMapSizeX(0),
ShadowMapSizeY(0)
{}
ENGINE_API void Empty();
size_t GetAllocatedSize() const
{
return DepthSamples.GetAllocatedSize();
}
friend FArchive& operator<<(FArchive& Ar, FStaticShadowDepthMapData& ShadowMap);
};
```
继续看这个
const FVector2D FadeParams = LightSceneInfo->Proxy->GetDirectionalLightDistanceFadeParameters(View.GetFeatureLevel(), LightSceneInfo->IsPrecomputedLightingValid(), View.MaxShadowCascades);
```
virtual FVector2D GetDirectionalLightDistanceFadeParameters(ERHIFeatureLevel::Type InFeatureLevel, bool bPrecomputedLightingIsValid, int32 MaxNearCascades) const override
{
float FarDistance = GetCSMMaxDistance(bPrecomputedLightingIsValid, MaxNearCascades);
{
if (ShouldCreateRayTracedCascade(InFeatureLevel, bPrecomputedLightingIsValid, MaxNearCascades)) //断电显示为false
{
FarDistance = GetDistanceFieldShadowDistance();
}
FarDistance = FMath::Max(FarDistance, FarShadowDistance); //farDistance断电
}
// The far distance for the dynamic to static fade is the range of the directional light.
// The near distance is placed at a depth of 90% of the light's range.
const float NearDistance = FarDistance - FarDistance * ( ShadowDistanceFadeoutFraction * CVarCSMShadowDistanceFadeoutMultiplier.GetValueOnAnyThread() );
return FVector2D(NearDistance, 1.0f / FMath::Max<float>(FarDistance - NearDistance, KINDA_SMALL_NUMBER));
}
```
动态物体最远距离到静态渐隐是平行光的范围。近距离是光范围大约90%处。
FDirectionalLightSceneProxy类里的WholeSceneDynamicShadowRadius就是平行光上输入的
```
WholeSceneDynamicShadowRadius = Component->DynamicShadowDistanceStationaryLight;
```
```
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=CascadedShadowMaps, meta=(UIMin = "0", UIMax = "20000", DisplayName = "Dynamic Shadow Distance StationaryLight"))
float DynamicShadowDistanceStationaryLight;
```
如果cascade数目小于等于0,返回0,否则,返回阴影的scale*最大距离(如果预先烘焙了,就是编辑器那里设的,否则是命令行设的)
```
float GetCSMMaxDistance(bool bPrecomputedLightingIsValid, int32 MaxShadowCascades) const
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("r.Shadow.DistanceScale"));
if (MaxShadowCascades <= 0)
{
return 0.0f;
}
float Scale = FMath::Clamp(CVar->GetValueOnRenderThread(), 0.0f, 2.0f);
float Distance = GetEffectiveWholeSceneDynamicShadowRadius(bPrecomputedLightingIsValid) * Scale;
return Distance;
}
```
```
float GetEffectiveWholeSceneDynamicShadowRadius(bool bPrecomputedLightingIsValid) const
{
return bPrecomputedLightingIsValid ? WholeSceneDynamicShadowRadius : CVarUnbuiltWholeSceneDynamicShadowRadius.GetValueOnAnyThread();
}
```
```
virtual bool ShouldCreateRayTracedCascade(ERHIFeatureLevel::Type InFeatureLevel, bool bPrecomputedLightingIsValid, int32 MaxNearCascades) const override
{
const uint32 NumCascades = GetNumShadowMappedCascades(MaxNearCascades, bPrecomputedLightingIsValid);
const float RayTracedShadowDistance = GetDistanceFieldShadowDistance();
const bool bCreateWithCSM = NumCascades > 0 && RayTracedShadowDistance > GetCSMMaxDistance(bPrecomputedLightingIsValid, MaxNearCascades);
const bool bCreateWithoutCSM = NumCascades == 0 && RayTracedShadowDistance > 0;
return DoesPlatformSupportDistanceFieldShadowing(GShaderPlatformForFeatureLevel[InFeatureLevel]) && (bCreateWithCSM || bCreateWithoutCSM);
}
```
```
static TAutoConsoleVariable<int32> CVarMaxMobileShadowCascades(
TEXT("r.Shadow.CSM.MaxMobileCascades"),
2,
TEXT("The maximum number of cascades with which to render dynamic directional light shadows when using the mobile renderer."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
```
```
uint32 GetNumShadowMappedCascades(uint32 MaxShadowCascades, bool bPrecomputedLightingIsValid) const
{
int32 EffectiveNumDynamicShadowCascades = DynamicShadowCascades; //component编辑器输入的最大cascade数目
if (!bPrecomputedLightingIsValid) //如果没有烘焙
{
EffectiveNumDynamicShadowCascades = FMath::Max(0, CVarUnbuiltNumWholeSceneDynamicShadowCascades.GetValueOnAnyThread());
static const auto CVarUnbuiltPreviewShadowsInGame = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.UnbuiltPreviewInGame"));
bool bUnbuiltPreviewShadowsInGame = CVarUnbuiltPreviewShadowsInGame->GetInt() != 0;
if (!bUnbuiltPreviewShadowsInGame && !GetSceneInterface()->IsEditorScene())
{
EffectiveNumDynamicShadowCascades = 0;
}
}
const int32 NumCascades = GetCSMMaxDistance(bPrecomputedLightingIsValid, MaxShadowCascades) > 0.0f ? EffectiveNumDynamicShadowCascades : 0;
return FMath::Min<int32>(NumCascades, MaxShadowCascades);
}
```
```
float GetCSMMaxDistance(bool bPrecomputedLightingIsValid, int32 MaxShadowCascades) const
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("r.Shadow.DistanceScale"));
if (MaxShadowCascades <= 0)
{
return 0.0f;
}
float Scale = FMath::Clamp(CVar->GetValueOnRenderThread(), 0.0f, 2.0f); //不同等级,scale变化
float Distance = GetEffectiveWholeSceneDynamicShadowRadius(bPrecomputedLightingIsValid) * Scale;
return Distance;
}
```
```
float GetEffectiveWholeSceneDynamicShadowRadius(bool bPrecomputedLightingIsValid) const
{
return bPrecomputedLightingIsValid ? WholeSceneDynamicShadowRadius : CVarUnbuiltWholeSceneDynamicShadowRadius.GetValueOnAnyThread();//wholeScene是编辑器输入的
}
```
FadeParameter
FVector2D(NearDistance, 1.0f / FMath::Max<float>(FarDistance - NearDistance, KINDA_SMALL_NUMBER))。
然后赋值:
```
DeferredLightUniformsValue.DistanceFadeMAD = FVector2D(FadeParams.Y, -FadeParams.X * FadeParams.Y);
```
```
int32 ShadowMapChannel = LightSceneInfo->Proxy->GetShadowMapChannel(); //烘焙的mapBuildData的ShadowmapChannel
```
if (MapBuildData && bStaticShadowing && !bStaticLighting)
{
ShadowMapChannel = MapBuildData->ShadowMapChannel;
}
else
{
ShadowMapChannel = INDEX_NONE;
}
```
DeferredLightUniformsValue.ShadowMapChannelMask = FVector4(
ShadowMapChannel == 0 ? 1 : 0,
ShadowMapChannel == 1 ? 1 : 0,
ShadowMapChannel == 2 ? 1 : 0,
ShadowMapChannel == 3 ? 1 : 0);
```
如果勾选了投射阴影,投射动态阴影,则ShadowedBits为3.
得到contactShadows的值
DeferredLight Vertex Shader.usf中Directional Vertex Main函数中,
```
/** Vertex shader for rendering a directional light using a full screen quad. */
void DirectionalVertexMain(
in float2 InPosition : ATTRIBUTE0,
in float2 InUV : ATTRIBUTE1,
out float2 OutTexCoord : TEXCOORD0,
out float3 OutScreenVector : TEXCOORD1,
out float4 OutPosition : SV_POSITION
)
{
DrawRectangle(float4(InPosition.xy, 0, 1), InUV, OutPosition, OutTexCoord);
OutScreenVector = mul(float4(OutPosition.xy, 1, 0), View.ScreenToTranslatedWorld).xyz;
}
```
其他光是这个函数:
```
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4
/** Vertex shader for rendering a point or spot light using approximate bounding geometry. */
void RadialVertexMain(
in uint InVertexId : SV_VertexID,
in float3 InPosition : ATTRIBUTE0,
out float4 OutScreenPosition : TEXCOORD0,
out float4 OutPosition : SV_POSITION
)
{
```
光源类型
```
enum class ELightSourceShape
{
Directional,
Capsule,
Rect,
MAX
};
```
GetDynamicLighting函数里阴影相关:
```
FShadowTerms Shadow;
Shadow.SurfaceShadow = AmbientOcclusion;
Shadow.TransmissionShadow = 1;
Shadow.TransmissionThickness = 1;
GetShadowTerms(GBuffer, LightData, WorldPosition, L, LightAttenuation, Dither, Shadow);
```
```
struct FShadowTerms
{
float SurfaceShadow;
float TransmissionShadow;
float TransmissionThickness;
};
```
LightRendering.cpp文件中,RenderLight函数中,设置的blendState
```
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One>::GetRHI();
//GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_DestColor, BF_Zero, BO_Add, BF_DestAlpha, BF_Zero>::GetRHI();
```
// for quads, write RGB, RGB = src.rgb * 1 + dst.rgb * 0
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_Zero, BO_Add, BF_One, BF_Zero>::GetRHI();
// for quads, write RGBA, RGB = src.rgb * src.a + dst.rgb * 0, A = src.a + dst.a * 0
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_SourceAlpha, BF_Zero, BO_Add, BF_One, BF_Zero>::GetRHI();
```
// for mirror window, write RGBA, RGB = src.rgb * src.a + dst.rgb * (1 - src.a), A = src.a * 1 + dst.a * (1 - src a)
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_One, BF_InverseSourceAlpha>::GetRHI();
```
RenderLights函数: (延迟光照是在这个函数执行的,对应的就是那个DeferredLightPixelShaders.usf)
```
{
SCOPED_DRAW_EVENT(RHICmdList, StandardDeferredLighting);
// make sure we don't clear the depth
SceneContext.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite, true);
// Draw non-shadowed non-light function lights without changing render targets between them
for (int32 LightIndex = StandardDeferredStart; LightIndex < AttenuationLightStart; LightIndex++)
{
const FSortedLightSceneInfo& SortedLightInfo = SortedLights[LightIndex];
const FLightSceneInfo* const LightSceneInfo = SortedLightInfo.LightSceneInfo;
// Render the light to the scene color buffer, using a 1x1 white texture as input
RenderLight(RHICmdList, LightSceneInfo, NULL, false, false);
}
SceneContext.FinishRenderingSceneColor(RHICmdList);
}
```
这个函数的层级
DirectLighting下 有NonShadowedLights、IndirectLighting、ShadowedLights
Shadowedlights里面,PerObject 阴影会调用到RenderShadowProjections函数,这个里面的目标贴图是ScreenShadowMaskTexture,也就是把阴影渲染到这张贴图上:
```
FRHIRenderPassInfo RPInfo(ScreenShadowMaskTexture->GetRenderTargetItem().TargetableTexture, ERenderTargetActions::Load_Store);
RPInfo.DepthStencilRenderTarget.Action = MakeDepthStencilTargetActions(ERenderTargetActions::Load_DontStore, ERenderTargetActions::Load_Store);
RPInfo.DepthStencilRenderTarget.DepthStencilTarget = SceneContext.GetSceneDepthSurface();
RPInfo.DepthStencilRenderTarget.ExclusiveDepthStencil = FExclusiveDepthStencil::DepthRead_StencilWrite;
TransitionRenderPassTargets(RHICmdList, RPInfo);
RHICmdList.BeginRenderPass(RPInfo, TEXT("RenderShadowProjection"));
```
对应的shader文件为ShadowProjectionPixelShader.usf。
后面deferredSHader里用到这张图,在FDeferredLightPS的SetParameterBase函数中:
```
if(LightAttenuationTexture.IsBound())
{
SetTextureParameter(
RHICmdList,
ShaderRHI,
LightAttenuationTexture,
LightAttenuationTextureSampler,
TStaticSamplerState<SF_Point,AM_Wrap,AM_Wrap,AM_Wrap>::GetRHI(),
ScreenShadowMaskTexture ? ScreenShadowMaskTexture->GetRenderTargetItem().ShaderResourceTexture : GWhiteTexture->TextureRHI
);
}
```
将ScreenShadowMaskTexture赋给了LightAttenuationTexture。