godotengine / godot-proposals

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

Make placing MultiMesh instances manually easier #5352

Open me2beats opened 2 years ago

me2beats commented 2 years ago

Describe the project you are working on

A 3D game

Describe the problem or limitation you are having in your project

In Multimesh editor there is only Populate mode, but it doesn't allow you to add instances manually, you need to do this with code, which is not handy. For example you want to add a hundred plants in a forest scene but in a way you exactly want.

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

I would like to work with MultimeshInstances just like with nodes: have a list (Tree) of instances (populated objects), which you can select, remove, move, rotate etc.

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

see above, screenshots maybe will come soon. The data can be stored using set_meta() maybe.

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

Imo this will be used often when adding many objects to scenes.

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

See above

YuriSizov commented 2 years ago

See above

A fair answer to that question would be that there are several addons for that, like Scatter or more recently Spatial Gardener. Though I agree that some built-in tools for manual placement would be nice to have.

clayjohn commented 2 years ago

I agree an editor would be amazing. Doing something properly would like be a lot of work, but should be doable. This is also something that can get prototyped in a GDExtension before being merged into main.

mindinsomnia commented 2 years ago

I would like to work with MultimeshInstances just like with nodes: have a list (Tree) of instances (populated objects), which you can select, remove, move, rotate etc.

Further to this, a simple 'draw' tool to create an instance at a specific location would be nice.

Here's a suggestion on how such a tool might work:

  1. Left click and hold down left click to create an instance at a location.
  2. Drag mouse to adjust scale of the instance and let go of left click when finished.
  3. Drag mouse to rotate instance.
  4. Left click to confirm placement, scale and rotation, or right click to cancel.

That would allow for controlling an instance's placement, scale and rotation in just 2 mouse clicks with an option to cancel the placement quickly as well.

Extra Option: Option in tool to align new instances to a specific axis, or to the normal of the surface they're being drawn on.

Zireael07 commented 2 years ago

@mindinsomnia Several scatter/foliage painting addons already exists that work mostly like you wrote

warcanin commented 1 year ago

One solution would be to allow importing instances from blender as multimesh. You woul have an object with a "-multimesh" hint that is the parent of all the instances, with that you would be able to edit it before you export it and you could even export godot multimesh to blender edit them and import them again.

synalice commented 10 months ago

I think a good workflow should be as follows:

  1. You place your mesh inside the MultiMeshInstance3D in the Inspector (the same way as it's done right now.
  2. You place instances of this mesh as nodes inside your scene, transforming them as you need.
  3. You move all these nodes in the scene tree under the MultiMeshInstance3D as its children.
  4. These meshes then will be rendered via GPU instancing.

This way you can both position meshes as you want and use the GPU instancing.

Another Quality of Life feature would be adding a custom property to MultiMeshInstance3D — a Node3D scene. This scene will be placed together with each mesh. It could be used for adding things like collisions. The same way Spatial Gardener does things.

Are there any potential issues with this approach?

donn-xx commented 7 months ago

I made a plugin called MetaMultimesh3D to try help this situation. It's here: https://godotengine.org/asset-library/asset/2043

I agree that the functionality should be in core. Why not have Grab, Rotate, Scale (and add, delete meshes) just work within a MultimeshInstance node? Perhaps some modal switch, like double-clicking a gizmo on-screen to step-into the local space of the multimesh where the usual tools can be used to pick, move, transform etc?

gtibo commented 2 months ago

I did some research back in April on this topic, multimesh isn't really useful by default. IMO, when using multimesh, you should be able to perform basic operations out of the box, for example:

For now, I've just explored the possibility of quickly placing and moving instances, but it could also contain a simple gizmo for moving specific instances, as you said.

(test repo) https://github.com/gtibo/multimesh-plus

flower (video) https://github.com/user-attachments/assets/fc9d5baa-5bc2-4a80-a3b2-52fb0cbae578

Update I tested adding per transform translations, surface snapping could be an option?

selection (video) https://github.com/user-attachments/assets/709177a2-c876-44d9-b27e-49b0b5384bc2

donn-xx commented 2 months ago

@gtibo Appreciate your code. It's a start. I think the real problem will come once the numbers of instances gets large and that looping of transforms.size starts to bog-down.

If this is to be taken seriously, it needs to be in C++ and using (whatever remains *) of the Physics/BVH tools available while in the editor.

It would be super-great to have some kind of chunking capacity for multimeshes (AND colliders per instance). Rather have more Multimeshes than few containing too many instances. As the player (whatever) gets closer, the instances can become 'realized' (as MeshInstance3D nodes) and have colliders added. (And the reverse further away.)

gtibo commented 2 months ago

@donn-xx

No prob, my test is a very naive integration to test a use case :)

At present, it is recommended to use Multimesh as is, in very localized sections, essentially by making small chunks of Multimesh manually, as LOD and culling are only supported for the entire Multimesh and not at instance level. (To change that, you'd have to add some form of spatial partitioning, I guess?)

This is a problem: even if you have a performant “multimesh editor”, the node itself is not designed to spread meshes over a large area.

I don't know about colliders, I think Multimesh as a node should do 1 thing (display a large number of meshes).

If you have instances in a MultiMesh that are far away from each other, they should be placed in a separate MultiMeshInstance3D node. Doing so will also improve rendering performance, as frustum and occlusion culling will be able to cull individual nodes (while they can't cull individual instances in a MultiMesh). https://docs.godotengine.org/en/stable/tutorials/3d/mesh_lod.html#using-mesh-lod-with-multimesh-and-particles

donn-xx commented 2 months ago

I was (not clearly!) thinking about how to spatially-match the "cursor" (in-editor) against a large mesh of say +1000 instances. In order to do that there have to exist colliders (AABBs at least) around all the instances. That way, your cursor's own collider can detect which instance collider/s it's near.

In order to do that it seems logical that the MultiMeshInstance3D should 'chunk' somehow to construct (and destroy) the minimum number of colliders in the BVH for roughly where the cursor is.

I agree that all this is rather complex and may not be reasonable to do.