当前位置: 首页 > 工具软件 > F-Spot > 使用案例 >

UE4:Mobile Spot Ligth shadow

勾起运
2023-12-01

如需转载本文,请声明作者及出处。

basepixelshader.txt 知道,计算Cascaded Shadow Map需要的参数,其实跟Cascaded Shadow Map也没多大关系,能计算阴影就行
int4 SpotLightId;

FPCFSamplerSettings Settings;
Settings.ShadowDepthTexture = MobileDirectionalLight.DirectionalLightShadowTexture;
Settings.ShadowDepthTextureSampler = MobileDirectionalLight.DirectionalLightShadowSampler;
Settings.TransitionScale = MobileDirectionalLight.DirectionalLightShadowTransition;
Settings.ShadowBufferSize = MobileDirectionalLight.DirectionalLightShadowSize;
Settings.bSubsurface = false;
Settings.bTreatMaxDepthUnshadowed = false;
Settings.DensityMulConstant = 0;
Settings.ProjectionDepthBiasParameters = 0;


需要修改源码,将所需的参数向gpu传输
		MeshPipleLine
CPU---------------------->pass param to GPU------->MobileBasePassPixel.usf
		MobileBasePass


------------------------------------------MobileBasePassPixel.usf-----------------------------------
//灯光id传入shader
int4 SpotLightId;

//阴影的计算抄MobileBasePassPixel.usf前面的代码
#if PROJECT_MOBILE_ENABLE_MOVABLE_SPOTLIGHTS
if(SpotLightAngles[i].w > 0.0)
{
    Attenuation *= SpotAttenuation(L, -SpotLightDirection[i].xyz, SpotLightAngles[i].xy);
    #if RECEIVE_MOBILE_SPOT_LIGHT_SHADOW
    if (SpotLightId[i] == MobileSpotLight.SpotLightId)
    {
        half Shadow = 1;
        FPCFSamplerSettings Settings;
        //主要参数
        Settings.ShadowDepthTexture = MobileSpotLight.SpotLightShadowTexture;
        Settings.ShadowDepthTextureSampler = MobileSpotLight.SpotLightShadowSampler;
        Settings.TransitionScale = MobileSpotLight.SpotLightTransition;
        Settings.ShadowBufferSize = MobileSpotLight.SpotLightShadowSize;
        Settings.bSubsurface = false;
        Settings.bTreatMaxDepthUnshadowed = false;
        Settings.DensityMulConstant = 0;
        Settings.ProjectionDepthBiasParameters = 0;
        float4 ShadowPosition = float4(0, 0, 0, 0);
        // 抄MobileBasePassPixel.usf前面的代码
        ShadowPosition = mul(float4(MaterialParameters.ScreenPosition.xyw, 1), MobileSpotLight.SpotLightScreenToShadow);
        if (ShadowPosition.z > 0)
        {
            float LightSpacePixelDepthForOpaque = min(ShadowPosition.z, 0.99999f);
            Settings.SceneDepth = LightSpacePixelDepthForOpaque;
            half ShadowMap = Manual2x2PCF(float2(ShadowPosition.xy / ShadowPosition.w), Settings);
            Shadow = min(Shadow, ShadowMap);
        }
        // Attenuation计算出阴影强度
        Attenuation *= Shadow;
    }
    #endif
}
#endif


所以一共有两砣参数需要传递
-------------------------------------shader params----------------------------------------------------------------
TMobileBasePassPSPolicyParamType												MobileBasePassPixel.usf
FShaderUniformBufferParameter MobileSpotLightBufferParam;		----->				MobileSpotLight
FShaderParameter SpotLightIdParameter;							----->				int4 SpotLightId

SceneView.h
// 新增shader参数的定义,基本上就是FPCFSamplerSettings中所需的参数
BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT_WITH_CONSTRUCTOR(FMobileSpotLightShaderParameters, ENGINE_API)
    SHADER_PARAMETER(int32, SpotLightId)
    SHADER_PARAMETER(float, SpotLightTransition)
    SHADER_PARAMETER(FMatrix, SpotLightScreenToShadow)
    SHADER_PARAMETER_EX(FVector4, SpotLightShadowSize, EShaderPrecisionModifier::Half)
    SHADER_PARAMETER_TEXTURE(Texture2D, SpotLightShadowTexture)
    SHADER_PARAMETER_SAMPLER(SamplerState, SpotLightShadowSampler)
END_GLOBAL_SHADER_PARAMETER_STRUCT()

class ENGINE_API FSceneView
{
    /** Mobile Spot Lighting uniform buffers */
    TUniformBufferRef<FMobileSpotLightShaderParameters> MobileSpotLightUniformBuffers[NUM_LIGHTING_CHANNELS+1];
}

SceneView.cpp
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FMobileSpotLightShaderParameters, "MobileSpotLight");


// bass pass 中新添两砣参数
class TMobileBasePassPSPolicyParamType : public FMeshMaterialShader, public LightMapPolicyType::PixelParametersType
{
    FShaderUniformBufferParameter MobileSpotLightBufferParam;
    FShaderParameter SpotLightIdParameter;
}

TMobileBasePassPSPolicyParamType(const FMeshMaterialShaderType::CompiledShaderInitializerType& Initializer)
        : FMeshMaterialShader(Initializer)
{
    MobileSpotLightBufferParam.Bind(Initializer.ParameterMap, FMobileSpotLightShaderParameters::StaticStructMetadata.GetShaderVariableName());

    SpotLightIdParameter.Bind(Initializer.ParameterMap, TEXT("SpotLightId"));
}


virtual bool Serialize(FArchive& Ar) override
{
        Ar << MobileSpotLightBufferParam;
        Ar << SpotLightIdParameter;

        return bShaderHasOutdatedParameters;
}


--------------------------------------base pass 传入SpotLightId参数-------------------------------------------------
FMobileBasePassMeshProcessor::AddMeshBatch
FMobileBasePassMeshProcessor::Process
FMeshPassProcessor::BuildMeshDrawCommands
// FUniformLightMapPolicy 在此通道中设置
TMobileBasePassPSPolicyParamType<FUniformLightMapPolicy>::GetShaderBindings
{
    // 传入两砣参数
    if (LightPositionAndInvRadiusParameter.IsBound() || SpotLightDirectionAndSpecularScaleParameter.IsBound())
    {
        // 源码中在此处设置生成LightInfo
        FMobileBasePassMovableLightInfo LightInfo(PrimitiveSceneProxy);
        ShaderBindings.Add(SpotLightAnglesParameter, LightInfo.SpotLightAngles);
        ShaderBindings.Add(SpotLightIdParameter, LightInfo.SpotLightId);
    }

    if (MobileSpotLightBufferParam.IsBound() && Scene)
    {
        ShaderBindings.Add(MobileSpotLightBufferParam, Scene->UniformBuffers.MobileSpotLightUniformBuffers);
    }
}


---------------------------------------SpotLightIdParameter--------------------------------------------------------
                            ||
                            ||

// 在LightInfo中传入所有光照Id
MobileBasePassRendering.cpp
FMobileBasePassMovableLightInfo::FMobileBasePassMovableLightInfo
{
    for (FLightPrimitiveInteraction* LPI = InSceneProxy->GetPrimitiveSceneInfo()->LightList; LPI && NumMovablePointLights < MobileNumDynamicPointLights; LPI = LPI->GetNextLight())
    {
        if (bIsValidLightType && LightProxy->IsMovable() && (LightProxy->GetLightingChannelMask() & InSceneProxy->GetLightingChannelMask()) != 0)
        {
            SpotLightId[NumMovablePointLights] = LPI->GetLight()->Id;
        }
    }
}
-------------------------------------------------------------------
                            ||
                            ||

MobileBasePassRendering.h
class FMobileBasePassMovableLightInfo
{

    int32 SpotLightId[MAX_BASEPASS_DYNAMIC_POINT_LIGHTS];
    FShaderUniformBufferParameter MobileSpotLightBufferParam;

};



---------------------------------------MobileSpotLightBufferParam--------------------------------------------------------
--------------------------------------------render主流程的修改,传入setting所需参数FMobileSpotLightShaderParameters--------------------------------
-------------------------------在initviews中,创建相关的render target 和 shader param----------------------------------
//为所有灯光生成shadowmap
void FMobileSceneRenderer::InitViews(FRHICommandListImmediate& RHICmdList)
FSceneRenderer::InitDynamicShadows(RHICmdList, DynamicIndexBuffer, DynamicVertexBuffer, DynamicReadBuffer);
AllocateShadowDepthTargets(RHICmdList);
AllocateSpotLightDepthTargets(RHICmdList, WholeSceneSpotLightShadows);
void FSceneRenderer::AllocateSpotLightDepthTargets(FRHICommandListImmediate& RHICmdList, TArray<FProjectedShadowInfo*, SceneRenderingAllocator>& WholeSceneSpotLightShadows)


// 创建参数
void FMobileSceneRenderer::InitViews(FRHICommandListImmediate& RHICmdList)
CreateSpotLightUniformBuffers(Views[ViewIndex]);
void FMobileSceneRenderer::CreateSpotLightUniformBuffers(FViewInfo& View)
{
    bool bDynamicShadows = ViewFamily.EngineShowFlags.DynamicShadows;
    FMobileSpotLightShaderParameters Params;
    SetupMobileSpotLightUniformParameters(*Scene, View, VisibleLightInfos, bDynamicShadows, Params);
    View.MobileSpotLightUniformBuffers = TUniformBufferRef<FMobileSpotLightShaderParameters>::CreateUniformBufferImmediate(Params, UniformBuffer_SingleFrame);
}


//渲染时更新参数
MobileTranslucentRendering.cpp
bool FMobileSceneRenderer::RenderInverseOpacity(FRHICommandListImmediate& RHICmdList, const FViewInfo& View)
{
    if (Scene->UniformBuffers.UpdateViewUniformBuffer(View))
    {
        UpdateSpotLightUniformBuffers(RHICmdList, View);
    }
}


oid FMobileSceneRenderer::RenderTranslucency(FRHICommandListImmediate& RHICmdList, const TArrayView<const FViewInfo*> PassViews, bool bRenderToSceneColor)
{
    if (!View.Family->UseDebugViewPS())
    {
        if (Scene->UniformBuffers.UpdateViewUniformBuffer(View))
        {
            UpdateSpotLightUniformBuffers(RHICmdList, View);
        }
    }
}

--------------------------------------------------------------------------------------------
                                            ||
                                            ||
-------------------------------------之后的depth pass中渲染-----------------------------
TShadowDepthVS PS DepthPass中渲染深度
--------------------------------------------------------------------------------------
                                            ||
                                            ||
--------------------------------------上面提到的base pass中会使用----------------------




----------------------------------------主流程用到的相关接口的修改实现-------------------------------
ShadowRendering.h
class FProjectedShadowInfo : public FRefCountedObject
{
    inline bool IsWholeSceneSpotLightShadow() const
    {
        return bWholeSceneShadow && (LightSceneInfo->Proxy->GetLightType() == LightType_Spot);
    }

}

ShadowSetup.cpp
//收集所有点光
void FSceneRenderer::AllocateShadowDepthTargets(FRHICommandListImmediate& RHICmdList)
{
    // 2d shadowmaps for mobile spot light
    TArray<FProjectedShadowInfo*, SceneRenderingAllocator> WholeSceneSpotLightShadows;

    for (TSparseArray<FLightSceneInfoCompact>::TConstIterator LightIt(Scene->Lights); LightIt; ++LightIt)
    {
        if (FeatureLevel < ERHIFeatureLevel::SM4
        // Mobile renderer only supports opaque per-object shadows or CSM or SpotLight Shadow
        && (!ProjectedShadowInfo->bPerObjectOpaqueShadow && !(ProjectedShadowInfo->bDirectionalLight && ProjectedShadowInfo->bWholeSceneShadow) && !ProjectedShadowInfo->IsWholeSceneSpotLightShadow()))
        {
            bShadowIsVisible = false;
        }

        if (ProjectedShadowInfo->IsWholeSceneSpotLightShadow() && FeatureLevel < ERHIFeatureLevel::SM4)
        {
            WholeSceneSpotLightShadows.Add(ProjectedShadowInfo);
        }
    }
    AllocateSpotLightDepthTargets(RHICmdList, WholeSceneSpotLightShadows);
}

//创建 depth render target
void FSceneRenderer::AllocateSpotLightDepthTargets(FRHICommandListImmediate& RHICmdList, TArray<FProjectedShadowInfo*, SceneRenderingAllocator>& WholeSceneSpotLightShadows)
{
    //创建 depth render target
}

-------------------------------SpotLightShadowTexture & uniform--------------------------------
ScenePrivate.h
class FPersistentUniformBuffers
{
    TUniformBufferRef<FMobileSpotLightShaderParameters> MobileSpotLightUniformBuffers;
}

RendererScene.cpp
void FPersistentUniformBuffers::Initialize()
{
    FMobileSpotLightShaderParameters MobileSpotLightShaderParameters = {};
    MobileSpotLightUniformBuffers = TUniformBufferRef<FMobileSpotLightShaderParameters>::CreateUniformBufferImmediate(MobileSpotLightShaderParameters, UniformBuffer_MultiFrame, EUniformBufferValidation::None);
}


class FScene : public FSceneInterface
{
    /** For the mobile renderer, the movable spot lights who cast dynamic shadow. */
    TSet<FLightSceneInfo*> MobileSpotlLights;
}

SceneManagement.cpp
FMobileSpotLightShaderParameters::FMobileSpotLightShaderParameters()
{
    FMemory::Memzero(*this);

    SpotLightShadowTexture = GWhiteTexture->TextureRHI;
    SpotLightShadowSampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
    SpotLightScreenToShadow.SetIdentity();
    SpotLightId = -1;
}


void SetupMobileSpotLightUniformParameters(
    const FScene& Scene,
    const FViewInfo& SceneView,
    const TArray<FVisibleLightInfo, SceneRenderingAllocator> VisibleLightInfos,
    bool bDynamicShadows,
    FMobileSpotLightShaderParameters& Params)
{
    // 更新setting里所需的参数
}

void FMobileSceneRenderer::CreateSpotLightUniformBuffers(FViewInfo& View)
{
    bool bDynamicShadows = ViewFamily.EngineShowFlags.DynamicShadows;
    FMobileSpotLightShaderParameters Params;
    SetupMobileSpotLightUniformParameters(*Scene, View, VisibleLightInfos, bDynamicShadows, Params);
    View.MobileSpotLightUniformBuffers = TUniformBufferRef<FMobileSpotLightShaderParameters>::CreateUniformBufferImmediate(Params, UniformBuffer_SingleFrame);
}

void FMobileSceneRenderer::UpdateSpotLightUniformBuffers(FRHICommandListImmediate& RHICmdList, const FViewInfo& View)
{
    bool bDynamicShadows = ViewFamily.EngineShowFlags.DynamicShadows;
    FMobileSpotLightShaderParameters Params;
    SetupMobileSpotLightUniformParameters(*Scene, View, VisibleLightInfos, bDynamicShadows, Params);
    // 如此,在mesh pipeline 里可传递
    Scene->UniformBuffers.MobileSpotLightUniformBuffers.UpdateUniformBufferImmediate(Params);
}

 

 类似资料: