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 3D skeleton preview to Advanced Importer #96094

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 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 @@ -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(SceneStringName(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 @@ -480,6 +483,31 @@ 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) {
Ref<ArrayMesh> bones_mesh = Skeleton3DGizmoPlugin::get_bones_mesh(skeleton, -1, true);

bones_mesh_preview->set_mesh(bones_mesh);

Transform3D accum_xform;
Node3D *base = skeleton;
while (base) {
accum_xform = base->get_transform() * accum_xform;
base = Object::cast_to<Node3D>(base->get_parent());
}

bones_mesh_preview->set_transform(accum_xform * skeleton->get_transform());

AABB aabb = accum_xform.xform(bones_mesh->get_aabb());

if (first_aabb) {
contents_aabb = aabb;
first_aabb = false;
} else {
contents_aabb.merge_with(aabb);
}
}
}

void SceneImportSettingsDialog::_update_scene() {
Expand Down Expand Up @@ -795,6 +823,7 @@ void SceneImportSettingsDialog::_select(Tree *p_from, const String &p_type, cons
selecting = true;
scene_import_settings_data->hide_options = false;

bones_mesh_preview->hide();
if (p_type == "Node") {
node_selected->hide(); // Always hide just in case.
mesh_preview->hide();
Expand Down Expand Up @@ -834,6 +863,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 All @@ -853,6 +883,8 @@ void SceneImportSettingsDialog::_select(Tree *p_from, const String &p_type, cons

scene_import_settings_data->settings = &ad.settings;
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION;

_animation_update_skeleton_visibility();
} else if (p_type == "Mesh") {
node_selected->hide();
if (Object::cast_to<Node3D>(scene)) {
Expand Down Expand Up @@ -1055,6 +1087,11 @@ 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 *p_skeleton) {
bones_mesh_preview->set_skeleton_path(p_skeleton->get_path());
bones_mesh_preview->set_skin(p_skeleton->register_skin(p_skeleton->create_skin_from_rest_transforms()));
}

void SceneImportSettingsDialog::_animation_finished(const StringName &p_name) {
Animation::LoopMode loop_mode = animation_loop_mode;

Expand All @@ -1080,6 +1117,14 @@ void SceneImportSettingsDialog::_animation_finished(const StringName &p_name) {
}
}

void SceneImportSettingsDialog::_animation_update_skeleton_visibility() {
if (animation_toggle_skeleton_visibility->is_pressed()) {
bones_mesh_preview->show();
} else {
bones_mesh_preview->hide();
}
}

void SceneImportSettingsDialog::_material_tree_selected() {
if (selecting) {
return;
Expand Down Expand Up @@ -1282,6 +1327,8 @@ void SceneImportSettingsDialog::_notification(int p_what) {
light_1_switch->set_icon(theme_cache.light_1_icon);
light_2_switch->set_icon(theme_cache.light_2_icon);
light_rotate_switch->set_icon(theme_cache.rotate_icon);

animation_toggle_skeleton_visibility->set_icon(get_editor_theme_icon(SNAME("Skeleton3D")));
} break;

case NOTIFICATION_PROCESS: {
Expand Down Expand Up @@ -1661,6 +1708,7 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() {
animation_hbox->add_child(animation_stop_button);
animation_stop_button->set_flat(true);
animation_stop_button->set_focus_mode(Control::FOCUS_NONE);
animation_stop_button->set_tooltip_text(TTR("Selected Animation Stop"));
animation_stop_button->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_stop_current_animation));

animation_slider = memnew(HSlider);
Expand All @@ -1673,6 +1721,15 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() {
animation_slider->set_focus_mode(Control::FOCUS_NONE);
animation_slider->connect(SceneStringName(value_changed), callable_mp(this, &SceneImportSettingsDialog::_animation_slider_value_changed));

animation_toggle_skeleton_visibility = memnew(Button);
animation_hbox->add_child(animation_toggle_skeleton_visibility);
animation_toggle_skeleton_visibility->set_toggle_mode(true);
animation_toggle_skeleton_visibility->set_flat(true);
animation_toggle_skeleton_visibility->set_focus_mode(Control::FOCUS_NONE);
animation_toggle_skeleton_visibility->set_tooltip_text(TTR("Toggle Animation Skeleton Visibility"));

animation_toggle_skeleton_visibility->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_animation_update_skeleton_visibility));

base_viewport->set_use_own_world_3d(true);

HBoxContainer *viewport_hbox = memnew(HBoxContainer);
Expand Down Expand Up @@ -1800,6 +1857,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
4 changes: 4 additions & 0 deletions editor/import/3d/scene_import_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,12 @@ class SceneImportSettingsDialog : public ConfirmationDialog {
HSlider *animation_slider = nullptr;
Button *animation_play_button = nullptr;
Button *animation_stop_button = nullptr;
Button *animation_toggle_skeleton_visibility = nullptr;
Animation::LoopMode animation_loop_mode = Animation::LOOP_NONE;
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 @@ -187,9 +189,11 @@ class SceneImportSettingsDialog : public ConfirmationDialog {
void _reset_animation(const String &p_animation_name = "");
void _animation_slider_value_changed(double p_value);
void _animation_finished(const StringName &p_name);
void _animation_update_skeleton_visibility();
void _material_tree_selected();
void _mesh_tree_selected();
void _scene_tree_selected();
void _skeleton_tree_entered(Skeleton3D *p_skeleton);
void _cleanup();
void _on_light_1_switch_pressed();
void _on_light_2_switch_pressed();
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 @@ -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.

Expand All @@ -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));
Expand All @@ -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;
}
Expand Down Expand Up @@ -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");
Expand All @@ -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;
Expand All @@ -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++) {
Expand All @@ -1405,16 +1417,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 @@ -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();
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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();
}
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
Loading