godotengine / godot-proposals

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

Improve the mesh asset workflow in the 3D editor #2883

Open mrtripie opened 3 years ago

mrtripie commented 3 years ago

Describe the project you are working on

Describe the problem or limitation you are having in your project

Building 3D scenes in Godot is currently quite slow. Most of this is just a bunch of small Editor UI problems that pile up (sometime in the next few weeks I plan on trying to make some contributions to those), but there some usability problems that are bit more complicated.

Basically what I would like is easy tweaking of singular 3D assets with collision in a map (for example a desk with a collision box and static body).

Lets go into further detail: 1: Lets say I'm building a house out of modular parts. I place some wall parts (a singular 3d asset with collision), and I decide this room should have different color walls, so I need to override the wall mesh's material with a different one. To do this I must: MeshWorkflowProposalChangingMaterial 1: Right click on the asset scene's root node 2: Find and click "Editable Children" 3: Find and click on the Mesh instance Node 4: Finally go to Surface Material Override and change the material.

Three clicks to get to step 4 and this scales really badly. Ideally I would know the right material going in, and only have to go through this process once per modular part in this room (wall, doorframe, window), which would still require doing this multiple times, however, if I build a room and go back to it later wanting to change its color, I'd have to repeat steps 1-3 for EACH MESH, (I can't multi select scenes and enable editable children, and once they are editable, as they are child nodes, I can't just select the first, and Shift select the last to select them all at once). For the most basic room with 3 basic walls + 1 wall with a hole for door in it, you would need to click 12 times to get the multi mesh inspector edit, and most rooms will be more complicated needing even more clicks. The room I'm in now has some windows, 3 doorways to different parts of the house, a shape that isn't a perfect rectangle, and a fireplace, where it would require 17 modular parts to build a similar room, meaning 3x17 = 51 clicks to get to the point where I could change the wall color!

This would be the same process with other tweaks, maybe I need to change the layer the mesh is on so I can really push the lighting by having lights that only effect certain objects, or change the layer to have a decal only effect it and not surrounding meshes, or maybe I need to tweak some settings for performance (disabling shadows, LOD bias, etc), etc.

Another case would be quickly switching between mesh variants. Lets say I'm building an ancient ruins scene. I place some stone columns around the scene. As they should have collision, I'd like to use the Advanced Mesh Import Window to give them collision. I'll likely want to easily change to a different variant of the mesh, perhaps giving different broken patterns. This may happen because as I block out the scene I don't have all my variants made yet, or because it would be easiest to just lay them out by duplicating them and then change some of them to different variants. To do this now: MeshWorkflowProposalChangingMesh 1: Click options button in corner of Inspector 2: Click "Copy Parameters" 3: Delete node, click OK 4: Drag the new asset into the scene 5: Click options button in corner of Inspector 6: Click "Paste Parameters"

And again, this is something you can't do as a bulk edit action, if I wanted to select multiple of those columns and change them all into the a different variant, I would have to repeat that 6 step process for each one, when all I should have to do is select all I want to change, and do a 1 step process of changing the mesh or scene.

Other problems with using "Editable Children" include:

So "Editable Children" is really best as an occasional quick hack, and not something that should be part of the usual mesh workflow.

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

There should be a way to easily set up mesh assets with collision and physics, while being able to easily access the Mesh Instance node's options such as Material Overrides and Layers. For example, if I have my scene tree organized well, or I search for "wall" in the Scene dock, I should be able to Click on the first wall, and Shift Click the last one to easily select all the walls in 2 clicks, and have the Mesh Instance's shown in the Inspector, ready for changing the material overrides, going from anywhere from 12 to over a 100 clicks to change a complicated room's wall color, to just 2, all while having the collision set up in the Advanced Import Options Window so I don't have to build my own wall scenes.

I should also be able to select a 3d asset in my scene, and have an easy way to swap it swap it to a different asset, and multi select several assets in the scene, and changing them all at once without having to repeat that 6 step process for each.

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

To fix this you could either change the relationship between a Mesh and its Collision/Physics, or create UI elements designed to streamline this process.

Here are some options I thought of:

Option 1:

Add collision shape data into the Mesh Resource, while merging the Physics Body nodes into the Mesh Instance Node. When importing a 3d file, you can tell Godot to either import as a Mesh Resource (where you can use the Advanced Import Options Window to add collision), or as a scene (again using the Advanced Import Options Window, where each mesh in the scene would have just 1 Mesh Instance Node attached to a root Node3D, with no Collision Shape/Physics Body nodes.) This is basically how Unreal Engine does it, and at least from the user's perspective, it works quite nicely. Pros:

Cons:

You could do several things to improve the con of having a lot of options in the Inspector:

I'm not sure how this would effect performance and memory usage. My guess is it would be about the same, as there would be less Nodes, but there would be more unused options. Unreal does this with a ton more options, and it seems to work fine.

In Godot, something similar is already used in a few places: -CSG nodes can enable a static body with collision via a checkbox. -Soft Body is a child class of MeshInstance3D. -In 2D, tilemaps have static bodies and collision built in. -RigidBody3d also seems like it might already have a lot of the different body's code merged into it via its different modes.

If this was done, it may even make sense to consider removing the Physics Body Nodes entirely, as other than invisible walls that are easily worked around, there wouldn't be any normal use cases for them to be separate from a Mesh.

Some other potential benefits: -Easy Multi Mesh Instance Collision -Certain art addons such as a vertex painting, sculpting, or modeling addon could have an easier time modifying your assets as they wouldn't have to worry about dealing with scenes. (Also for option 2) -Swapping materials easily by dragging and dropping them onto a mesh may be easier to implement, as not only are material overrides now exposed, but you don't have to worry about going deeper into a scene tree. (Also for option 2)

This would look something like this: MeshWorkflowProposalMeshInstanceWithPhysicsInspector

Option 2:

When importing a 3D scene with only 1 mesh, Godot could make the Mesh Instance the scene root, while the Physics Body and Collision Shapes are added as children. Currently this would work okay with Static Bodies (as long as you aren't using its new Kinematic option), however Rigid, Character, etc Bodies don't work this way. So these nodes would have to be changed so that instead of moving themselves, with children following, they would actually move their parent node, basically acting as a component that turns their parent into a Physics Body. Pros:

Cons:

You can overcome the problem of not easily being able to change to a different 3d asset by adding a UI element for changing which scene is instanced. This could be a "Scene" option placed at the top of the inspector for all scene instances, or a toolbar button called something like "Change Scene" that shows up when a scene instance is selected. This wouldn't be perfect, as overriding the Mesh Option on the root Mesh Instance Node would keep whatever collision was already there, but that shouldn't be done very often.

Inverting the Physics Body node's positions may seem strange as it wouldn't follow the normal rules of Parent-Child transform, but at least for me, having used other engines, I actually got them backwards when first messing around with them. I expected it to act like adding a Physics Body Component to a mesh I placed in the scene. Having the Rigid Body being the parent felt a little wrong as the Rigid Body feels more like a detail of the Mesh Instance, rather than the Mesh Instance being a detail of the Rigid Body, if that makes sense. So flipping them may not be that strange.

Other potential benefits: A scene swapping tool could help with swapping scenes in other situations as well. (Also for 3)

Option 3:

Build UI elements that will help streamline these processes. These could include:

Pros:

Cons:

Something like this: MeshWorkflowProposalOverridesInspector

I'm not sure which of these options would work the best in Godot, so this would need some discussion.

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

One could work around part of this for meshes with Static Bodies by creating their own scenes for each asset with the mesh as the root node, but this takes more steps, adds extra files to have to manage, and defeats the whole point of all the hard work to make the Advanced Import Settings Window to avoid those problems.

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

Addons could possibly add UI based ways to improve this, but this will be a very common issue that will make building detailed scenes in Godot a lot harder for artists, so it makes sense to fix it in core.

I really appreciate all the hard work you guys are doing on improving Godot's workflow! I'm super excited for all these improvements such as Import Settings Window, and Automatic LODs. I think its super important for an engine built for small teams/solo users to have its workflow highly polished, like many aspects of Godot 4.0 will be.

trollodel commented 3 years ago

I think there are 2 things proposed here:

For the multinode editing, it would be nice some sort of proxy resources in MultiNodeEdit which allows to edit all the nodes' property in a single step. Of course, all the selected nodes must be structurally the same, or it doesn't work. It's similar to what you propose in the option 3, but not limited only to scenes.

For mesh assets, instead, I don't agree with the proposed changes for the following reasons:

Constructing your asset workflow

I think Godot shouldn't provide a preferred/rigid asset workflow because everyone has different needs. For me, imported assets are immutable, and they are configured in an intermediary (or container) scene through a script and not in the game/level scene. This give me the possibility to add collisions, "patch" the asset (mostly for animations), and add extra properties that I can use in the game scene.

Meshes and bodies should stay separated

In Option 1, you propose to merge all the physics bodies into MeshInstance. There are several reasons of why it is a bad idea, but for me the most important one is the fact you mix physics and rendering, especially when scripting. But, creating a script that creates a static body in a MeshInstance is possible, while not being trivial (requires using PhysicsServer).

Conclusions

I think you can resolve most of your issues by planning your workflow or by using script (I know it's not artist-friendly, but at some point it will be necessary, at least for asset configuring). Godot doesn't provide (and probably never does) the tooling required for "instant" prototyping, but it's flexible and quite extensible, which IMO it's preferred over prototyping tools.

mrtripie commented 3 years ago

@trollodel As for the multinode editing part, I'm not really sure what you mean in your suggestion, it sounds pretty much the same as how it works now, unless you mean also giving access to child nodes (that may be hidden in a scene instance)? Could you explain your idea a bit further?

I agree that not having a rigid workflow is important, but I think that common workflows should be should be well supported by default. Most Godot users (especially less experienced) will NOT build their own custom workflows with import scripts.

Here are Godot 4.0's current workflows:

The Mesh Instance not being the root means that to customize a Mesh Instance in any way, you have use workarounds like opening the scene instance via "Editable Children", or a script, or some sort of custom UI element, all of which aren't great.


I don't think combining Physics Bodies and Mesh Instances is a bad idea, other than it would probably take a fair amount of work to do, and would lead to a bigger class. Physics Bodies and Mesh's are in practice pretty strongly linked, other than the case of invisible things (which would be easy to work around if both Mesh Instance got Physics Bodies built in, and Phyics Body Nodes were removed, walls could just use an invisible CSGBox, and other invisible things would be rare enough and not too hard to work around that I don't think they would be a problem), I can't think of any use case for the Physics Bodies that aren't directly linked to a mesh.

Why would mixing the two be a problem for scripting? I've used Unreal which works this way before, and I can't see any way the two would get in the way? (And I know how to script games)

This way gives you all the options from both Mesh Instance and Physics Bodies you could need in the inspector.

As it would have the Mesh Instance as the root node, it would make certain tools such as Vertex Painting easier to make.

Having the Colliders as part of the Mesh Asset can be handy elsewhere, such as Multi Mesh Instances, though it wouldn't be too hard to work around either way.

Godot already combines rendering and physics in several places (SoftBody3D, CSGShape3D, TileMap), though to a lesser degree.

RigidBody3D for some reason already has modes for Rigid Body, Kinematic Body, and Static Body, so the most common ones are already merged somewhere.

This way is messy from the viewpoint of the engine developer, but is much cleaner from the viewpoint of the game developer. The way it is now is the other way around.


One way to make them both fairly clean would be a component based workflow, where a Mesh Instance Component and a Physics Body Component could be placed on the same Node, seperate from the Engine Developer's viewpoint, but together from the Game Developers viewpoint. Godot isn't designed that way though, but Option #2 is similar. Having the Physics Body node placed as a child of the Mesh Instance will allow Godot to consistently set it up that way when imporing scenes, and could allow single mesh scenes to have the Mesh Instance as the root. Unlike Option #1 you wouldn't get Physics Options though, and both would require a bit of redesign.

Option 3 would probably be the least work, but it doesn't really feel right to me. Part of that may be that tools like a vertex painting addon would likely still have to enable "Editable Children", though it should still be an improvement.

Any approach, you should still have a fair amount of customizability, such as using custom import scripts for your character animations. Do you think any of these would likely do more harm than good to your workflow?

mrtripie commented 3 years ago

Another UI based approach may be for Instanced Scenes to add a tree of the Instanced Scene's nodes in the inspector when you click it (like a mini Scene Dock for it). You could then choose which node in the instanced scene you want to edit the properties on, and if you have multiple Instanced Scenes selected with the same structure, you could then do a multi edit with it.

For example: With the wall example, you could change the room color by selecting all the walls, going to the inspector and choosing the Mesh Instance node, and then choosing the material override. It would add 1 click to the ideal process of having the Mesh Instance being the root node, but it would be a huge improvement.

Here is an example of what that may look like: MeshWorkflowProposalSceneTreeInspector (again, I added a little option for changing which scene is instanced here easily, though it may be better to have it be a toolbar button or something. Not sure if it should have this "Scene Instance" heading, as the other headings like that are classes, maybe it should be left blank.)

Alternatively, this could be placed in the Scene Dock, though that tends to have less room.

This could completely replace the "Editable Children" option, as now all children would be editable.

As all children would then be editable, tools like a vertex painter or dragging and dropping materials on meshes could work with scenes without having to first open them up.

codecomedytv commented 3 years ago

I agree with OP’s pain points with mesh asset workflow especially around batching. Can’t speak to the proposals as I’m not that deep into Godot’s code. As someone who needs this solved, I think a ‘destroy’ addon would be perfect. Every node can have a destruction simulation which the user can then make permanent. If you destroy a mesh, it should flatten like a cardboard box where you can edit triangle/quad of verts as a surface. If its a physics object then it can break into minecraft style blocks or solid to liquified or powdered etc. Bounding boxes are heavily influenced by this, it will give much more realistic interactions and take the right amount of space. There might also be a create a new aabb on destruct option, maybe a fork of some kind.

trollodel commented 3 years ago

unless you mean also giving access to child nodes

Exactly this, but instead of putting every node into the inspector like Option 3, you have a resource to access each child, like this a:

IMO, this should be a MultiNodeEdit only option, but it may make sense for scenes too.

  • Custom import script: Not likely to be used by most users, most likely won't even know it exists. (At least right now discoverability is low, its at the bottom of the basic importer dock, and its not mentioned in the documentation for mesh workflows). You should not expect most people to use this.

I don't mean those, they are quite bad, last time I tried. I create an inhered scene and then do what changes I want, with or without scripts. And then I use that scene (and not the asset directly) in game scenes. And for the material problem you described, I would use this simple script:

@tool
extends Node3D

@export @onready var material = $MeshInstance.get_active_material(0):
    set(material):
        $MeshInstance.set_surface_override_material(0, material)

No need for built-in tools that probably don't cover a lots' of possible use cases.

1° Just a mesh resource: Great for being able to swap the mesh or override materials easily, but can't have any collision unless you add it manually each time. 2° Use just a mesh resource, and build a scene manually. This gives you collision, and if you're using a Static Body, you can make your Mesh Instance the root, giving you easy access to its settings. Though you'd have to set it up each time manually, and will have extra files to deal with.

All of these 2 options are good because it gives you freedom to do whatever you want with the asset and build your custom scene, including OP's Option 2.

  • Import as a scene. With either exporting objects with names signalling that they should become colliders, or the brand new Advanced Importer you can set up collision easily! This works great for scenes fully made in your 3D program, and insures that you don't have a bunch of extra files everywhere. But for singluar assets that will be used to build scenes, it has what I think (and I expect lots of artists to agree) is a major problem, the Mesh Instance isn't the root node.

Again, create an inhered scene and setup it with editable children.

and would lead to a bigger class

Why would mixing the two be a problem for scripting? I've used Unreal which works this way before, and I can't see any way the two would get in the way? (And I know how to script games)

This is a big issue alone for me, because when you script a MeshInstance you have tons of methods and properties (that you can't hide like what you do in the inspector) that are not related to each other. In addition, doing that merge will creates a huge documentation page for something that needs to be checked often.

Physics Bodies and Mesh's are in practice pretty strongly linked, other than the case of invisible things (which would be easy to work around if both Mesh Instance got Physics Bodies built in, and Phyics Body Nodes were removed, walls could just use an invisible CSGBox, and other invisible things would be rare enough and not too hard to work around that I don't think they would be a problem),

For static bodies, in most case it's true, but for rigid and character (kinematic) bodies I want to have the complete freedom in how I set up collisions including adding more than 1 shape (I suppose you want to remove CollisionShape3D too) or add shapes that doesn't depend on the mesh.

I can't think of any use case for the Physics Bodies that aren't directly linked to a mesh.

Networked games where the physics simulation is done in the server. Adding mesh stuff and not using it is a waste of memory.

RigidBody3D for some reason already has modes for Rigid Body, Kinematic Body, and Static Body, so the most common ones are already merged somewhere.

RigidBody3D in Kinematic mode and CharacterBody3D are not the same node, they have different features and different use cases.

Here's my points about physics node. At most, a new node which creates a static body and shows mesh is acceptable. Less acceptable is allowing to show a mesh in a StaticBody3D or adding a checkbox to create a static body in MeshInstance3D like CSG nodes, but these solutions only adds bloat (to me at least) and they don't touch my workflow.

Do you think any of these would likely do more harm than good to your workflow?

Only the physics merge (and Option 2 if it is not optional), which is the main reason I commented here.