Ver código fonte

add support for visualizing bones in Advanced Import Settings

When an imported model Skeleton3D type node is selected, the bones are drawn using lines or octahedrons to provide a clearer reference to their position.
Refactored Skeleton3DGizmoPlugin::redraw now uses a static function to generate bone meshes
Jeronimo Schreyer 1 ano atrás
pai
commit
030fd71da2

+ 22 - 1
editor/import/3d/scene_import_settings.cpp

@@ -37,6 +37,7 @@
 #include "editor/editor_settings.h"
 #include "editor/editor_string_names.h"
 #include "editor/gui/editor_file_dialog.h"
+#include "editor/plugins/skeleton_3d_editor_plugin.h"
 #include "editor/themes/editor_scale.h"
 #include "scene/3d/importer_mesh_instance_3d.h"
 #include "scene/animation/animation_player.h"
@@ -419,7 +420,9 @@ void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_ite
 				animation_player->connect(SceneStringName(animation_finished), callable_mp(this, &SceneImportSettingsDialog::_animation_finished));
 			} else if (Object::cast_to<Skeleton3D>(p_node)) {
 				category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
-				skeletons.push_back(Object::cast_to<Skeleton3D>(p_node));
+				Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_node);
+				skeleton->connect(SNAME("tree_entered"), callable_mp(this, &SceneImportSettingsDialog::_skeleton_tree_entered).bind(skeleton));
+				skeletons.push_back(skeleton);
 			} else {
 				category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
 			}
@@ -480,6 +483,11 @@ void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_ite
 			contents_aabb.merge_with(aabb);
 		}
 	}
+
+	Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_node);
+	if (skeleton) {
+		bones_mesh_preview->set_mesh(Skeleton3DGizmoPlugin::get_bones_mesh(skeleton, -1, true));
+	}
 }
 
 void SceneImportSettingsDialog::_update_scene() {
@@ -800,6 +808,7 @@ void SceneImportSettingsDialog::_select(Tree *p_from, const String &p_type, cons
 		mesh_preview->hide();
 		_reset_animation();
 
+		bones_mesh_preview->hide();
 		if (Object::cast_to<Node3D>(scene)) {
 			Object::cast_to<Node3D>(scene)->show();
 		}
@@ -834,6 +843,7 @@ void SceneImportSettingsDialog::_select(Tree *p_from, const String &p_type, cons
 				scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
 			} else if (Object::cast_to<Skeleton3D>(nd.node)) {
 				scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
+				bones_mesh_preview->show();
 			} else {
 				scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
 				scene_import_settings_data->hide_options = editing_animation;
@@ -1055,6 +1065,10 @@ void SceneImportSettingsDialog::_animation_slider_value_changed(double p_value)
 	animation_player->seek(p_value * animation_map[selected_id].animation->get_length(), true);
 }
 
+void SceneImportSettingsDialog::_skeleton_tree_entered(Skeleton3D *skeleton) {
+	bones_mesh_preview->set_skeleton_path(skeleton->get_path());
+}
+
 void SceneImportSettingsDialog::_animation_finished(const StringName &p_name) {
 	Animation::LoopMode loop_mode = animation_loop_mode;
 
@@ -1800,6 +1814,13 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() {
 		collider_mat->set_albedo(Color(0.5, 0.5, 1.0));
 	}
 
+	{
+		bones_mesh_preview = memnew(MeshInstance3D);
+		bones_mesh_preview->set_cast_shadows_setting(GeometryInstance3D::SHADOW_CASTING_SETTING_OFF);
+		bones_mesh_preview->set_skeleton_path(NodePath());
+		base_viewport->add_child(bones_mesh_preview);
+	}
+
 	inspector = memnew(EditorInspector);
 	inspector->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
 	inspector->connect(SNAME("property_edited"), callable_mp(this, &SceneImportSettingsDialog::_inspector_property_edited));

+ 2 - 0
editor/import/3d/scene_import_settings.h

@@ -113,6 +113,7 @@ class SceneImportSettingsDialog : public ConfirmationDialog {
 	bool animation_pingpong = false;
 	bool previous_import_as_skeleton = false;
 	bool previous_rest_as_reset = false;
+	MeshInstance3D *bones_mesh_preview = nullptr;
 
 	Ref<StandardMaterial3D> collider_mat;
 
@@ -190,6 +191,7 @@ class SceneImportSettingsDialog : public ConfirmationDialog {
 	void _material_tree_selected();
 	void _mesh_tree_selected();
 	void _scene_tree_selected();
+	void _skeleton_tree_entered(Skeleton3D *skeleton);
 	void _cleanup();
 	void _on_light_1_switch_pressed();
 	void _on_light_2_switch_pressed();

+ 36 - 25
editor/plugins/skeleton_3d_editor_plugin.cpp

@@ -1180,16 +1180,18 @@ int Skeleton3DEditor::get_selected_bone() const {
 	return selected_bone;
 }
 
+Skeleton3DGizmoPlugin::SelectionMaterials Skeleton3DGizmoPlugin::selection_materials;
+
 Skeleton3DGizmoPlugin::Skeleton3DGizmoPlugin() {
-	unselected_mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
-	unselected_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
-	unselected_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
-	unselected_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-	unselected_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
-	unselected_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
-
-	selected_mat = Ref<ShaderMaterial>(memnew(ShaderMaterial));
-	selected_sh = Ref<Shader>(memnew(Shader));
+	selection_materials.unselected_mat.instantiate();
+	selection_materials.unselected_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+	selection_materials.unselected_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+	selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+	selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+	selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
+
+	selection_materials.selected_mat.instantiate();
+	Ref<Shader> selected_sh = Ref<Shader>(memnew(Shader));
 	selected_sh->set_code(R"(
 // Skeleton 3D gizmo bones shader.
 
@@ -1208,7 +1210,7 @@ void fragment() {
 	ALPHA = COLOR.a;
 }
 )");
-	selected_mat->set_shader(selected_sh);
+	selection_materials.selected_mat->set_shader(selected_sh);
 
 	// Register properties in editor settings.
 	EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
@@ -1218,6 +1220,11 @@ void fragment() {
 	EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d_gizmos/gizmo_settings/bone_shape", PROPERTY_HINT_ENUM, "Wire,Octahedron"));
 }
 
+Skeleton3DGizmoPlugin::~Skeleton3DGizmoPlugin() {
+	selection_materials.unselected_mat.unref();
+	selection_materials.selected_mat.unref();
+}
+
 bool Skeleton3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
 	return Object::cast_to<Skeleton3D>(p_spatial) != nullptr;
 }
@@ -1354,6 +1361,11 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 		selected = se->get_selected_bone();
 	}
 
+	Ref<ArrayMesh> m = get_bones_mesh(skeleton, selected, p_gizmo->is_selected());
+	p_gizmo->add_mesh(m, Ref<Material>(), Transform3D(), skeleton->register_skin(skeleton->create_skin_from_rest_transforms()));
+}
+
+Ref<ArrayMesh> Skeleton3DGizmoPlugin::get_bones_mesh(Skeleton3D *p_skeleton, int p_selected, bool p_is_selected) {
 	Color bone_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/skeleton");
 	Color selected_bone_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/selected_bone");
 	real_t bone_axis_length = EDITOR_GET("editors/3d_gizmos/gizmo_settings/bone_axis_length");
@@ -1367,11 +1379,11 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 	Ref<SurfaceTool> surface_tool(memnew(SurfaceTool));
 	surface_tool->begin(Mesh::PRIMITIVE_LINES);
 
-	if (p_gizmo->is_selected()) {
-		surface_tool->set_material(selected_mat);
+	if (p_is_selected) {
+		surface_tool->set_material(selection_materials.selected_mat);
 	} else {
-		unselected_mat->set_albedo(bone_color);
-		surface_tool->set_material(unselected_mat);
+		selection_materials.unselected_mat->set_albedo(bone_color);
+		surface_tool->set_material(selection_materials.unselected_mat);
 	}
 
 	LocalVector<int> bones;
@@ -1385,16 +1397,16 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 	weights[0] = 1;
 
 	int current_bone_index = 0;
-	Vector<int> bones_to_process = skeleton->get_parentless_bones();
+	Vector<int> bones_to_process = p_skeleton->get_parentless_bones();
 
 	while (bones_to_process.size() > current_bone_index) {
 		int current_bone_idx = bones_to_process[current_bone_index];
 		current_bone_index++;
 
-		Color current_bone_color = (current_bone_idx == selected) ? selected_bone_color : bone_color;
+		Color current_bone_color = (current_bone_idx == p_selected) ? selected_bone_color : bone_color;
 
 		Vector<int> child_bones_vector;
-		child_bones_vector = skeleton->get_bone_children(current_bone_idx);
+		child_bones_vector = p_skeleton->get_bone_children(current_bone_idx);
 		int child_bones_size = child_bones_vector.size();
 
 		for (int i = 0; i < child_bones_size; i++) {
@@ -1405,8 +1417,8 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 
 			int child_bone_idx = child_bones_vector[i];
 
-			Vector3 v0 = skeleton->get_bone_global_rest(current_bone_idx).origin;
-			Vector3 v1 = skeleton->get_bone_global_rest(child_bone_idx).origin;
+			Vector3 v0 = p_skeleton->get_bone_global_rest(current_bone_idx).origin;
+			Vector3 v1 = p_skeleton->get_bone_global_rest(child_bone_idx).origin;
 			Vector3 d = (v1 - v0).normalized();
 			real_t dist = v0.distance_to(v1);
 
@@ -1414,7 +1426,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 			int closest = -1;
 			real_t closest_d = 0.0;
 			for (int j = 0; j < 3; j++) {
-				real_t dp = Math::abs(skeleton->get_bone_global_rest(current_bone_idx).basis[j].normalized().dot(d));
+				real_t dp = Math::abs(p_skeleton->get_bone_global_rest(current_bone_idx).basis[j].normalized().dot(d));
 				if (j == 0 || dp > closest_d) {
 					closest = j;
 				}
@@ -1441,7 +1453,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 					for (int j = 0; j < 3; j++) {
 						Vector3 axis;
 						if (first == Vector3()) {
-							axis = d.cross(d.cross(skeleton->get_bone_global_rest(current_bone_idx).basis[j])).normalized();
+							axis = d.cross(d.cross(p_skeleton->get_bone_global_rest(current_bone_idx).basis[j])).normalized();
 							first = axis;
 						} else {
 							axis = d.cross(first).normalized();
@@ -1496,7 +1508,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 				surface_tool->add_vertex(v0);
 				surface_tool->set_bones(bones);
 				surface_tool->set_weights(weights);
-				surface_tool->add_vertex(v0 + (skeleton->get_bone_global_rest(current_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
+				surface_tool->add_vertex(v0 + (p_skeleton->get_bone_global_rest(current_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
 
 				if (j == closest) {
 					continue;
@@ -1513,7 +1525,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 					surface_tool->add_vertex(v1);
 					surface_tool->set_bones(bones);
 					surface_tool->set_weights(weights);
-					surface_tool->add_vertex(v1 + (skeleton->get_bone_global_rest(child_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
+					surface_tool->add_vertex(v1 + (p_skeleton->get_bone_global_rest(child_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
 
 					if (j == closest) {
 						continue;
@@ -1526,6 +1538,5 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 		}
 	}
 
-	Ref<ArrayMesh> m = surface_tool->commit();
-	p_gizmo->add_mesh(m, Ref<Material>(), Transform3D(), skeleton->register_skin(skeleton->create_skin_from_rest_transforms()));
+	return surface_tool->commit();
 }

+ 8 - 3
editor/plugins/skeleton_3d_editor_plugin.h

@@ -252,11 +252,15 @@ public:
 class Skeleton3DGizmoPlugin : public EditorNode3DGizmoPlugin {
 	GDCLASS(Skeleton3DGizmoPlugin, EditorNode3DGizmoPlugin);
 
-	Ref<StandardMaterial3D> unselected_mat;
-	Ref<ShaderMaterial> selected_mat;
-	Ref<Shader> selected_sh;
+	struct SelectionMaterials {
+		Ref<StandardMaterial3D> unselected_mat;
+		Ref<ShaderMaterial> selected_mat;
+	};
+	static SelectionMaterials selection_materials;
 
 public:
+	static Ref<ArrayMesh> get_bones_mesh(Skeleton3D *p_skeleton, int p_selected, bool p_is_selected);
+
 	bool has_gizmo(Node3D *p_spatial) override;
 	String get_gizmo_name() const override;
 	int get_priority() const override;
@@ -269,6 +273,7 @@ public:
 	void redraw(EditorNode3DGizmo *p_gizmo) override;
 
 	Skeleton3DGizmoPlugin();
+	~Skeleton3DGizmoPlugin();
 };
 
 #endif // SKELETON_3D_EDITOR_PLUGIN_H