我们在使用HISMComponent管理实例时,遇到了从InstanceReorderTable里面取出来的值出现越界的问题。

我们在使用HISMComponent管理实例时,遇到了从InstanceReorderTable里面取出来的值出现越界的问题

[Image Removed]

具体的操作包括:在同一帧内,对HISMComponent进行调用RemoveInstances和AddInstances

每次出现这个报错时,HISMComponent内,ClusterTree都处在异步构建中,即bIsAsyncBuilding=true

我们正在使用的版本是,UE5.3.2,想知道要定位这个问题,应该从哪些模块处入手,或者虚幻是否在后续版本中已经修复了这个问题

对这个问题再补充一些信息。

当出现这个ensure的check之前,HISMComponent经历了如下的调用:

1. AddInstances被调用后,bIsAsyncBuilding=true,bConcurrentChanges=false,bIsOutOfDate=true。这意味着,构建ClusterTree的任务已经被Dispatch了,PerInstanceSMData、InstanceReorderTable等的值也被更新了;

2. 同一帧的情况下,接着调用RemoveInstances后,此时bIsAsyncBuilding=true,bConcurrentChanges=true,bIsOutOfDate=true。意味着检查到ClusterTree正在构建,但又有修改发生了,所以bConcurrentChanges被设置为true了。相应的,PerInstanceSMData、InstanceReorderTable等的值再次被更新;

3. 在调用HISMComponent的CreateSceneProxy之前,ApplyBuildTreeAsync函数被调用,由于此时bConcurrentChanges=true,ApplyBuildTree不会被调用,而是再次进入BuildTreeAsync(在步骤1中已经被调用过了):

[Image Removed]

此时,在BuildTreeAsync函数中,PerInstanceRenderData->UpdateFromCommandBuffer(InstanceUpdateCmdBuffer);函数会被调用,InstanceUpdateCmdBuffer.NumEditInstances的值被更新:

[Image Removed]

如果Max(InstanceUpdateCmdBuffer.NumEditInstances, GetInstanceCount())的值,比InstanceReorderTable里面记录的值要少,后续的ensure就会被触发。

[Image Removed]

4. 问题的焦点在于InstanceUpdateCmdBuffer.NumEditInstances的值是这样计算的:

[Image Removed]

此时,如果渲染线程还没来得及调用:

InstanceBuffer->UpdateFromCommandBuffer_RenderThread(*NewCmdBuffer);

那么,这个时候,在Game线程中调用InstanceData->GetNumInstances();返回的就是步骤1调用时的值,但此时InstanceUpdateCmdBuffer.NumAdds的值一定为0,因为此时它记录的是步骤2中的值。

那么如果步骤2删除的Instance的数量比步骤1添加的Instance的数量要多,InstanceReorderTable中存储的值,就一定会有比Max(InstanceUpdateCmdBuffer.NumEditInstances, GetInstanceCount())的值要大的值,ensure的check就会被触发

Hi,

这个问题有点麻烦,我们内部也查到一个类似的问题,但是修复是通过一个refactor修复的https://github.com/EpicGames/UnrealEngine/commit/e5f34a1d9c9a40eae610d5697040ea89d34c5bb9

而且这个改动可能距离你们的版本有几个月,中间也有些改动,估计很难直接合入5.3.