There’s a few different systems involved, but LODRequirementsUpdateSystem.cs will get you started. They bake LODGroups.
One thing worth noting is that skinned meshes with LODs have a negative impact on performance. I’ve fixed this in my own tech.
There’s a few different systems involved, but LODRequirementsUpdateSystem.cs will get you started. They bake LODGroups.
One thing worth noting is that skinned meshes with LODs have a negative impact on performance. I’ve fixed this in my own tech.
So I have a few questions on this DOTS 1.0 LOD workflow and I can hardly find any information about it. I’m sure one of the experts in here will be able to clarify.
In the EntityComponentSystemSamples example there is a scene for LODs. Basically it has 100 LOD group parent objects, each with three children representing 3 LOD levels.
When I press play, or in the baked scene… there are 400 individual entities! So that’s a little annoying because it clutters up the entities hierarchy and makes it difficult to find the entity I’m looking for. They all have transforms. I think that 100 of the entities represent the groups, and the other 300 represent the meshes.
The real thing that is bugging me is that there are now 3 renderable entities per actual entity. Say I want to add a few authoring components to the same entity that the MaterialMeshInfo component is on so that I can query the two components together. I now have to add that authoring component to all 3 child objects? If that authoring component has a bunch of parameters on it, then every time I need to tweak the parameters, I have to change them in 3 places? This seems like a messy workflow. I would much rather have ONE object and ONE entity that points to 3 different meshes.
Another minor question I have is - what’s up with a box collider being on each LOD child object? Is that necessary and used for a render bounds box or is it just there because no one removed it?
There are 400 entities because there are 400 GameObjects. It is a 1-1 bake. Inside each LODGroup are 3 renderer GameObjects.
Propagating material properties is trickier than most would like, especially since baking is really bad at relationship-dependent components. The problem also exists for renderers with multiple materials. There’s not really a good solution to this either as not all properties should be propagated automatically.
If you want to go deeper into the details of the specific material property problems you are trying to solve, I can provide some tips on how to make the system as low-overhead as possible.
Thanks!!
Because of the triple mesh renderers, it’s rather weird integrating it into my texture baked vertex animation library. The animation System is setting various custom Material Properties to advance the animation frame, determine which clip is playing, set playback speed, etc. But now with LODs I suspect that system is running on 3x the entities. I guess maybe that’s just part of the tradeoff for having LODs? I probably shouldn’t complain since it did bring 100k entities with 1890 vertices each from 8fps to 50fps on my laptop.
This is the first time I’ve used LODs, so I’m just stumbling around here. The main issue is that it makes the texture animation baking workflow cumbersome.
I have another question… so unlike the demo which has all the boxes static and fixed, i need my entities to be movable (ie they need a localtransform). If I didn’t have a LinkedEntityGroupAuthoring script on the parent, the entities didn’t appear after pressing play. When I looked at the profiler, the penalty was huge for CmputeChildLocalToWorldJob … like 4 or 5ms compared to the animation System which is at 0.01ms. Is there a way to split them out into separate entities without a parent or get the child transform stuff to run faster?
TransformUsageFlags can force an entity to be baked using world-space transforms. That’s what Unity Physics uses.
Oh wow, that’s crazy - I had no idea you reworked the transform system! It seems like it would be difficult to swap my whole game over to use those transforms instead, especially since I’m using unity physics every now and then?
Because the transform system is so heavy those 3 child objects were just hammering the CPU even when zoomed in and only a few entities were in the same field of view. I attempted to use TransformUsageFlags.WorldSpace to break the children out, but the LODs would end up not being rendered - I think it’s because unlike the Unity example where all entities are fixed and never move, my LODs need to move when the parent moves.
So I did a little experiment… I tried manually flipping through the LODs based on distance-to-camera using MaterialMeshInfo.
I simply registered the meshes and materials and then wrote a system to possibly swap them every 0.25 seconds.
[BurstCompile]
public partial struct SimpleLodJob : IJobEntity
{
public float3 CamPos;
[BurstCompile]
public void Execute(ref MaterialMeshInfo mmi, in SimpleLodData lod, in LocalToWorld ltw, in SimpleLodDistData lodDist)
{
if (math.distancesq(CamPos, ltw.Position) < lodDist.Dist0Sq) {
mmi.MaterialID = lod.MatId0;
mmi.MeshID = lod.MeshId0;
} else if (math.distancesq(CamPos, ltw.Position) < lodDist.Dist1Sq) {
mmi.MaterialID = lod.MatId1;
mmi.MeshID = lod.MeshId1;
} else if (math.distancesq(CamPos, ltw.Position) < lodDist.Dist2Sq) {
mmi.MaterialID = lod.MatId2;
mmi.MeshID = lod.MeshId2;
} else {
mmi.MaterialID = new BatchMaterialID { value = 888 }; // invalid number hides the material
mmi.MeshID = new BatchMeshID { value = 888 }; // invalid number hides the mesh
}
}
}
Result: The 4ms taken by the child-transforms (using 100k animated entities) is gone! When zoomed out the results are similar, but when zoomed in I gained 80 FPS. For some reason, the Unity LOD system was causing big spikes that made camera movement jerky by dropping FPS really low every so often - those are now all gone and everything is smooth as butter. Also, the Unity LOD jobs were taking between 2ms and 3ms (not including the child transform stuff), so that performance hit is now down to the 0.45ms taken by SimpleLodJob.
So there are some obvious difference between my blue-collar LOD system and Unity’s fancy one.
At this point, I’m leaning heavily towards using my own LOD. However, I’m still new at this LOD stuff. Can you think of any reasons why it would be better to use Unity LODs instead?
The technique I describe can also be applied to Unity Transforms. You only need to swap out the systems, and all the components and rules stay intact. That’s what I did for Transforms V1. And I will probably do it for Unity’s latest Transforms if I have enough of an incentive to.
The big difference is that you are evaluating the LODs for just the main camera at a sparse rate (so you have to be careful about camera cuts). Unity is evaluating LODs for each culling pass, whether they be cameras, shadows, probes, ect.
With that said, their actual LOD algorithm is super old, and probably has some nasty performance edge cases since I think its caching was designed for static scenes and a single culling pass. I have the entire Entities Graphics stack refactored so that I can easily swap out the LOD algorithm with something else if I ever end up with a project where LODs are costly. That hasn’t been the case yet, but if you wanted to see how your algorithm fairs directly in the culling loop, it wouldn’t take me long to wire it up into a custom Latios Framework version.
As for cross fades, those aren’t supported in Entities Graphics. I haven’t taken the time to figure out how the technique works and can be adapted to ECS. But if I do figure it out I’ll definitely implement it.
That’s a good point about camera cuts, so if I ever need to deal with those I’ll bump it back up to every frame because I easily can adjust the interval. Either way, per frame it’s 5.5x faster than Unity’s LOD calculation (15x if you count child-transforms) so it doesn’t really matter too much.
That code I pasted above is the core algorithm of my LOD system… it’s embarrassingly trivial! There is a little bit of setup code by way of authoring components and such. I’ll probably convert it to an array instead of mesh1, mesh2, mesh3, but that’s about the only change I have planned and it’ll only take about 15 minutes to implement.
From what I read, they do crossfades by showing both meshes during the transition window and increase the transparency of the new one while decreasing the transparency of the old one. I’m guessing shaders would be used, but tackling that is above my paygrade.
Anyway, thanks again for all your help!! You always have the best info!
Sorry for necro, but perhaps you had success after 1.0 release? I’m still not satisfied with instancedindirect way, as it’s still halving my FPS, I’m also making tropical island with kinda same goals as you.