Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add drag-and-drop support for materials in 3D Instances #56597

Merged
merged 1 commit into from
Jul 28, 2022

Conversation

SaracenOne
Copy link
Member

@SaracenOne SaracenOne commented Jan 7, 2022

PR for adding drag and drop support for materials into 3D editor viewport. Uses the material override slot by default.
drag_and_drop

Things changed since draft:

I would still like to add some extra features in the future such as being able to drag onto individual surfaces and/or a modifer key to choose the individual surface once the mouse is released (similar to what happens when you drag a material onto a mesh instance in the scene tree), but I think this is in a good enough state for review now.

@SaracenOne
Copy link
Member Author

Updated to support assignment to CSG objects. Requires this PR to work properly though #56602

@SaracenOne SaracenOne marked this pull request as ready for review February 11, 2022 04:32
@SaracenOne SaracenOne requested a review from a team as a code owner February 11, 2022 04:32
@SaracenOne
Copy link
Member Author

Okay, this has now been updated to a state that I think this can come out of draft and consider it ready for review. The biggest issue with code quality should be resolved now, a minor bug has been addressed, and new feature of being able to drag textures directly into your 3D scene has been added.

@SaracenOne
Copy link
Member Author

Hold on, I missed something...

@SaracenOne
Copy link
Member Author

Okay, should be sorted now

@SaracenOne SaracenOne force-pushed the material_drag_and_drop branch 2 times, most recently from b78e670 to 9fe6e8e Compare February 12, 2022 03:42
Copy link
Member

@fire fire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't able to give a deep technical review but my brief test shows the functionality does what I think it does.

2022-02-14.06-33-31.mp4

break;
}

editor->set_preview_material(mat);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is can_drop_data, AFAIK it's only supported to check if the selected files contain anything that can be used as a result of drag and drop.

Copy link
Member

@KoBeWi KoBeWi Mar 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually correct, because it allows previewing the material before dropping it:
ezgif com-gif-maker
But AFAIK this method is called with every mouse move, so material swapping should only be done when needed to avoid performance problems.

Comment on lines 4045 to 4060
if (editor->get_preview_material().is_valid()) {
ObjectID new_object_id = _select_ray(p_point);

// Get the corresponding GeometryInstance for new_object_id, and if it is not valid, reset the new_object_id
if (new_object_id.is_valid()) {
GeometryInstance3D *geometry_instance = Object::cast_to<GeometryInstance3D>(ObjectDB::get_instance(new_object_id));
if (!geometry_instance) {
new_object_id = ObjectID();
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing, this is in the wrong callback. It should only be set when the drop action is actually confirmed (drop_data_fw I believe).

@reduz
Copy link
Member

reduz commented Feb 15, 2022

My main issue with this is that it uses material override. I feel this should be setting the proper surface and not the override (or at least we should make it controllable somehow by hitting a key while dragging over the viewport).

@reduz
Copy link
Member

reduz commented Feb 15, 2022

Maybe show some subtext while dragging at the bottom of the viewport like "hit space to switch between surface and override", or some option in the view menu setting? like DND Material -> Set Surface, Set Override.

@akien-mga
Copy link
Member

As discussed on PR this requires some more work, maybe other contributors familiar with it can help:

  • As @reduz mentioned this should likely apply to surfaces by default, and with a modifier it can apply as override. Maybe @JFonS can help
  • The drag and drop API is not properly used, should be refactored (maybe @KoBeWi or @groud can help?)
  • To show a text label while dragging to display whether it's affecting surface (and which one) or override, you can look at the CanvasItemEditorPlugin that has similar stuff for dragging PNGs

@SaracenOne
Copy link
Member Author

@KoBeWi Okay, should be resolved now

@@ -42,6 +42,7 @@ class Mesh : public Resource {
GDCLASS(Mesh, Resource);

mutable Ref<TriangleMesh> triangle_mesh; //cached
mutable Vector<Ref<TriangleMesh>> surface_triangle_meshes; //cached
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think rather than doing this, it should be simpler to modify TriangleMesh to contain an index of the surface ID as an optional second argument Vector<int32_t> to triangle_mesh->create()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will also ensure that ray collision is correct.

@SaracenOne
Copy link
Member Author

SaracenOne commented Apr 24, 2022

Since I didn't write the per-surface assignment part of this, do you have any thoughts @gaudecker? The technique seems like it would be a little more efficent, but I feel there was likely reluctance to alter too many internal data structures for one feature; supplying an array of custom face IDs may not be too bad though, since it could possibly be used for other things outside of the scope of this too.

@reduz One alternative approach I might want to mention though is instead of simply creating the TriangleMesh with the surface IDs directly, instead, we modify the intersection functions so the return the specific face ID (and maybe even the exact triangle intersection point too) which could then be cross-referenced with an external ID buffer which would give the surface IDX. The reason doing it this way might be better is it may make the TriangleMesh more generically useful when it comes to mapping intersections tests with other forms of regular mesh data, like UVs for example.

It could be just me though, I tend to get a bit nervous about modifying APIs for one specific purpose unless I can claim there's other stuff changing it might be useful for.

@SaracenOne
Copy link
Member Author

Actually, thinking about it, the internal TriangleMesh data would still likely need to be modified to factor the mapping between raw triangle data and face indicies, but my question was how generic this metadata should be

@gaudecker
Copy link
Contributor

gaudecker commented Apr 24, 2022

@SaracenOne In the context of #59266, I think these meta-indices could probably work both for mesh surfaces and CSG faces. 🤔

There are probably other use-cases as well.

@reduz
Copy link
Member

reduz commented Apr 27, 2022

I would just harcode it into TriangleMesh because this is only really used by the editor, to be honest. If other uses can be added, I think they should be added at the time they are needed.

@reduz
Copy link
Member

reduz commented Jun 22, 2022

I opened #62321 to help unblock this PR. Once merged, it should make implementation of this easier as you can simply query the surface index of the ray collision.

@fire
Copy link
Member

fire commented Jul 19, 2022

I will be salvaging this.

Add mesh surface picking for material drag & drop, show drag info label
@fire
Copy link
Member

fire commented Jul 19, 2022

Having an infinite loop in TriangleMesh::intersect_ray. Investigating. This is not the pr branch, but trying to use reduz's new api.

@reduz
Copy link
Member

reduz commented Jul 27, 2022

@fire Did you have any luck so far?

@fire
Copy link
Member

fire commented Jul 27, 2022

Not so much. I got stuck and I moved onto assisting tokage on animations and lyuma on ModificationStack conversion to nodes..

@reduz
Copy link
Member

reduz commented Jul 28, 2022

Ok, if for the PR it works well, your freeze is mostly unrelated because all my code did was add an extra return information.

@akien-mga akien-mga merged commit 422725c into godotengine:master Jul 28, 2022
@akien-mga
Copy link
Member

Thanks!

@TokisanGames
Copy link
Contributor

TokisanGames commented Jul 31, 2022

I think this should not put the material on the GeometryInstance3D/material_override. It should be on the actual mesh material slot (Mesh/surface_X/material or CSG/material), with an option to go on the MeshInstance3D/surface_material_override/X. Or the reverse, on the surface override with an option for the mesh.

Reasons:

  • For attaching it to the mesh (Mesh/surface_X/material): The most common use case is setting up master assets, which are saved in scenes to be reused. When meshes are imported, materials are attached to the mesh. We don't import materials into override slots, so dropping materials on meshes should also default to this most common use case. That is a specific material for a specific mesh, tied to the actual mesh as a master material. Not just instances of the mesh.

  • For Mesh Instance override as a secondary option (MeshInstance3D/surface_material_override/X): In some less common cases, I might have generic objects like rocks that can use multiple rock materials. In this case I'd want a blank or default rock material on the mesh, and a quick drag and drop to the mesh instance surface material override for a custom, per instance override of say a mossy or dirt covered variant.

  • Against using GeometryInstance3D/material_override: besides the fact that it's way down in the inspector, the biggest reason against this is material_override only supports one slot. surface_material_override and mesh/surfaces support all material slots. If I have an object w/ 4 material slots, there's no reason I would want the same material in all four slots. If I wanted full coverage of one material, I wouldn't have taken the time to split the uvs into 4 groupings. I would have made a mesh with only one slot.

e.g. 4 material slots
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.