代码改变世界

ue4 延迟光照

2019-11-21 15:51  kk20161206  阅读(558)  评论(0)    收藏  举报

 

 

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。
 
View Code