HISMC bug, always shows lowest LOD

HISMCs are currently broken in master. They always show the lowest LOD available for a mesh, so if you have a HISMC with a tree mesh set, you would always see the billboard of the tree and no matter how far you are away from it or how the settings for that specific mesh are, it never changes.

I know master is not supposed to be stable, but I would be interested if this is a known bug since the HISMC code in master does not seem to have changed since at least a month, and I tested 4.14 and the bug is not in there.

Thanks for the notification, John. I wasn’t aware of this. I’ve filed ticket UE-38930 to make sure it’s fixed.

Oh, we had something similar during 4.14 development which was due to the newly added Cinematic quality level overrides the LOD distances, but in that case it was always using the highest LOD. I’m willing to bet this has a similar cause.

Thanks ! I’ve actually noticed that it’s not completely broken, its just that the screen size seems to be off by a factor of 1000 or something like that. So what usually would be a screen size of 0.5 now more equals something like 0.0005 and then the LOD transitions actually work again.

So not the LOD transition itself is broken in master, just the screen size calculation for HISMC instances is. But since the last dev-rendering merge to master was more than 2.5 weeks ago, maybe it’s already fixed there :slight_smile:

Thank you John Alcatraz for precisely observing this bug. I can also confirm it in master 4.15 since 4.14. For example, KiteDemo/GDC_Landscape_01/Forest_and_Lake, all the foliage instances of HillTree_Tall_02 are stuck at last LOD3. If the foliage instanced assets have last LOD Screen Sizes set at 0, it hides the bug. Regular (non foliage, non HISMC) instances of the assets are working ok, as in 4.14.

Quick solution “foliage.LODDistanceScale 20000”.
More info: Solution: Foliage & HierarchicalInstancedStaticMesh stuck at last LOD with master 4.15 - C++ - Epic Developer Community Forums

I’ve tried that, but its still not working too great.
, are you sure this will get fixed in 4.15? Any guess on when the fix will be in master?

Hi John, I don’t have any schedule for this yet but it’s marked as a regression and it’s Priority 1 so we will definitely fix it for 4.15. I’ll try to get to it before Preview 1.

Thanks ! Thats great to know :slight_smile:

Hi John,

I checked in a fix just now. I think it’s too late to make preview 1 but it will definitely be in preview 2. If you are able to look at it before then, that would be awesome also. The fix is here:

The cause was a change in the screen size calculation we use in the rest of the engine and HISMC LOD needed a rework. It also now supports disabling the “Dithered LOD Transition” material flag which fixes black dither during LOD transitions for materials that don’t set it.


Great, thanks! :slight_smile:

I am using master for my project, so I will probably have to wait until that fix appears in master to try it out. It will be in the next dev-rendering merge I guess?

No, 4.15 is merged to master separately. After Preview 1 is released, we will merge, but it looks like the code went into the staging area on 1/17 so that merge will not contain this fix. We usually merge to master after each preview release.

Thanks ! I switched from my old master to 4.15, so I was able to test this now.

It seems to work fine :slight_smile:

I don’t really understand why the screen size of LOD0 has no impact at anything though, since after screen size is > 1, always LOD0 is visible. So its no longer possible to say that a tree should switch to LOD0 only after a screen size of 2 is reached. I actually don’t remember how it was before. That seems to be same for a regular static mesh too, so it’s not related to HISMCs. If that’s considered a bug, its a general LOD bug.

As far as I can tell, HISMC instances now have same LOD transition distances like static meshes, so this bug is indeed fixed!

I have noticed something else too, that might be another HISMC bug in 4.15. I just made my tree system use pooled instances so that I no longer have to add and remove instances while the game runs, so on begin play I add 5000 instances at 0/0/-10000 location with 0/0/0 scale and 0/0/0 rotation, and then later I update individual instance transforms when I spawn a tree. Now there’s the bug that the bounds of the HISMC are not updated when I update the instance transform. So I call UpdateInstanceTransform for multiple instances and give them a new location of something like 1000/1000/2000, but if 0/0/-100000 is out of the camera frustum, the instances are invisible. Once 0/0/-100000 is inside the camera frustum, the instances become visible.
So the bounds are not updated correctly.

I do set MarkRenderStateDirty to true when I call UpdateInstanceTransform. I also tried calling MarkRenderStateDirty() manually on the HISMC later, but that also doesn’t help.

Hi John,

I’m not sure about the first bit, I’ll ask another engineer who made the general screen size change for a comment on that.

For the second isssue, there’s not really an advantage to adding instances before-hand and moving them later. Is there any reason you don’t just add them when you need them, and if you do so does everything work correctly?

The code in UpdateInstanceTransform only attempts to update the bounds calculation if the instance location doesn’t move (search for bDoInPlaceUpdate). In other cases where the location is also updated, which is what you’re doing, the update gets treated like a delete of the old instance, and an add of a new instance with the new transform.

What I’m not sure about is why this doesn’t work automatically in your case.

If I add them when I need them then yes, it does work correctly.

I switched to the pooled way because I hoped there would be some performance improvements when I have a constant amount of instances in the world, at least it should help with memory allocations since it doesn’t need to constantly allocate memory when a new instance is added or free memory when an instance is deleted.

Also, I need indices that keep their number when I “remove” another instance, so I can’t really remove instances since that would cause instances with a higher index to lose the index they had before. So on remove I have to pool them anyway, and I just thought if I already do that I can also just create a pool on begin play and always use that.

The problem seems to be that bDoInPlaceUpdate is always true if I update an instance transform, even though I modify the location of the instance.
bIsOmittedInstance is false, and bIsBuiltInstance is true.

Hey , here is the commit that broke it:


That commit removed the “!” before bIsBuiltInstance, which causes bDoInPlaceUpdate to always be true in my case.

Right, that change fixed another bug but introduced this one.

We can only do in-place updates for built instances that don’t change location, so what we really want is:

const bool bDoInPlaceUpdate = bIsBuiltInstance && NewLocalLocation.Equals(OldTransform.GetOrigin());

That works, thanks very much! :slight_smile:

Hi, thanks for checking this out - the limit on the screen size for LODs other than LOD0 is just a clamp in the details customization for that struct (FLevelOfDetailSettingsLayout::OnLODScreenSizeChanged). Looks like it is an oversight for static meshes (and those things that use them, like ISMCs and HISMCs).

Ill get a fix in ASAP.

Thanks, I submitted that for 4.15.