如需转载本文,请声明作者及出处。
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);
}