So there is this cool video from epic featuring instanced meshes. Canon Man Tutorial: Hierarchical Instanced Static Meshes | Live Training | Unreal Engine - YouTube . It basically says that instead of deleting the x index in the hierachy. it gets replaced by the last index of it and thats going to be removed. so everytime you remove an index of it, the last index will be moved there. thats what ruined the structure. simple fix would be to use a normal instanced mesh (ISM) instead of an hism. that worked for me.
I tried emulating erase and swap, but they still get shuffled unknown way. That issue remains unsolved for me for 13 months. How to restore correct indices after removal from HISM?
**Update: **I tried again. Yes, it’s erase and swap. That feel when you fix 13-month bug.
In case anyone needs it, index restoration is something like this:
int instancesNumber = MeshComponent->GetInstanceCount();
for (auto& x: instances) {
if (x.instanceIndex == instancesNumber) {
x.instanceIndex = deletedInstance.instanceIndex;
break;
}
}
What about removing instances after a certain number of hit. I’m able to remove instances without any problem but I want the player to have to interact multiple times with the instance before removing it.
Gonna link those 2, seems quite related:
you can just use the “Clear Instances” Node
I’m glad you guys kept this post alive, I couldn’t figure out what was going on for the life of me…It was removing the wrong instances at the wrong indexes and no one on any of the Discord channels knew why. I was getting ready to post it in this forum when It pulled this up as I was typing.
Basically what I ended up doing is changing it from an ISM to an HISM as described above, I used Remove Instances instead of Remove Instance and used the Traced Hit Index as an Array…seems to work flawlessly now.
I had the same issue with deleting mesh instances, since I keep an external map linking my own IDs to those of the HISM mesh indices. Using Rasie1’s approach above to emulate the RemoveAtSwap() behavior worked for me in maintaining this external mapping, at least for now.
Looking at the UE5 source code for UHierarchicalInstancedStaticMeshComponent::RemoveInstancesInternal(), I found that it triggers this multicast delegate in response to any internal index changes:
FInstancedStaticMeshDelegates::OnInstanceIndexUpdated
Setting up a handler in your Actor class like this (arbitrary name):
void OnHismInstanceIndexUpdated(UInstancedStaticMeshComponent* Component, TArrayView<const FInstancedStaticMeshDelegates::FInstanceIndexUpdateData> IndexUpdates);
You can then connect it to the multicast delegate in e.g. Init() like this:
FInstancedStaticMeshDelegates::OnInstanceIndexUpdated.AddUObject(this, &AYourActorClass::OnHismInstanceIndexUpdated);
Your handler function can then get lists of Added, Removed, Relocated, Cleared, and Destroyed updates from all HISM components and can react to any internal changes without having to guess.
void AYourActorClass::OnHismInstanceIndexUpdated(UInstancedStaticMeshComponent* Component, TArrayView<const FInstancedStaticMeshDelegates::FInstanceIndexUpdateData> IndexUpdates)
{
// Only handle the HISM(s) owned by this instance!
if (Component == HismComp)
{
for (auto& upd : IndexUpdates)
{
// Note: Could be Added, Removed, Relocated, Cleared, Destroyed
if (upd.Type == FInstancedStaticMeshDelegates::EInstanceIndexUpdateType::Relocated)
{
// In here, update any tracking you have using upd.OldIndex to use upd.Index instead!
}
// ... other handlers as needed
}
}
}
I’m sure everyone kinda has their own solutions and tricks, but the issue of the array indexes getting re-ordered got solved by doing reverse for loops! Either Reverse For Loop or Reverse For Each loop. ive found that doesnt care about the re-ordering!
Bumping this. In case anyone’s battling this right now, I figured out exactly how the ‘remove instance’ node works since I wasn’t able to find the info anywhere on forums, and it’s different from how removing an index from an array works:
When you ‘remove instance’ on an HISM, it does a ‘remove swap’ where it removes the instance you wanted to remove, THEN it takes the instance with the highest index and places it wherever you just removed from. Every other instance can now stay where it is.
Example: if your HISM has 4 instances (indexed 0-3) and you remove index 1, it removes index 1 and moves index 3 to be at index 1. indexes 0 and 2 can stay where they are.
I’m guessing they did this so it doesn’t have to reorder every higher index the way an array does, but I really wish they made it work like ‘remove index’ from an array, so we can track our instances with arrays and correlate them with variables. BUT knowing this you can rearrange your arrays to match the way the HISM has been rearranged.
Depending on what you’re doing, if the indexing order is paramount, instead of removing instances, move them. Move them where we cannot ever find them, under the carpet they go.
You can also add the indexes to an array fitst and then batch remove them from HISM. Example:
Removing them with a for loop one-by-one is not a thing since the order gets jumbled, as you said.
I wasn’t able to find the info anywhere on forums
Late to the party, just wanted to add that FDynamicMesh3 uses FRefCountVector and TDynamicVector to solve the stable vertex/triangle ID indexing issue for dynamic mesh, not sure if instanced static mesh would get a similar overhaul?
After some further digging, it seems that FSMInstanceElementIdMap (based on the OnInstanceIdUpdated delegate) provides a way to map unstable instanceIDs to stable elementIDs, so user code would just keep the stable elementIDs as translated from instanceIDs, and when dealing with the original ISM APIs, application code would use the corresponding method on the class to translate stable element ID to raw (and possibly updated) instance ID! Check the document and the source code for more information
Digging even deeper, I discovered that the 5.4 (also UE5-main) branches contains the statble instance ID for ISM methods: AddInstanceById / RemoveInstanceById (and other XxxById methods), and they return/use FPrimitiveInstanceId which seems to be a built-in counterpart of FSMInstanceElementIdMap, which seems to be removed in those branches as well - so I’m looking forward to the release of 5.4
Wow, so they finally noticed that hism is totally broken.
So, I have same index chaos problem too. What should I do? Waiting for a fix (also i am using blueprints, so that fix should be im blueprints too) or trying to a system that fixes indexs or giving instances a id?
I tried a instance id system too, but it not ended good. I completed a id system but even I, dont know how it works.(exteremly complex and weird)
Working with hism is very painfull.
Is that addinstancebyid thing exist in blueprint?
I don’t think it matters whether you use AddInstance or AddInstanceById it will always be broken.
I think I understand your assumption but it’s not founded so far!
the main problem that messing up our code is PrimitiveInstanceDataManager
and this manager doesnt support FPrimitiveInstanceId
. it basically takes the ID FPrimitiveInstanceId
and it translate it to index, then it letterly uses the same code as before
so either way it uses the index to sort and reconstruct the array lol
EPIC is trolling with us