ue4.26 Assertion failed: MeshCommands.Num() == MeshCommandsCSM.Num() 解法

在ue4.26的pc端添加了自定义meshpass  xxxPass,切到移动端后产生如下错误:

  Assertion failed: MeshCommands.Num() == MeshCommandsCSM.Num()

  VisibleMeshDrawCommands of BasePass and MobileBasePassCSM are expected to match.

为了看清楚状况,做一个最简场景进行复现,一个材质名为floor的绿色平面,一个材质名为cartoonTransp的球体,pc平台效果如下:

切换为移动平台后,触发asset fail断点如下:

查看断点数据,可见MeshCommands和MeshCommandsCSM元素数量分别为1和2。

进一步展开细看,可见MeshCommands中的1个元素为floor,MeshCommandsCSM中的两个元素为floor和cartoonTransp:

此种mesh command与阴影comand对不上的情况不会发生在pc端,因为由下面代码可见,pc端直接GenerateDynamicMeshDrawCommands,而移动端在GenerateDynamicMeshDrawCommands之前多一个MergeMobileBasePassMeshDrawCommands过程,在其中会asset两种command数量相等。

void AnyThreadTask()
	{
		...

		if (bMobileShadingBasePass)
		{
			MergeMobileBasePassMeshDrawCommands(
				...
				Context.MeshDrawCommands,
				Context.MobileBasePassCSMMeshDrawCommands
			);

			GenerateMobileBasePassDynamicMeshDrawCommands(
				...
				Context.MeshDrawCommands,
				...
			);
		}
		else
		{
			GenerateDynamicMeshDrawCommands(
				...
				Context.MeshDrawCommands,
         ...
			);
		}
        ...
} 

我们知道GenerateDynamicMeshDrawCommands是完成将meshbatch转为meshdrawcommand的过程,也就是说GenerateDynamicMeshDrawCommands之前还不存在meshdrawcommand,那MergeMobileBasePassMeshDrawCommands中的Context.MeshDrawCommands和Context.MobileBasePassCSMMeshDrawCommands是从哪来的呢?

其实这里的Context.MeshDrawCommands和Context.MobileBasePassCSMMeshDrawCommands根本不是FMeshDrawCommand类型,而是FVisibleMeshDrawCommand类型(书写时偷懒了)。

FVisibleMeshDrawCommand定义如下:

即首先SceneVisibility.cpp中由MeshBatch生成FVisibleMeshDrawCommand,然后是GenerateDynamicMeshDrawCommands由FVisibleMeshDrawCommand和MeshBatch生成FMeshDrawCommand。

由于在SceneVisibility.cpp中,我只让球体对xxxPass生成visibleMeshDrawCommand,所以球体对MobileBasePass不生成visibleMeshDrawCmmand,这是对的。

但由于SceneVisibility.cpp中默认有一句:

    if (ShadingPath == EShadingPath::Mobile)
	{
       DrawCommandPacket.AddCommandsForMesh(PrimitiveIndex, PrimitiveSceneInfo, StaticMeshRelevance, StaticMesh, Scene, bCanCache, EMeshPass::MobileBasePassCSM); 
	} 

所以球体会对MobileBasePassCSM这个pass生成visibleMeshDrawCommand。于是产生不匹配。

解法就是让球体对MobileBasePassCSM不生成visibleMeshDrawCommand,即改为:

SceneVisibility.cpp

if (ShadingPath == EShadingPath::Mobile) {
		if (!StaticMesh.MaterialRenderProxy->GetMaterial(View.GetFeatureLevel())->GetShadingModels().HasOnlyShadingModel(EMaterialShadingModel::MSM_Toon_01_TR)) {
    
DrawCommandPacket.AddCommandsForMesh(PrimitiveIndex, PrimitiveSceneInfo, StaticMeshRelevance, StaticMesh, Scene, bCanCache, EMeshPass::MobileBasePassCSM); } } 

再运行切移动端,就不会asset fail了,不过球体有影子但本身不可见,如下:

 原因是我只在FDeferredShadingSceneRenderer::Render中调用了RenderxxxPass,但没在FMobileSceneRenderer::RenderDeferred中调用RenderxxxPass。

 

posted on 2024-01-18 03:18  wantnon  阅读(45)  评论(0编辑  收藏  举报

导航