Hi, we’d like to be able to hide an instance of an hism.
There does not appear to be any option to “setinstancehiddeningame” or “toggleinstancevisibility”. We could use removeinstance, but maintaining that is a royal PITA because internally the system uses removeatswap, this means we have to book keep all the swaps if we are associating data with instance ids. The one solution we have used since early 4.x is that we simply updateinstancetransform and set the scale 1000x smaller however in recent versions of unreal that appears to really mess with the lodding and fading calculations.
We have instances that disappear and re-appear right in front of the player as they walk closely.
Obviously hiding instances is possible otherwise they would not be able to be distance culled, occlusion culled etc. The question is, whether it’s feasible to introduce a new function that hides particular instances and then have code (likely on the render thread) that listens for those changes and hides them in the first culling step. We’d also probably want the option to destroy the physics state of that instance and re-create it when toggled.
Do you have any advice on whether this is possible or what the easiest path would be here? Am I missing something?
Thanks,
Brenden
We use FPrimitiveInstanceId
RemoveInstanceById. etc
[Image Removed]
Hi Brenden,
I don’t think it is possible to completely disable rendering of arbitrarily chosen instances, because they are all rendered by a single draw call. Usually, when this needs to be done, individual instances can have their transform changed (applying a scale or sending them far underground, for example). Another option is to use Per-Instance Custom Datato pass a per-instance visibility flag to the material. This can then be used to drive the “opacity” or “opacity mask” on a translucent or masked material, or “world position offset” if preferred. Here are the steps to achieve that:
- On your HISM component, select that component and set “Num Custom Data Floats” to 1 or more.
- On the blueprint that contains the component, use node “Set Custom Data Value” to set the visibility flag to 0 or 1 per-instance
- On the material, use node “PerInstanceCustomData” to access the assigned value and use it to drive the desired material attribute
I hope that is helpful. Please let me know if this solution works for you!
Best regards,
Vitor
Yeah it’s not a bad suggestion except that only handles the rendering side of things not the physics. You basically end up left with an invisible collider. The scaling issue addresses both and is what we’ve been doing since 4.21 however it seems epic has added some kind of instance averaging when calculating lods so as soon as one has been scaled down to “hide” the instance, other instances start lodding or fading out and back in at incorrect distances.
Hi Brenden,
You are correct, the “Per-Instance Custom Data” approach handles only the rendering side of the problem. For physics, other than working with instance transforms (scale or translation), I believe the next best option would be to add and remove instances as needed, while manually keeping track of index changes resulting from internal remove-at-swap operations. To achieve that without relying on internal implementation details, you can use delegate “FInstancedStaticMeshDelegates::OnInstanceIndexUpdated” (only available in C++), which will be called every time an instance has its index changed.
Note that, as Jeremy mentioned, there is also a built-in FPrimitiveInstanceId struct type, along with C++ related functions inside UInstancedStaticMeshComponent such as AddInstanceById() and RemoveInstanceById(). However, this API is not safe when using HISMs, since the instance IDs can get invalidated when its internal tree gets rebuilt. Moreover, invalidation can also happen when an ISM changes as a result of an undo/redo operation in the Editor, or when it is imported by serialization. Tracking index changes manually should not have these issues.
Also note that, since UE 5.4, regular ISMs offer per-instance LOD selection, which might be useful for you. Also, in my tests here, ISM LODs don’t seem to be negatively affected by setting a tiny/zero scale on some specific instances. HISMs are still required for granular frustum culling, though.
Finally, I should mention that I was able to observe how changing the scale of a single HISM instance can negatively affect the LOD selection of every instance. This does seem odd to me, but I went all the way back to 4.27 and it had the same behavior. Do you recall which older engine version has HISM LODs working well when changing the scale of some instances? If we can find the specific version where the behavior changed, I can try to report this as a bug so that the engine devs can take a closer look.
Kind regards,
Vitor
Hi again!
I think I just came up with a workaround that might allow you to keep using the technique of hiding individual instances by setting their scale to zero (or tiny). After looking through the code, I noticed that HISMs attempt to account for instance scales by performing the following calculation:
average_instance_scale = (max_instance_scale + min_instance_scale) / 2
This seems odd to me, since a single instance can completely skew the result. It is possible that this is a bug, maybe the devs should have made average_scale = sum_of_all_scales / number_of_instances instead, not sure.
In any case, if you need to zero out some instance scales, you should be able to trick the system by also setting some other instance to a scale of 2.0 (and hiding it from view). This seemed to work in my tests here with a single 2.0-scale instance for any number of 0.0-scale instances.
If you do attempt that, please let me know how it goes!
All the best,
Vitor
Hi Victor, our title that successfully uses this technique without errors is shipped under UE 4.21. I did a comparison between engine versions and average scale logic is absent in 4.21. It may have been added earlier than ue5 though (such as 4.22-4.27)
I’ll play with some source changes on our end to see if we can restore 4.21 behaviour. I think that would be preferable to scaling up instances and hiding them to counteract the engine’s math.
Ok, I found it. It seems that the average scale logic was added by CL 5225334 / commit 3b7e432 to address UE-59256 on February 2019, which aligns with the launch of 4.22. It was later optimized a little by CL 31941355 / commit e3b75e5 on March 2024. Hopefully seeing those changes can help you with your experiments.
I’ll also file a bug report about this, but since this managed to go unnoticed for so many years already, I’m not sure if the engine devs will consider it a priority.
Thanks that’s very helpful. I’ll try reverting some things here and if the older code is still compatible then that probably solves the problem for us.