Download

Populating UInstancedStaticMeshComponent using Multithreading

So I have UInstancedStaticMeshComponent that I’m filling with about 10,000 instances to render. Once it is populated, it draws very fast, so no problems there. The trouble is that populating it seems to take some time and causes a very noticeable pause on the main game thread for at least a full second possibly longer. I need to be able to fill the UInstancedStaticMeshComponent at runtime when the player presses a key. I don’t mind if there is a delay between pressing the key and when the instances are finished populating and displaying. I just don’t want the main game thread to pause while its doing it. So I’m hoping this can be solved by running a separate thread. Either using something like FRunnable or the Task Graph. I’m just not 100% sure how to go about this.

Is it even possible to add instances to a UInstancedStaticMeshComponent on a secondary thread? Will that cause problems as the main game thread would most likely be trying to render it while a secondary thread is adding instances to it. Would I need to use some sort of locking perhaps to block rendering of the UInstancedStaticMeshComponent until the secondary thread has finished adding instances? I’ve had a browse through ThreadingBase.h in the UE4 source, but I’m not sure how to accomplish this with the UE4 classes available. There are a lot of classes in there and many don’t make sense to me as to what they are for or how they should be used.

Can anyone help?

Well for anyone else wondering, I don’t think it is possible. I spent the time setting up an FRunnable with a secondary thread to populate the UInstancedStaticMeshComponent. All went well until actually calling AddInstanceWorldSpace() on the UInstancedStaticMeshComponent.

Take a look at the following call stack.


UE4Editor-Engine.dll!FInitBodiesHelper<1>::InitBodies_PhysX() Line 1550	C++
UE4Editor-Engine.dll!FBodyInstance::InitBody(UBodySetup * Setup, const FTransform & Transform, UPrimitiveComponent * PrimComp, FPhysScene * InRBScene, physx::PxAggregate * InAggregate) Line 1774	C++
UE4Editor-Engine.dll!UInstancedStaticMeshComponent::InitInstanceBody(int InstanceIdx, FBodyInstance * InstanceBodyInstance) Line 986	C++
UE4Editor-Engine.dll!UInstancedStaticMeshComponent::SetupNewInstanceData(FInstancedStaticMeshInstanceData & InOutNewInstanceData, int InInstanceIndex, const FTransform & InInstanceTransform) Line 1697	C++
UE4Editor-Engine.dll!UInstancedStaticMeshComponent::AddInstance(const FTransform & InstanceTransform) Line 1428	C++
UE4Editor-Engine.dll!UInstancedStaticMeshComponent::AddInstanceWorldSpace(const FTransform & WorldTransform) Line 1447	C++

Turns out, if you follow the rabbit warren down through the UE4 code, you eventually get to InitBodies_PhysX() in BodyInstance.cpp. In this function there is the following line of code about four lines in.


check(IsInGameThread());

If creating PhysX bodies can only be done on the main game thread, then that basically kills any ideas of multithreading the creation of anything that has collision/physics data attached to it, which is kind of everything. Now I can understand that a PhysX body cannot be created mid-simulation, which is why this check would exist. However, I don’t see why they can’t be created anytime, but inserted into the simulation between ticks. Why can’t UE4 keep a buffer of objects that were created mid-frame (from other threads for example) and then shuffle them into the simulation at an appropriate time when the simulation is finished for the frame. Anyway, maybe an UE4 dev knows more about this as that goes a bit over my head.

So that pretty much sums it up and puts an end to this journey! Back to the drawing board.

Has anyone found a solution to this problem of multithreading creation of adding instances?

You can immediately create a small number of instances in the start area, and continue to create the rest at runtime with short intervals of time, or even when approaching them.

Simplest solution would be to just stagger adding those instances over many game thread ticks instead of doing it on another thread.

Multithreading isn’t going to help if the bottleneck is creating the physics data anyway. You’ll need to split that over several frames.