godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.15k stars 97 forks source link

Implement static objects and batching in Godot #2049

Closed Arnklit closed 3 years ago

Arnklit commented 3 years ago

Describe the project you are working on

Various 3D projects

Describe the problem or limitation you are having in your project

Creating large scenes with many identical objects in Godot is not performant due to the lack of batching.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

I think Godot should have the concept of static objects that are automatically batched by the engine.

I have heard that the reason Godot does not have the concept of static objects is that it is seen as confusing for beginners. I'd like to argue against that, there is inherently quite a bit of complexity in getting into 3D, but the idea of static objects is not more complicated than the concept of MultiMeshInstances or merging meshes with scripts and understanding how doing so incorrectly might make performance even worse due to lack of culling.

Currently when a new Godot user tries to make a big 3D scene and starts having issues. Rather than telling them. Set your static objects. We end up with discussions of how people should write their own complicated systems to handle MMIs or merge objects - not very user friendly.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

A "static object" checkbox on MeshInstances. Then the renderer should handle the batching for the user.

If this enhancement will not be used often, can it be worked around with a few lines of script?

This enhancement would be used often.

Is there a reason why this should be core and not an add-on in the asset library?

Good performance in 3D scenes should be built into the engine, not reliant on third party assets that might not be up to date.

Zireael07 commented 3 years ago

1) Static objects is a Unity3D specific term, I had to google around to find that out. 2) Static objects are only used in Unity for occlusion culling, which Godot still does not have...

Arnklit commented 3 years ago
  1. Unreal also uses the term. I could have referred to it as static mesh if that makes more sense https://docs.unrealengine.com/en-US/WorkingWithContent/Types/StaticMeshes/index.html
  2. No it is used for batching https://docs.unity3d.com/Manual/DrawCallBatching.html
Zireael07 commented 3 years ago

Godot already batches draw calls for objects using the same materials, I believe - no need to specially mark objects as static.

Arnklit commented 3 years ago

I thought it did as well, but from testing it was pretty clear it doesn't. And Calinou confirmed it here. https://www.reddit.com/r/godot/comments/kg5ikl/is_there_3d_batching_in_godot_3x/

omicron321 commented 3 years ago

Currently when a new Godot user tries to make a big 3D scene and starts having issues. Rather than telling them. Set your static objects. We end up with discussions of how people should write their own complicated systems to handle MMIs or merge objects - not very user friendly.

We would need sample of such code or scene new users struggle with. Multimesh is already providing batching. It uses any mesh as a "static" mesh, with its .mesh property.

Zireael07 commented 3 years ago

@Omicron666: Multimesh is difficult to use for most new users. Also it requires meshes to be identical.

Example main scene that has (not too big, but still) issues: https://github.com/Zireael07/FreeRoamRoguelikeRacerPrototype/tree/master/game

also: https://github.com/TwistedTwigleg/Godot_FPS_Tutorial (this one uses gridmaps, and you'll likely need to assign the grid library again as it's mysteriously unassigned on first load. The desert level does not use GI, unlike the space level)

Arnklit commented 3 years ago

@Omicron666 I will try to work on a test scene to show the issue.

The big problem with MultiMeshInstances, is that there are no beginner friendly ways of using it. There is no built in way to take a level where you've placed your objects by hand and optimizing it with MMI. And even if a user can figure out how to convert meshInstances into an MMI with a script, they still have to guess at what a good chunk size might be for the MMI to still allow some amount of frustum culling.

omicron321 commented 3 years ago

@Arnklit ok thanks. i understand this doesn't fit with pure manual 3d editor workflow without code, but how many instances we are talking about?

fire commented 3 years ago

Merging objects in Unreal Engine is a wait one to ??? minutes procedure, you can't do that per frame let's say every 6ms. I don't expect Godot to do better than that.

Call of Duty https://research.activision.com/publications/2020-09/lima-oscar-delta--scaling-content-in-call-of-duty--modern-warfar mentions using 12 hours to generate LODs for batching their 200 player maps. This is also not a 6ms thing.

A possible proposal is a LOD where non-moving groups can be combined, and when they move they are separated. This is also known as hierarchical LOD.

See

I don't think static mesh batching is doable as an online rendering feature, it'll have to be part of the import pipeline.

This is very similar to https://github.com/godotengine/godot-proposals/issues/901.

golddotasksquestions commented 3 years ago

@fire I would assume this to be an Editor setting, not something to be used during runtime.

Zireael07 commented 3 years ago

Yep, with the caveat that my proposal is specifically for imported stuff, while this one is more general and applies to Godot's primitive meshes for example (and I assume CSG too)

fire commented 3 years ago

I don’t think its possible to do at runtime unless you go into the realm of runtime mesh generation similar to csg and you’ll have to combine the materials and mesh in a compute shader to be fast enough. Sony Dreams uses a splat point cloud rendering and UE5 uses something else.

omicron321 commented 3 years ago

there is a system more or less using that "static" instantiation, MeshLibrary resource used with GridMap

Calinou commented 3 years ago

The recent optimization work brought support for 3D instancing (which is a form of dynamic batching). This supersedes this proposal considering that Vulkan draw calls are already significantly cheaper compared to OpenGL.

Instancing is used to render similar objects (mesh, material and misc settings), reducing the pressure over the rendering API.

Mesh merging should be discussed in https://github.com/godotengine/godot-proposals/issues/901.