godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.11k stars 69 forks source link

Implement mesh splitting for imported 3D scenes #3673

Open mrjustaguy opened 2 years ago

mrjustaguy commented 2 years ago

Describe the project you are working on

Large Terrains, From Blender, Loaded as obj

Describe the problem or limitation you are having in your project

obj have no auto Mesh Lod, and for Large (in terms of size, not polycount) meshes, just slapping auto Mesh Lod wouldn't work anyway due to the Massive size of the Mesh, that you will often be close to.

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

Adding an Auto Mesh Splitter for importing obj files and then running the Auto Mesh Lod would allow for Large Static Meshes to be simply dumped into Godot, and be used with Great Performance, compared to what we currently have. Since obj don't have Bones and thus no animated parts, they can be split into smaller meshes (I'd call them meshlets, but that's already taken by Mesh Shaders, which this would not be related to)

obj meshes with this style of Import should be imported as Scenes only, with a root node that has the number of meshinstances that the Mesh was split into, each having their corresponding mesh parts

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

On Import of obj files Check AABB of the resulting mesh.

If AABB > Mesh Size Limit (Import setting) Divide Mesh by Mesh Size Limit (so just start making Mesh Size Limit AABBs from center, like they're voxels, and every triangle inside a given MSL AABB is assigned to the New MeshInstance in the Composite Scene)

When all Cells with Mesh Parts are found, Make auto Lods for all the Mesh Parts, when this is done, Load the obj as a scene

Note: if cell size is for example (1D Vector for simplicity, apply logic to 3D Vector) 1, if you have a triangle which has points 0,0,2, the triangle will be in both Mesh Parts if it's not somehow deterministically placed in one mesh or the other. Probably the best way to do this is to cut the triangle at the cell edge, which will result in 3 triangles from that 1 triangle, but will be friendlier for Auto LOD to process without causing significant cracks in the end result mesh when each submesh is at different LOD

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

No.

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

This would go hand in hand with Auto LOD feature in Godot 4

Calinou commented 2 years ago

Note that this can only be implemented for meshes imported as part of 3D scenes, not 3D meshes (OBJ files) unless you switch their import mode to Scene. This is because a 3D mesh import needs to have a single Mesh resource as the output. If you need several meshes, you need to have a scene as an output.

For Godot 3.x, there's an add-on that provides mesh splitting and merging: https://github.com/lawnjelly/godot-splerger

mrjustaguy commented 2 years ago

that was already noted and implied a couple of times in the proposal.. however it is indeed a very important thing to remember during implementation, so extra emphasis can't hurt.

anunknowperson commented 2 years ago

sounds very useful for imported terrains

mrjustaguy commented 2 years ago

Imported Terrains, Massive Ships/Bases, really anything that is larger than 10 units, in the 100s+ range, and basically a must have for 1k units+ range

fire commented 2 years ago

Any support for porting Splitting many meshes by Grid to a c++ module?

func split_branch(node : Node,
  attachment_node : Node,
  grid_size : float,
  grid_size_y : float = 0.0,
  use_local_space : bool = false):

This will search recursively and find all the MeshInstances' in the scene graph that are children / grandchildren of 'node', and perform a split by grid on them.

Reference

https://github.com/lawnjelly/godot-splerger

fire commented 2 years ago

Both #3673 and this #901 are the same. Crosslinking.

mrjustaguy commented 2 years ago

Actually, they're exact opposite in what they want, but both have to do with cutting up or batching cut up meshes.

lawnjelly commented 2 years ago

I do suspect in terms of LOD, dealing with the cracks between object LODs may be the biggest obstacle to overcome. If you can identify the verts of the seams and lock them to prevent simplification this may help deal with the problem (if the simplification library mesh_optimizer allows this, which is pretty crucial).

Splitting polys may not always be necessary I guess, it depends on the mesh etc. You could just choose a best fit seam for preserving (based on a low number of edges) and use this. This is what nanite uses afaik .. their meshlets are pretty freeform rather than on a grid I think.

However while that might work for terrain it might not work so well where several separate objects overlap a border, and there is no obvious seam. In that case as you say splitting polys might be a good solution to prevent cracks.

mrjustaguy commented 2 years ago

Dealing with the cracks is fairly easy. You essentially have 2 types of Triangles in each cell: 1) Triangles fully in the cell - These can be simplified without looking at the higher cells no problem 2) Triangles partially in the cell - These you split into smaller triangles of Type 1, and keep the vertices on the edge of the cell as data for doing LODs.

Now, as a cell is a Cube, and they're stacked right on top of each other, you know that each of the Cell's faces is shared with exactly 1 other cell, so to prevent cracks, all you need to do, is make sure that for every cell edge, the vertices on the cell edge must match when you're simplifying the mesh.

This results in a little bit of extra geometry... However there is a way to cut that geometry out at large distances while keeping it crack free, and that is to merge cells and simplify those mega cells which would be 2(x,x,x) in size x is the cell size, so 1(1,1,1) is smallest cell, 2*(1,1,1) is a (2,2,2) cell, and it could be composed into a (4,4,4) cell etc)