UE4:Mobile Spot Ligth shadow

    技术2024-06-17  73

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

    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); }

     

    Processed: 0.017, SQL: 9