I’m trying to maintain a FInstancedStaticMeshSceneProxy without any actor component similar to FFastGeoInstancedStaticMeshComponent.
But I need to update the primitive transform of the InstancedStaticMeshSceneProxy instead of just static like the fast geo component.
However I couldn’t find a simple way to update the primitive transform of the proxy (All the instances’ datas like local transform are not changed).
I build the InstanceSceneDataBuffers just like how FFastGeoInstancedStaticMeshComponent::BuildInstanceData does
FInstanceSceneDataBuffers InstanceSceneDataBuffers{};
FInstanceSceneDataBuffers::FAccessTag AccessTag(PointerHash(this));
FInstanceSceneDataBuffers::FWriteView View = InstanceSceneDataBuffers.BeginWriteAccess(AccessTag);
// PrimitiveLocalToWorld
InstanceSceneDataBuffers.SetPrimitiveLocalToWorld(SourceComponent->GetComponentTransform().ToMatrixWithScale(), AccessTag);
// InstanceLocalBounds...
// LocalToPrimitiveRelativeWorld...
// InstanceCustomData...
// InstanceRandomIDs...
InstanceSceneDataBuffers.EndWriteAccess(AccessTag);
InstanceSceneDataBuffers.ValidateData();
NewDesc.SceneProxyDesc.InstanceDataSceneProxy = MakeShared<FInstanceDataSceneProxy, ESPMode::ThreadSafe>(MoveTemp(InstanceSceneDataBuffers));
Then I create the scene proxy and add primitive like this
auto& NewProxy = PLAProxy->Proxies[PLAProxy->Proxies.Add()];
Nanite::FMaterialAudit NaniteMaterials{};
const bool bUseNanite = SceneProxyDesc.ShouldCreateNaniteProxy(&NaniteMaterials);
if (bUseNanite)
{
TRACE_CPUPROFILER_EVENT_SCOPE(CreateNaniteSceneProxy);
NewProxy.PrimitiveSceneData.SceneProxy = ::new Nanite::FSceneProxy(NaniteMaterials, SceneProxyDesc);
}
else
{
TRACE_CPUPROFILER_EVENT_SCOPE(CreateSceneProxy);
if (SceneProxyDesc.bIsInstancedStaticMesh)
{
NewProxy.PrimitiveSceneData.SceneProxy = ::new FInstancedStaticMeshSceneProxy(SceneProxyDesc, SceneProxyDesc.FeatureLevel);
}
else
{
NewProxy.PrimitiveSceneData.SceneProxy = ::new FStaticMeshSceneProxy(SceneProxyDesc, false);
}
}
FPrimitiveSceneDesc SceneDesc;
SceneDesc.SceneProxy = NewProxy.PrimitiveSceneData.SceneProxy;
SceneDesc.ProxyDesc = &SceneProxyDesc;
SceneDesc.PrimitiveSceneData = &NewProxy.PrimitiveSceneData;
SceneDesc.RenderMatrix = (InstanceData.RelativeTransform * PLATransform).ToMatrixWithScale();
SceneDesc.AttachmentRootPosition = PLATransform.GetTranslation();
SceneDesc.LocalBounds = SceneProxyDesc.bIsInstancedStaticMesh ? Desc.InstancesLocalBounds : SceneProxyDesc.StaticMesh->GetBounds();
SceneDesc.Bounds = SceneDesc.LocalBounds.TransformBy(SceneDesc.RenderMatrix);
SceneDesc.Mobility = EComponentMobility::Movable;
SceneProxyDesc.Scene->AddPrimitive(&SceneDesc);
It works great until I tried to update the primitive transform like this
Scene->StartUpdatePrimitiveTransform(NumProxies);
...
auto& InstanceData = PLAProxy->Components[Index];
auto& Desc = PLAProxy->Descs[InstanceData.DescIndex];
auto& SceneProxyDesc = Desc.SceneProxyDesc;
FPrimitiveSceneDesc SceneDesc;
SceneDesc.SceneProxy = Proxy.PrimitiveSceneData.SceneProxy;
SceneDesc.ProxyDesc = &SceneProxyDesc;
SceneDesc.PrimitiveSceneData = &Proxy.PrimitiveSceneData;
SceneDesc.RenderMatrix = (InstanceData.RelativeTransform * PLATransform).ToMatrixWithScale();
SceneDesc.AttachmentRootPosition = PLATransform.GetTranslation();
SceneDesc.LocalBounds = SceneProxyDesc.StaticMesh->GetBounds();
SceneDesc.Bounds = Desc.SceneProxyDesc.bIsInstancedStaticMesh ? Desc.InstancesLocalBounds : SceneDesc.LocalBounds.TransformBy(SceneDesc.RenderMatrix);
SceneDesc.Mobility = EComponentMobility::Movable;
SceneProxyDesc.Scene->UpdatePrimitiveTransform(&SceneDesc);
SceneProxyDesc.Scene->UpdatePrimitiveInstances(&SceneDesc);
...
Scene->FinishUpdatePrimitiveTransform();
It moves all the instances somehow, but I got an ensure of “Mismatched Primitive transform!”
And I can’t figure out a simple way to update the primitive transform inside the InstanceSceneDataBuffers.
[Image Removed]
[Attachment Removed]