UE5.32里的ShaderUniformBufferBinding崩溃
修改逐Pass的UniformBuffer时,极易触发 “Shader attempted to bind uniform buffer ‘%s’ at slot %s with hash ‘%u’, but the shader expected ‘%s’ with hash ‘%u’. “检查崩溃,当遇到这种崩溃时,应该首先检查最近的MeshPass的UniformBinding是不是有问题(而不是怀疑SharedDDC的缓存有问题,XD,说的就是我自己)。
以UE5里的DistortionPass为例,回顾一下修改逐Pass的UniformBuffer步骤,最重要和容易忽略的地方是第4步:
- 挑选一个Slot, 声明一个自定义的Global Shader Parameter(此处用了SceneTextures),在原Slot类型的基础上额外加上自己的参数:
BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FDistortionPassUniformParameters, )
SHADER_PARAMETER_STRUCT(FSceneTextureUniformParameters, SceneTextures)
SHADER_PARAMETER(FVector4f, DistortionParams)
END_GLOBAL_SHADER_PARAMETER_STRUCT()
- 调用实现宏:
IMPLEMENT_STATIC_UNIFORM_BUFFER_STRUCT(FDistortionPassUniformParameters, "DistortionPass", SceneTextures);
- 将新Parameter添加到PassParameter中(如果原来用了SceneTextures,则替换之):
BEGIN_SHADER_PARAMETER_STRUCT(FDistortionPassParameters, RENDERER_API)
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FDistortionPassUniformParameters, Pass)
SHADER_PARAMETER_STRUCT_INCLUDE(FInstanceCullingDrawParams, InstanceCullingDrawParams)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
- 正确在GraphBuilder中申请并绑定UniformBuffer
TRDGUniformBufferRef<FDistortionPassUniformParameters> CreateDistortionPassUniformBuffer(FRDGBuilder& GraphBuilder, const FViewInfo& View)
{
auto* Parameters = GraphBuilder.AllocParameters<FDistortionPassUniformParameters>();
SetupSceneTextureUniformParameters(GraphBuilder, View.GetSceneTexturesChecked(), View.FeatureLevel, ESceneTextureSetupMode::All, Parameters->SceneTextures);
SetupDistortionParams(Parameters->DistortionParams, View);
return GraphBuilder.CreateUniformBuffer(Parameters);
}
auto* PassParameters = GraphBuilder.AllocParameters<FDistortionPassParameters>();
PassParameters->View = View.GetShaderParameters();
PassParameters->Pass = CreateDistortionPassUniformBuffer(GraphBuilder, View);
- 在Shader中,如果原本用到的Slot被替换了,一定要用宏重新声明,指示原来的Slot如何访问(注意此处的宏声明要放在Generated的文件include前面):
如果忘记了重声明,有些材质蓝图里面如果采样了SceneTexture或者其他原本Slot的内容,UE的Shader编译器会再给Shader额外加一个SceneTextures(或其他)的Slot,此时,包括前面我们自己声明的SceneTextures,此处重复了定义了相同Slot的UniformBuffer,在Shader验证阶段的ValidateStaticUniformBuffer函数中,会直接挂掉,报出类似如下的信息:
Shader attempted to bind uniform buffer 'FVelocityPassUniformParameters' at slot
[Name: SceneTextures, Slot: 8] with hash '96469509',
but the shader expected 'LumenFrontLayerTranslucencyGBufferPass' with hash '13633221'..
为啥会是LumenFrontLayerTranslucencyGBufferPass,因为它也是SceneTextures的Slot,UE会直接拿上一个相同Slot的补上,所以有时候,这个崩溃也是随机的。
令人感到蛋疼的是这个崩溃仅运行时需要使用到这个材质时才能触发,打包是可以正常完成的,所以该崩溃很容易让人觉得是SharedDDC的问题,最后都查歪方向了。