godot-lod icon indicating copy to clipboard operation
godot-lod copied to clipboard

Take the camera FOV into account for LOD calculations

Open Calinou opened this issue 3 years ago • 15 comments

When the camera FOV decreases, the distances should be multiplied accordingly so distant objects still look detailed. The user-supplied camera distances will be specified for the default camera FOV (which is 70 in Godot 3.2.x).

There should be a project setting to disable this LOD adjustment in case it's not desired (e.g. for a game where the FOV is only changed for aesthetic reasons).

I've also considered using screen density-based LOD calculations, but they have an additional performance cost and some downsides (such as making high-resolution gaming even slower than it would be otherwise).

Calinou avatar Sep 25 '20 19:09 Calinou

How about an option is added to take screen coverage into account instead. That way, the LOD swapping is fov independent. I believe that this is the approach that Unity uses as well.

SIsilicon avatar Oct 12 '20 15:10 SIsilicon

@SIsilicon See OP:

I've also considered using screen density-based LOD calculations, but they have an additional performance cost and some downsides (such as making high-resolution gaming even slower than it would be otherwise).

I know this might be an unpopular opinion in today's LOD scene, but I stand by it :slightly_smiling_face:

Calinou avatar Oct 12 '20 16:10 Calinou

Don't know how I missed that in the post. 😅 That's understandable though.

SIsilicon avatar Oct 12 '20 17:10 SIsilicon

Question though. How would that method be slow on high resolution games?

SIsilicon avatar Oct 12 '20 17:10 SIsilicon

@SIsilicon The method isn't necessarily slower depending on the viewport resolution, but the end result will be slower since higher quality LODs will be selected on higher resolutions (for a given distance).

Lots of 4K displays have higher DPI compared to 1080p/1440p displays, making this high-quality LOD selection not as important as it theoretically should be.

Calinou avatar Oct 12 '20 17:10 Calinou

How would that be so? The screen coverage wouldn't be dependent on screen resolution, but rather by the percentage of the screen it covers. The result should theoretically be the same no matter what resolution is used.

SIsilicon avatar Oct 12 '20 17:10 SIsilicon

@SIsilicon I see… I always thought it was based on the number of pixels covered by the object (which would make it resolution-dependent).

Either way, I'm not sure if Godot exposes everything required for that – a mesh's AABB may not be representative of its actual volume. This would also make LODSpatial only work for MeshInstance-derived nodes, rather than all Spatial-derived nodes. Not to mention performance is critical for this add-on, so I'd prefer keeping computations as simple as possible.

Calinou avatar Oct 12 '20 17:10 Calinou

True. I decided to do a stress test with this method, and these were the results. Without LOD: 40 FPS Distance LOD: 36-37 FPS Coverage LOD: 32-33 FPS

These were from spawning 5000 static spheres in a 100x100x100 volume. It's strange that the FPS dipped with LOD either way though, even when I had a refresh rate of 3 seconds.

SIsilicon avatar Oct 12 '20 17:10 SIsilicon

Then again, that could be because of the draw calls themselves. If the LOD were to be implemented directly into a MultimeshInstance, things would've been different. It's too bad that you can't just make an addon for that.

Either way though, I like to see screen coverage as just another option. People don't need to use it if they don't want to. But there are people out there that do, and are used to Unity's way of doing things. Simply having both options would probably be a good idea. image Obviously some of the options would appear and disappear depending on the mode used.

This would also make LODSpatial only work for MeshInstance-derived nodes, rather than all Spatial-derived nodes.

Well I mean, it is screen coverage. You wouldn't really expect a node like Position3D to take up screen space.

SIsilicon avatar Oct 12 '20 17:10 SIsilicon

Then again, that could be because of the draw calls themselves. If the LOD were to be implemented directly into a MultimeshInstance, things would've been different. It's too bad that you can't just make an addon for that.

The performance drop is likely due to nodes being included in the octree if they're still hidden. To prevent this, you need to remove nodes from the scene tree entirely using remove_child() rather than hiding them. I could investigate this, but adding/removing lots of nodes in rapid succession might impact performance negatively too.

Obviously some of the options would appear and disappear depending on the mode used.

That means I can't use exported properties anymore and have to override the much more complex _get_property_list() method :slightly_frowning_face:

Calinou avatar Oct 12 '20 17:10 Calinou

To prevent this, you need to remove nodes from the scene tree entirely using remove_child() rather than hiding them. I could investigate this, but adding/removing lots of nodes in rapid succession might impact performance negatively too.

I could benchmark that (later).

That means I can't use exported properties anymore and have to override the much more complex _get_property_list() method 🙁

Trust me, it's not that complex once you get used to it. It was hard for me too at first, but now I use it all the time in my plugins, and it makes the plugin look more like part of the engine. 😁 If you'd like I can implement that for you.

SIsilicon avatar Oct 12 '20 18:10 SIsilicon

One more thing. I believe both distance based and screen based lod calculations have their advantages and disadvantages.

Distance Based LOD:

  • Simple to understand controls
  • Faster than the latter method
  • Doesn't work accurately with orthogonal projection, or perspective projection with varying Fov

Screen coverage Based LOD:

  • Works with both orthogonal and perspective projection out of the box
  • Calculates LOD levels more accurately then the former method
  • Slower than the former method

SIsilicon avatar Oct 12 '20 18:10 SIsilicon

Doesn't work accurately with orthogonal projection, or perspective projection with varying Fov

It works with varying FOV if you take it into account during the distance checks :slightly_smiling_face: This is relatively easy to do, and is already done in many other engines (even id Tech 3 did it IIRC).

As for orthogonal projection, do you need LOD in the first place when using it?

Either way, I'd prefer supporting only distance-based LOD in this add-on to keep it simple. I appreciate the effort, but I'd rather avoid bloat if possible. This is especially the case since finding maintainers to fix bugs can be difficult.

Calinou avatar Oct 12 '20 18:10 Calinou

As for orthogonal projection, do you need LOD in the first place when using it?

Zooming in and out in an isometric game for example.

This is especially the case since finding maintainers to fix bugs can be difficult.

I can be the maintainer. :)

SIsilicon avatar Oct 12 '20 18:10 SIsilicon

Here's what the UI looks like using _get_property_list. I'll open pull request with these feature, including a different way to update the LODs.

image

SIsilicon avatar Oct 12 '20 22:10 SIsilicon