Skip to content

Commit

Permalink
add support for visualizing bones in Advanced Import Settings
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jeronimo-schreyer authored and Your Name committed Apr 5, 2024
1 parent 3df22bf commit 714527c
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 29 deletions.
23 changes: 22 additions & 1 deletion editor/import/3d/scene_import_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -414,7 +415,9 @@ void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_ite
animation_player->connect(SNAME("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;
}
Expand Down Expand Up @@ -474,6 +477,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() {
Expand Down Expand Up @@ -794,6 +802,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();
}
Expand Down Expand Up @@ -828,6 +837,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;
Expand Down Expand Up @@ -1049,6 +1059,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;

Expand Down Expand Up @@ -1708,6 +1722,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));
Expand Down
2 changes: 2 additions & 0 deletions editor/import/3d/scene_import_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,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;

Expand Down Expand Up @@ -175,6 +176,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 _viewport_input(const Ref<InputEvent> &p_input);
Expand Down
61 changes: 36 additions & 25 deletions editor/plugins/skeleton_3d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1181,16 +1181,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.
Expand All @@ -1209,7 +1211,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));
Expand All @@ -1219,6 +1221,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;
}
Expand Down Expand Up @@ -1355,6 +1362,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");
Expand All @@ -1368,11 +1380,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;
Expand All @@ -1386,16 +1398,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++) {
Expand All @@ -1406,16 +1418,16 @@ 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);

// Find closest axis.
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;
}
Expand All @@ -1442,7 +1454,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();
Expand Down Expand Up @@ -1497,7 +1509,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;
Expand All @@ -1514,7 +1526,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;
Expand All @@ -1527,6 +1539,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();
}
11 changes: 8 additions & 3 deletions editor/plugins/skeleton_3d_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,15 @@ class Skeleton3DEditorPlugin : public EditorPlugin {
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;
Expand All @@ -269,6 +273,7 @@ class Skeleton3DGizmoPlugin : public EditorNode3DGizmoPlugin {
void redraw(EditorNode3DGizmo *p_gizmo) override;

Skeleton3DGizmoPlugin();
~Skeleton3DGizmoPlugin();
};

#endif // SKELETON_3D_EDITOR_PLUGIN_H

0 comments on commit 714527c

Please sign in to comment.