Background
For a few major versions now, HISM (Hierarchical Instanced Static Mesh) has been particularly crash-prone during run-time updates, i.e. when UpdateInstanceTransform, AddInstance, etc are used on a HISM component after the game has begun. The crash typically happens in the rendering thread due to a HISM “ClusterTree” being invalid.
After chasing this for ages I finally have a clean simple repro project that demonstrates exactly what triggers this HISM crash.
Repro
Run the sample project, it should crash within 8-10 seconds. If not, just wait a bit or try a few times again. This bug is timing related so it behaves a little differently each time you run it. The relevant code is in HISMCrashSimulator.cpp’s Tick function.
HISM is likely to crash whenever UpdateInstanceTransform is called with a location that is exactly the same as the current location of the instance. Furthermore, calling AddInstanceTransform around the same time practically guarantees that the crash will happen (that’s what the repro project does).
In other words, if you need to update only the scale or rotation of a HISM instance and leave the location intact (or if you simply pass the instance’s current transform back to the update function) it eventually crashes and especially so if a new instance is also added at or around the same time.
Crash details
The crash occurs in the rendering thread at HierarchicalInstancedStaticMeshComponent.cpp in the function UpdateInstanceTreeBoundsInternal_RenderThread. Specifically - FClusterNode Node = &ClusterTree[0];* which produces undefined behavior because ClusterTree’s memory is invaild.
Sometimes it crashes right there, other times further ahead, but perhaps the most frightening issue of all is when it freezes the entire unreal process inside some WinEvent thread wait routine after which it is very difficult to even come out and close the program!
Workaround
HISM’s code treats “In-place-updates” (i.e. location unchanged) as a special scenario, this is where the issues manifest.
So the workaround is to add a tiny offset to the location so we can bypass that scenario, like this:
float tinyOffset = KINDA_SMALL_NUMBER * 10;
newTransform.AddToTranslation(FVector(0, 0, tinyOffset));
// newTransform's scale or rotation can now be manipulated as desired
// and UpdateInstanceTransform can be called safely
Obviously far from ideal, but until there’s a fix I really needed a way to stabilize my release builds so I could move forward and perhaps others using HISM may be in a similar situation as well.
I hope this report helps in fixing the issue!
HISM is one of my favorite features in Unreal Engine and the possibilities are endless when you add dynamic behaviors to it (that’s where the tricky bugs usually come in). I hope to see HISM become even more awesome over time!
Thank you.