Mesh LOD 2025

Yes the 6.2 version is our own and improving the LOD generation is part of our roadmap.

3 Likes

Will we be able to use MeshLOD with ProBuilder meshes?

Well actually if you export the mesh and then reimport it with ProBuilder I think it should work

Outstanding! Thank you for this awesome contribution to Unity!

I fully agree! I suspect the vast majority of users (nearly everyone?) who uses Mesh LOD desires Imposter support. I’ll vote on the roadmap for this capability.

Please consider lifting this limitation.

1 Like

This looks great! I’ve been very excited for this.

I’m curious how the LOD generator handles textures? I assume it does this by maintaining UV attributes when simplifying, but that can sometimes lead to weird issues when UV islands stretch across simplified regions. So I’m assuming that reducing texture-stretching on screen is ‘best effort’?

Is the idea that this generator is sort of a ‘simple first pass’ and users would swap in more advanced LOD generators if they have more advanced needs?

1 Like

Mh… I would think that if the LOD has this problem it probably will be far away enough

I know that I can do that, but I would like to be able to make modifications to the mesh and get the benefits of MeshLOD without having to re-export every time.

1 Like

In LOD Groups with multiple renderers there could be then different textures for each LOD. In the existing system is there any (GPU memory or performance) benefit to provide say 2K textures on LOD0, 1K textures on LOD1, 512 on LOD2 etc.? How are textures dealt with in LOD Groups?

If using MeshLOD, would the texture strategy change? I’m assuming there is only 1 set of materials.

Yes we do support both use cases as we keep sub mesh and material information across LODs.

1 Like

Mesh LOD is not yet fully compatible with ProBuilder. There are some known limitations with tools like for example Polybrush.

Glad you like it :grin:
For the LOD cross-face feature support, we are indeed considering lifting this limitation.

2 Likes

I’m curious how the LOD generator handles textures? I assume it does this by maintaining UV attributes when simplifying, but that can sometimes lead to weird issues when UV islands stretch across simplified regions. So I’m assuming that reducing texture-stretching on screen is ‘best effort’?

MeshLOD tries not to break UV seams, up until it can no longer decimate the mesh without breaking seams, and then will give best effort.
The decimator takes UV seams and curvature into account and tries to minimize attribute error.

Is the idea that this generator is sort of a ‘simple first pass’ and users would swap in more advanced LOD generators if they have more advanced needs?

The idea is indeed to keep flexibility so users can swap in custom / more specialized LOD generator. That was one of the biggest user requirements. We do have some improvements in our backlog though for our own generator.

1 Like

If that’s the case is probably worth mentioning this limitation in the documentation.

1 Like

There are lots of great questions in that message :grin:

Is it safe to assume we should not enable Mesh LODs on these types? e.g. for VFX meshes, because we won’t be able to obtain any benefits of those?

You assumed correctly. Today though there is an LOD system that exists within VFX that you could use.

Then, does the the index buffer obtained by the mesh have any indicator via c# to which indices belong to which LOD level? do we have any access for manual mesh runtime building / manipulation, to set these?

The MeshLodRange link is uhh, leading to a missing page :sweat_smile:

I’m sorry. I’m not sure what happened with the documentation :thinking: . Here is the correct page

MeshLODRange is a list of indices to take into account for a LOD.
Mesh.GetLOD and Mesh.SetLOD are probably the functions you are looking for. They should provide the list of indices for each Lod and also allow you you to define LODs.

Mesh LOD supports the LOD cross-fade feature only when the GPU Resident Drawer is enabled in a project.
Any particular reason for this limitation? would this also apply in the case of skinned meshes?

It is one of the current limitation but it is not bound to stay that way. We have not yet implemented the other paths. It indeed also applies to skinned meshes.

  • Is it possible to extract the Mesh LODs as their own HLODs? so we can reap the automatic authoring benefits while still using HLODs?

Could you give us a little bit more details? What do you mean by their own HLOD? Are you talking per chance of LOD Group?

  • Do you have any numbers on the general performance cost of skinning vs rendering a mesh? is this a significant reduction in the benefits or is it still beneficial to use Mesh LODs in the case of skinned meshes?

As long as your skinned mesh quality is acceptable, it makes sense to use MeshLOD for performance reason. You will get all rendering related benefits of MeshLOD but what you don’t get is better skinning or blendshape performance. Maybe we could add more clarification on the documentation.

I was under the impression unity converts all faces to tris on import, does this refer to ‘keep quads’? if yes, does this mean that ‘keep quads’ and ‘mesh lods’ are exclusive features to each other, or, do Mesh LODs simply not touch quads? (such as in the case of a mesh that has both, for whatever tarnished reason)

It is currently a runtime limitation.

So what value is actually used to determine which LOD will get picked when saying ‘size on screen’? renderer’s bounding box? renderer’s position? does scale play into this properly? if bounding boxes, are there any traps as to how a mesh might get authored to to have inflated bounding box that chooses LODs wrong? (such as a thin pole, placed 45 diagonally to inflate AABB bounding box?)

It is not related to the bounding box, so there should be no trap to avoid linked to the bounding box. Could you give more details about what you mean by does scale play into this properly?

3 Likes

Can we have per-renderer LOD Bias/Threshold?

Also, is there an example on how to use MeshLOD with BatchRendererGroup?

Thank you for linking that! And the question was for project-automatic importer settings - If a mesh is designated for VFX to not just auto-let the Mesh LODs be enabled.

Yup! Thank you! :grinning_face_with_smiling_eyes: I love that there’s also plurals for those methods. Extremely useful!
One thing that I sometimes deal with is visual effects where the (skinned mesh renderer) character copies their own skinned & posed mesh as an after effect. I didn’t consider this until this point is how LODs interact with SkinnedMeshRenderer.BakeMesh - The current paradigm involved getting all rendering meshes at the time and if there are skinned meshes, calling BakeMesh on them for that pose.

When using MeshLODs, Will BakeMesh bake the full mesh or just the triangles for its currently used index set? I assume that, since it bakes to a separate mesh object, it would only copy the relevant index set’s triangles over?

Similarly, Is it correct to assume that for those using MeshLODs, that properties like IsLOD0 become irrelevant? (if they weren’t irrelevant already)

Apologies, yes! :grinning_face_with_smiling_eyes:

The LODGroup paradigm enables working with MonoBehaviour.OnBecameVisible MonoBehaviour.OnBecameInvisible messages to enable and disable the certain behaviors when LOD levels switch. MeshLODs don’t enable this pattern - which is fine as it is replacable by scripting, just not an automatic switch.

Enabling and disabling expensive components including but not limited to dynamic bones, particle systems, constraints, etc of LODGroups, and, the authoring experience of just having an automatic “Make LODs for me!” from MeshLODs, is tantalizing. Since with the current solution level, we have to technically choose between the two, I wonder which way offers the best set of tradeoffs.

On the one hand, with the existence of Mesh.GetLODs its entirely possible to export the index sets as their own meshes on a per-object setting in an asset post processor. Correct me if I’m wrong but I should just be able to post process a mesh, see if the importer has a label like “ExtractMeshLodsToLodGroups” and then just grab the meshes in that importer + their lod levels + write new meshes with just the relevant triangles (and add the LODGroup components to the prefab) - gaining the benefit of “automatic LOD generation”. Losing the lower memory footprint of MeshLODs but gaining the automatic generation within Unity’s editor.

On the other hand, I can just make a script which, with polling (sadly?) refers to all game camera’s positions and, if any of them via frustum + distance check are within a given distance, allow behaviors to occur. Far less performant but probably rare enough that it shouldn’t be problematic. Can also probably be slightly staggered to only run once per few frames.

The first hand’s solution sounds far nicer though.

Yeah - and when I think about this further, trying to give users an expectation of metrics on the gains vs impact is subject to too many variables such as the shader, visible portion on screen, etc.

Given the statue example where a high poly mesh gets decimated, and, a user creating a scene with differently scaled versions of this statue. The original statement of MeshLODs is that it uses the “size” of mesh on the “screen”, so…

  • Assuming the original statue’s scale is a normal human’s head
  • If I have Eiffel tower scaled sized statue, and I’m close to it, Its expected to render at full detail… unless it checks by the object’s center. In which case, me being “close” to it is a stretch because it is, in fact, eiffel tower sized, so I can’t reach the center. If it checks the nearest face, then I’ll count as close. Similarly, if it checks the bounding box, I’ll be close.
  • If I have a keychain scaled sized statue, and I’m putting it on a booth 3 feet away, it’s expected to render at low detail, but if I take the camera close to it for inspection, it’s expected to reach high detail… but depending on how sized is picked, I suspect this won’t be the case, per the example above. Scale impacts the ‘size’ of the mesh on screen.

The original LODGroup component had an ‘Object Size’ float which I assume was just a distance subtraction from camera distance based on Object’s position. There was also a RecalculateBounds method though I’ve never used it. I assumed that, because of the two above, the object position and bounds are relevant. I’ve also gone and confirmed that the transform’s scale impacts which LOD is picked - good!

If bounding boxes were to be used - then, depending on if they are calculated for the imported mesh and are axis aligned, they’re prone to ‘bad fit’ (such as taking a stick and putting it diagonally, massively inflating the bounding box area.

Similarly, if Size is a float and isn’t the ‘central spot’ of the mesh with the lowest radius, we enter different problem spaces. This issue already exists with LODGroups most likely, and enough details are exposed on the LODGroup component that the developers can optimize for their project’s case.

I guess - my point is I’d love the documentation to note how distance vs ‘size on screen’ is actually calculated, please! :folded_hands:

Also, I’m thankful for the thorough response! :star_struck:

Isn’t this roughly the same concept as unreal’s nanite? Or virtual geometry as the chinese unity version (and unreal actually) calls it?

Or is this something different?

1 Like

would be cool to use specific LOD for shadow calculation or as raytracing structure: render at higher LOD, use lower LOD for shadow / as input for raytracing structure; either fixed level for both, or dynamic relative to render LOD. This should give an even bigger performance impact while keeping visual fidelity mostly same.

6 Likes

Since with LOD Group, each LOD is actually one or multiple renderer, you can have different materials.
You can find the LOD in
MeshLOD, on the contrary, doesn’t allow for material changes, all LODs use the same materials.
If memory usage is an issue, you should have mipmaps enabled on textures to take advantage of mipmap streaming. It should help you achieve the desired result.

Mesh LOD has a per-renderer LOD bias. It is documented in the Mesh Renderer component reference. Does that correspond to what you were looking for?

Increasing the “Selection Bias” makes it ignore the nearest LODs.
“Mesh LOD Threshold” from Quality settings is what I need