Backported from Godot4: Implemented SkeletonEditorGizmo.

-TokageItLab, lyuma
f2e9867e9f
- It still has some issues, as this one works differently than the 3.x version, they will be fixed later.
This commit is contained in:
Relintai 2022-08-11 17:31:02 +02:00
parent d662b2f3c9
commit 92600420ba
21 changed files with 1185 additions and 1335 deletions

View File

@ -203,6 +203,13 @@
This is helper function to make using [method Transform3D.looking_at] easier with bone poses.
</description>
</method>
<method name="is_bone_enabled" qualifiers="const">
<return type="bool" />
<argument index="0" name="bone_idx" type="int" />
<description>
Returns whether the bone pose for the bone at [code]bone_idx[/code] is enabled.
</description>
</method>
<method name="is_bone_rest_disabled" qualifiers="const">
<return type="bool">
</return>
@ -296,6 +303,14 @@
<description>
</description>
</method>
<method name="set_bone_enabled">
<return type="void" />
<argument index="0" name="bone_idx" type="int" />
<argument index="1" name="enabled" type="bool" default="true" />
<description>
Disables the pose for the bone at [code]bone_idx[/code] if [code]false[/code], enables the bone pose if [code]true[/code].
</description>
</method>
<method name="set_bone_global_pose_override">
<return type="void" />
<argument index="0" name="bone_idx" type="int" />
@ -401,7 +416,18 @@
</description>
</method>
</methods>
<members>
<member name="animate_physical_bones" type="bool" setter="set_animate_physical_bones" getter="get_animate_physical_bones" default="true">
</member>
<member name="show_rest_only" type="bool" setter="set_show_rest_only" getter="is_show_rest_only" default="false">
</member>
</members>
<signals>
<signal name="bone_enabled_changed">
<argument index="0" name="bone_idx" type="int" />
<description>
</description>
</signal>
<signal name="bone_pose_changed">
<argument index="0" name="bone_idx" type="int" />
<description>
@ -412,6 +438,10 @@
<description>
</description>
</signal>
<signal name="show_rest_only_changed">
<description>
</description>
</signal>
</signals>
<constants>
<constant name="NOTIFICATION_UPDATE_SKELETON" value="50">

View File

@ -237,6 +237,15 @@
Sets whether the node notifies about its global and local transformation changes. [Spatial] will not propagate this by default, unless it is in the editor context and it has a valid gizmo.
</description>
</method>
<method name="set_subgizmo_selection">
<return type="void" />
<argument index="0" name="gizmo" type="SpatialGizmo" />
<argument index="1" name="id" type="int" />
<argument index="2" name="transform" type="Transform" />
<description>
Set subgizmo selection for this node in the editor.
</description>
</method>
<method name="show">
<return type="void" />
<description>

View File

@ -6403,3 +6403,31 @@ bool AnimationTrackEditor::has_transform_key(Spatial *p_node, const String &p_su
}
return false;
}
bool AnimationTrackEditor::has_transform_track(Spatial *p_node, const String &p_sub) {
if (!keying) {
return false;
}
if (!animation.is_valid()) {
return false;
}
if (!root) {
return false;
}
//let's build a node path
String path = root->get_path_to(p_node);
if (p_sub != "") {
path += ":" + p_sub;
}
int track_id = animation->find_track(path);
if (track_id >= 0) {
//TODO
//if (animation->track_get_type(track_id) == Animation::TYPE_TRANSFORM) {
// return true;
//}
return true;
}
return false;
}

View File

@ -30,15 +30,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/gui/box_container.h"
#include "scene/gui/range.h"
#include "scene/gui/control.h"
#include "core/reference.h"
#include "scene/gui/box_container.h"
#include "scene/gui/control.h"
#include "scene/gui/range.h"
#include "scene/gui/slider.h"
#include "scene/resources/texture.h"
#include "scene/resources/animation.h"
#include "core/dictionary.h"
#include "core/list.h"
#include "core/map.h"
@ -49,6 +47,8 @@
#include "core/ustring.h"
#include "core/variant.h"
#include "core/vector.h"
#include "scene/resources/animation.h"
#include "scene/resources/texture.h"
class AnimationTrackEdit;
class Button;
@ -582,10 +582,12 @@ public:
void goto_next_step(bool p_from_mouse_event);
MenuButton *get_edit_menu();
AnimationTrackEditor();
~AnimationTrackEditor();
bool has_transform_key(Spatial *p_node, const String &p_sub);
bool has_transform_track(Spatial *p_node, const String &p_sub);
};
#endif // ANIMATION_TRACK_EDITOR_H

View File

@ -6901,6 +6901,33 @@ void SpatialEditor::_request_gizmo(Object *p_obj) {
}
}
void SpatialEditor::_set_subgizmo_selection(Object *p_obj, Ref<SpatialGizmo> p_gizmo, int p_id, Transform p_transform) {
if (p_id == -1) {
_clear_subgizmo_selection(p_obj);
return;
}
Spatial *sp = nullptr;
if (p_obj) {
sp = Object::cast_to<Spatial>(p_obj);
} else {
sp = selected;
}
if (!sp) {
return;
}
SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (se) {
se->subgizmos.clear();
se->subgizmos.insert(p_id, p_transform);
se->gizmo = p_gizmo;
sp->update_gizmos();
update_transform_gizmo();
}
}
void SpatialEditor::_clear_subgizmo_selection(Object *p_obj) {
Spatial *sp = nullptr;
if (p_obj) {
@ -7022,6 +7049,7 @@ void SpatialEditor::_bind_methods() {
ClassDB::bind_method("_xform_dialog_action", &SpatialEditor::_xform_dialog_action);
ClassDB::bind_method("_get_editor_data", &SpatialEditor::_get_editor_data);
ClassDB::bind_method("_request_gizmo", &SpatialEditor::_request_gizmo);
ClassDB::bind_method("_set_subgizmo_selection", &SpatialEditor::_set_subgizmo_selection);
ClassDB::bind_method("_clear_subgizmo_selection", &SpatialEditor::_clear_subgizmo_selection);
ClassDB::bind_method("_toggle_maximize_view", &SpatialEditor::_toggle_maximize_view);
ClassDB::bind_method("_refresh_menu_icons", &SpatialEditor::_refresh_menu_icons);
@ -7513,6 +7541,14 @@ void SpatialEditorPlugin::set_state(const Dictionary &p_state) {
spatial_editor->set_state(p_state);
}
bool SpatialEditor::is_gizmo_visible() const {
if (selected) {
return gizmo.visible && selected->is_transform_gizmo_visible();
}
return gizmo.visible;
}
void SpatialEditor::snap_cursor_to_plane(const Plane &p_plane) {
//cursor.pos=p_plane.project(cursor.pos);
}

View File

@ -727,6 +727,7 @@ private:
Spatial *selected;
void _request_gizmo(Object *p_obj);
void _set_subgizmo_selection(Object *p_obj, Ref<SpatialGizmo> p_gizmo, int p_id, Transform p_transform = Transform());
void _clear_subgizmo_selection(Object *p_obj = nullptr);
static SpatialEditor *singleton;
@ -758,7 +759,7 @@ public:
float get_fov() const { return settings_fov->get_value(); }
Transform get_gizmo_transform() const { return gizmo.transform; }
bool is_gizmo_visible() const { return gizmo.visible; }
bool is_gizmo_visible() const;
ToolMode get_tool_mode() const { return tool_mode; }
bool are_local_coords_enabled() const { return tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); }

View File

@ -1166,7 +1166,7 @@ void EditorSpatialGizmoPlugin::_bind_methods() {
MethodInfo cs = MethodInfo("commit_subgizmos", GIZMO_REF, PropertyInfo(Variant::POOL_INT_ARRAY, "ids"), PropertyInfo(Variant::ARRAY, "restore"), PropertyInfo(Variant::BOOL, "cancel"));
cs.default_arguments.push_back(false);
BIND_VMETHOD(cs);
#undef GIZMO_REF
}
@ -1270,13 +1270,13 @@ Transform EditorSpatialGizmoPlugin::get_subgizmo_transform(const EditorSpatialGi
return Transform();
}
void EditorSpatialGizmoPlugin::set_subgizmo_transform(const EditorSpatialGizmo *p_gizmo, int p_id, Transform p_transform) const {
void EditorSpatialGizmoPlugin::set_subgizmo_transform(const EditorSpatialGizmo *p_gizmo, int p_id, Transform p_transform) {
if (get_script_instance() && get_script_instance()->has_method("set_subgizmo_transform")) {
get_script_instance()->call("set_subgizmo_transform", p_id, p_transform);
}
}
void EditorSpatialGizmoPlugin::commit_subgizmos(const EditorSpatialGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform> &p_restore, bool p_cancel) const {
void EditorSpatialGizmoPlugin::commit_subgizmos(const EditorSpatialGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform> &p_restore, bool p_cancel) {
if (get_script_instance() && get_script_instance()->has_method("commit_subgizmos")) {
Array ids;
for (int i = 0; i < p_ids.size(); i++) {

View File

@ -186,8 +186,8 @@ public:
virtual int subgizmos_intersect_ray(const EditorSpatialGizmo *p_gizmo, Camera *p_camera, const Vector2 &p_point) const;
virtual Vector<int> subgizmos_intersect_frustum(const EditorSpatialGizmo *p_gizmo, const Camera *p_camera, const Vector<Plane> &p_frustum) const;
virtual Transform get_subgizmo_transform(const EditorSpatialGizmo *p_gizmo, int p_id) const;
virtual void set_subgizmo_transform(const EditorSpatialGizmo *p_gizmo, int p_id, Transform p_transform) const;
virtual void commit_subgizmos(const EditorSpatialGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform> &p_restore, bool p_cancel = false) const;
virtual void set_subgizmo_transform(const EditorSpatialGizmo *p_gizmo, int p_id, Transform p_transform);
virtual void commit_subgizmos(const EditorSpatialGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform> &p_restore, bool p_cancel = false);
Ref<EditorSpatialGizmo> get_gizmo(Spatial *p_spatial);

View File

@ -4,5 +4,4 @@ env.add_source_files(env.modules_sources,"register_types.cpp")
if env["tools"]:
env.add_source_files(env.modules_sources, "skeleton_editor_plugin.cpp")
env.add_source_files(env.modules_sources, "spatial_editor_gizmos.cpp")

View File

@ -24,7 +24,6 @@ SOFTWARE.
#ifdef TOOLS_ENABLED
#include "skeleton_editor_plugin.h"
#include "spatial_editor_gizmos.h"
#endif
void register_skeleton_editor_types() {

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,7 @@
#include "scene/3d/camera.h"
#include "scene/3d/mesh_instance.h"
#include "scene/3d/skeleton.h"
#include "scene/resources/immediate_mesh.h"
class EditorInspectorPluginSkeleton;
class Joint;
@ -93,6 +94,8 @@ class BoneTransformEditor : public VBoxContainer {
void _value_changed_transform(const String &p_path, const Variant &p_value, const String &p_name = "", bool changing = false);
// Changes the transform to the given transform and updates the UI accordingly.
void _change_transform(Transform p_new_transform);
// Update it is truely keyable then.
void _update_key_button(const bool p_keyable);
// Creates a Transform using the EditorPropertyVector3 properties.
Transform compute_transform_from_vector3s() const;
@ -116,6 +119,10 @@ public:
// Transform can be keyed, whether or not to show the button
void set_keyable(const bool p_keyable);
// When rest mode, pose and custom_pose editor are diasbled.
void set_properties_read_only(const bool p_readonly);
void set_transform_read_only(const bool p_readonly);
// Bone can be toggled enabled or disabled, whether or not to show the checkbox
void set_toggle_enabled(const bool p_enabled);
@ -126,45 +133,32 @@ public:
void _checkbox_toggled(const bool p_toggled);
};
class ModuleSkeletonEditor : public VBoxContainer {
GDCLASS(ModuleSkeletonEditor, VBoxContainer);
class SkeletonEditor : public VBoxContainer {
GDCLASS(SkeletonEditor, VBoxContainer);
friend class SkeletonEditorPlugin;
enum Menu {
MENU_OPTION_INIT_POSE,
MENU_OPTION_INSERT_KEYS,
MENU_OPTION_INSERT_KEYS_EXISTED,
MENU_OPTION_POSE_TO_REST,
MENU_OPTION_CREATE_PHYSICAL_SKELETON,
MENU_OPTION_ADD_BONE,
MENU_OPTION_REMOVE_BONE,
MENU_OPTION_RENAME_BONE
enum SkeletonOption {
SKELETON_OPTION_INIT_POSE,
SKELETON_OPTION_INSERT_KEYS,
SKELETON_OPTION_INSERT_KEYS_EXISTED,
SKELETON_OPTION_CREATE_PHYSICAL_SKELETON,
SKELETON_OPTION_ADD_BONE,
SKELETON_OPTION_REMOVE_BONE,
SKELETON_OPTION_RENAME_BONE
};
enum ToolMode {
TOOL_MODE_BONE_SELECT,
TOOL_MODE_BONE_MOVE,
TOOL_MODE_BONE_ROTATE,
TOOL_MODE_BONE_SCALE,
TOOL_MODE_BONE_NONE,
TOOL_MODE_BONE_MAX
};
enum MenuToolOption {
MENU_TOOL_BONE_SELECT,
MENU_TOOL_BONE_MOVE,
MENU_TOOL_BONE_ROTATE,
MENU_TOOL_BONE_SCALE,
MENU_TOOL_BONE_NONE,
MENU_TOOL_BONE_MAX
enum RestOption {
REST_OPTION_POSE_TO_REST
};
struct BoneInfo {
PhysicalBone *physical_bone;
Transform relative_rest; // Relative to skeleton node
BoneInfo() :
physical_bone(NULL) {}
BoneInfo() {
physical_bone = NULL;
}
};
EditorNode *editor;
@ -177,24 +171,24 @@ class ModuleSkeletonEditor : public VBoxContainer {
BoneTransformEditor *pose_editor;
BoneTransformEditor *custom_pose_editor;
VSeparator *separators[2];
MenuButton *options;
ToolButton *tool_button[TOOL_MODE_BONE_MAX];
ToolButton *rest_mode_button;
VSeparator *separator;
MenuButton *skeleton_options;
MenuButton *rest_options;
Button *edit_mode_button;
ToolMode tool_mode = TOOL_MODE_BONE_NONE;
bool rest_mode = false;
bool edit_mode;
EditorFileDialog *file_dialog;
UndoRedo *undo_redo;
bool keyable;
void _on_click_option(int p_option);
static SkeletonEditor *singleton;
void _on_click_skeleton_option(int p_skeleton_option);
void _on_click_rest_option(int p_rest_option);
void _file_selected(const String &p_file);
void _menu_tool_item_pressed(int p_option);
void rest_mode_toggled(const bool pressed);
TreeItem *_find(TreeItem *p_node, const NodePath &p_path);
void edit_mode_toggled(const bool pressed);
EditorFileDialog *file_export_lib;
@ -206,6 +200,7 @@ class ModuleSkeletonEditor : public VBoxContainer {
void init_pose();
void insert_keys(bool p_all_bones);
void pose_to_rest();
void create_physical_skeleton();
PhysicalBone *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos);
@ -213,22 +208,34 @@ class ModuleSkeletonEditor : public VBoxContainer {
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
void set_keyable(const bool p_keyable);
void set_rest_options_enabled(const bool p_rest_options_enabled);
MeshInstance *handles_mesh_instance;
Ref<ImmediateMesh> handles_mesh;
Ref<ShaderMaterial> handle_material;
Ref<Shader> handle_shader;
MeshInstance *pointsm;
Ref<ArrayMesh> am;
Transform bone_original;
void _update_pose_enabled(int p_bone = -1);
void _update_show_rest_only();
void _update_gizmo_transform();
void _update_gizmo_visible();
void _hide_handles();
void _draw_gizmo();
void _draw_handles();
SpatialEditorViewport::EditData _edit;
void _compute_edit(int p_index, const Point2 &p_point);
bool _gizmo_select(int p_index, const Vector2 &p_screenpos, bool p_highlight_only = false);
void _joint_tree_selection_changed();
void _joint_tree_rmb_select(const Vector2 &p_pos);
void _update_properties();
Transform original_local;
Transform original_global;
Transform original_to_local;
void _subgizmo_selection_change();
void _update_spatial_transform_gizmo();
int selected_bone;
protected:
void _notification(int p_what);
@ -236,23 +243,23 @@ protected:
static void _bind_methods();
public:
virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event);
void move_skeleton_bone(NodePath p_skeleton_path, int32_t p_selected_boneidx, int32_t p_target_boneidx);
static SkeletonEditor *get_singleton() { return singleton; }
// Transform can be keyed, whether or not to show the button
void set_keyable(const bool p_keyable);
void select_bone(int p_idx);
int get_selected_bone() const;
void move_skeleton_bone(NodePath p_skeleton_path, int32_t p_selected_boneidx, int32_t p_target_boneidx);
Skeleton *get_skeleton() const { return skeleton; };
void set_rest_mode_toggled(const bool pressed);
bool is_edit_mode() const { return edit_mode; }
void _joint_tree_selection_changed();
void _joint_tree_rmb_select(const Vector2 &p_pos);
void update_bone_original();
Transform get_bone_original() { return bone_original; };
void _update_properties();
ModuleSkeletonEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNode *p_editor, Skeleton *skeleton);
~ModuleSkeletonEditor();
SkeletonEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNode *p_editor, Skeleton *skeleton);
~SkeletonEditor();
void add_bone();
void remove_bone();
@ -277,20 +284,15 @@ class EditorInspectorPluginSkeleton : public EditorInspectorPlugin {
friend class SkeletonEditorPlugin;
ModuleSkeletonEditor *skel_editor;
SkeletonEditor *skel_editor;
EditorNode *editor;
UndoRedo *undo_redo;
void set_rest_mode_toggled(const bool p_pressed);
protected:
static void _bind_methods();
public:
virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { return skel_editor->forward_spatial_gui_input(p_camera, p_event); }
virtual bool can_handle(Object *p_object);
virtual void parse_begin(Object *p_object);
UndoRedo *get_undo_redo() { return undo_redo; }
};
class SkeletonEditorPlugin : public EditorPlugin {
@ -300,12 +302,8 @@ class SkeletonEditorPlugin : public EditorPlugin {
EditorNode *editor;
public:
virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) {
if (SpatialEditor::get_singleton()->get_tool_mode() != SpatialEditor::TOOL_MODE_EXTERNAL) {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
return skeleton_plugin->forward_spatial_gui_input(p_camera, p_event);
}
virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event);
bool has_main_screen() const { return false; }
virtual bool handles(Object *p_object) const;
@ -317,4 +315,26 @@ protected:
void _notification(int p_what);
};
class SkeletonGizmoPlugin : public EditorSpatialGizmoPlugin {
GDCLASS(SkeletonGizmoPlugin, EditorSpatialGizmoPlugin);
Ref<SpatialMaterial> unselected_mat;
Ref<ShaderMaterial> selected_mat;
Ref<Shader> selected_sh;
public:
bool has_gizmo(Spatial *p_spatial);
String get_gizmo_name() const;
int get_priority() const;
int subgizmos_intersect_ray(const EditorSpatialGizmo *p_gizmo, Camera *p_camera, const Vector2 &p_point) const;
Transform get_subgizmo_transform(const EditorSpatialGizmo *p_gizmo, int p_id) const;
void set_subgizmo_transform(const EditorSpatialGizmo *p_gizmo, int p_id, Transform p_transform);
void commit_subgizmos(const EditorSpatialGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform> &p_restore, bool p_cancel);
void redraw(EditorSpatialGizmo *p_gizmo);
SkeletonGizmoPlugin();
};
#endif // SKELETON_EDITOR_PLUGIN_H

View File

@ -1,18 +0,0 @@
In case it's needed later
+ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
for (int i = 0; i < bones.size(); i++) {
String prep = "bones/" + itos(i) + "/";
-p_list->push_back(PropertyInfo(Variant::STRING, prep + "name"));
-p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1"));
-p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest"));
-p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled"));
+p_list->push_back(PropertyInfo(Variant::STRING, prep + "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1", PROPERTY_USAGE_NOEDITOR));
+p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
-p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children"));
+p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
}

View File

@ -1,269 +0,0 @@
/*************************************************************************/
/* spatial_editor_gizmos.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "spatial_editor_gizmos.h"
#include "editor/editor_settings.h"
#include "scene/3d/skeleton.h"
#include "scene/resources/skin.h"
#include "scene/resources/surface_tool.h"
SkeletonSpatialGizmoPlugin::SkeletonSpatialGizmoPlugin() {
skeleton_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
selected_bone_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/selected_bone", Color(1, 0, 0));
bone_axis_length = EDITOR_DEF("editors/3d_gizmos/gizmo_settings/bone_axis_length", (float)0.015);
create_material("skeleton_material", skeleton_color);
selected_mat = Ref<ShaderMaterial>(memnew(ShaderMaterial));
selected_sh = Ref<Shader>(memnew(Shader));
selected_sh->set_code(" \
shader_type spatial; \
render_mode unshaded; \
uniform vec4 albedo : hint_color = vec4(1,1,1,1); \
uniform sampler2D texture_albedo : hint_albedo; \
uniform float point_size : hint_range(0,128) = 32; \
void vertex() { \
if (!OUTPUT_IS_SRGB) { \
COLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) ); \
} \
VERTEX = VERTEX; \
POSITION=PROJECTION_MATRIX*INV_CAMERA_MATRIX*WORLD_MATRIX*vec4(VERTEX.xyz,1.0); \
POSITION.z = mix(POSITION.z, -POSITION.w, 0.998); \
} \
void fragment() { \
vec2 base_uv = UV; \
vec4 albedo_tex = texture(texture_albedo,base_uv); \
albedo_tex *= COLOR; \
if (albedo.a * albedo_tex.a < 0.5) { discard; } \
ALBEDO = albedo.rgb * albedo_tex.rgb; \
} \
");
selected_mat->set_shader(selected_sh);
}
bool SkeletonSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
return Object::cast_to<Skeleton>(p_spatial) != NULL;
}
String SkeletonSpatialGizmoPlugin::get_gizmo_name() const {
return "Skeleton";
}
int SkeletonSpatialGizmoPlugin::get_priority() const {
return -1;
}
void SkeletonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
Skeleton *skel = Object::cast_to<Skeleton>(p_gizmo->get_spatial_node());
skel->force_update_all_bone_transforms();
p_gizmo->clear();
Ref<Material> material;
if (p_gizmo->is_selected()) {
material = selected_mat;
} else {
material = get_material("skeleton_material", p_gizmo);
}
Ref<SurfaceTool> surface_tool(memnew(SurfaceTool));
surface_tool->begin(Mesh::PRIMITIVE_LINES);
surface_tool->set_material(material);
Vector<Transform> grests;
grests.resize(skel->get_bone_count());
Vector<int> bones;
Vector<float> weights;
bones.resize(4);
weights.resize(4);
for (int i = 0; i < 4; i++) {
bones.write[i] = 0;
weights.write[i] = 0;
}
weights.write[0] = 1;
Color bone_color;
AABB aabb;
//LocalVector<int> bones_to_process = skel->get_parentless_bones();
LocalVector<int> bones_to_process;
bones_to_process = skel->get_parentless_bones();
while (bones_to_process.size() > 0) {
int current_bone_idx = bones_to_process[0];
bones_to_process.erase(current_bone_idx);
LocalVector<int> child_bones_vector;
child_bones_vector = skel->get_bone_children(current_bone_idx);
int child_bones_size = child_bones_vector.size();
// You have children but no parent, then you must be a root/parentless bone.
if (child_bones_size >= 0 && skel->get_bone_parent(current_bone_idx) <= 0) {
grests.write[current_bone_idx] = skel->global_pose_to_local_pose(current_bone_idx, skel->get_bone_global_pose(current_bone_idx));
}
for (int i = 0; i < child_bones_size; i++) {
int child_bone_idx = child_bones_vector[i];
int parent = skel->get_bone_parent(child_bone_idx);
if (parent == skel->get_selected_bone()) {
bone_color = selected_bone_color;
} else {
bone_color = skeleton_color;
}
grests.write[child_bone_idx] = skel->global_pose_to_local_pose(child_bone_idx, skel->get_bone_global_pose(child_bone_idx));
Vector3 v0 = grests[current_bone_idx].origin;
Vector3 v1 = grests[child_bone_idx].origin;
Vector3 d = skel->get_bone_rest(child_bone_idx).origin.normalized();
real_t dist = skel->get_bone_rest(child_bone_idx).origin.length();
// Find closest axis.
int closest = -1;
real_t closest_d = 0.0;
for (int j = 0; j < 3; j++) {
real_t dp = Math::abs(grests[current_bone_idx].basis[j].normalized().dot(d));
if (j == 0 || dp > closest_d) {
closest = j;
}
}
//find closest other
Vector3 first;
Vector3 points[4];
int pointidx = 0;
//Color axis_color[3];
//axis_color[0] = Color(1, 0, 0);
//axis_color[1] = Color(0, 1, 0);
//axis_color[2] = Color(0, 0, 1);
for (int j = 0; j < 3; j++) {
/*
if (p_gizmo->is_selected()) {
bones.write[0] = current_bone_idx;
surface_tool->add_bones(bones);
surface_tool->add_weights(weights);
surface_tool->add_color(axis_color[j]);
surface_tool->add_vertex(v1);
surface_tool->add_bones(bones);
surface_tool->add_weights(weights);
surface_tool->add_color(axis_color[j]);
surface_tool->add_vertex(v1 + (grests[current_bone_idx].basis.inverse())[j].normalized() * bone_axis_length);
} else {
bones.write[0] = current_bone_idx;
surface_tool->add_bones(bones);
surface_tool->add_weights(weights);
surface_tool->add_color(axis_color[j]);
surface_tool->add_vertex(v1 - (grests[current_bone_idx].basis.inverse())[j].normalized() * bone_axis_length * 0.5);
surface_tool->add_bones(bones);
surface_tool->add_weights(weights);
surface_tool->add_color(axis_color[j]);
surface_tool->add_vertex(v1 + (grests[current_bone_idx].basis.inverse())[j].normalized() * bone_axis_length * 0.5);
}*/
bones.write[0] = current_bone_idx;
surface_tool->add_bones(bones);
surface_tool->add_weights(weights);
surface_tool->add_color(bone_color);
surface_tool->add_vertex(v0 - grests[current_bone_idx].basis[j].normalized() * dist * 0.05);
surface_tool->add_bones(bones);
surface_tool->add_weights(weights);
surface_tool->add_color(bone_color);
surface_tool->add_vertex(v0 + grests[current_bone_idx].basis[j].normalized() * dist * 0.05);
if (j == closest) {
continue;
}
Vector3 axis;
if (first == Vector3()) {
axis = d.cross(d.cross(grests[current_bone_idx].basis[j])).normalized();
first = axis;
} else {
axis = d.cross(first).normalized();
}
for (int k = 0; k < 2; k++) {
if (k == 1) {
axis = -axis;
}
Vector3 point = v0 + d * dist * 0.2;
point += axis * dist * 0.1;
bones.write[0] = current_bone_idx;
surface_tool->add_bones(bones);
surface_tool->add_weights(weights);
surface_tool->add_color(bone_color);
surface_tool->add_vertex(v0);
surface_tool->add_bones(bones);
surface_tool->add_weights(weights);
surface_tool->add_color(bone_color);
surface_tool->add_vertex(point);
bones.write[0] = current_bone_idx;
surface_tool->add_bones(bones);
surface_tool->add_weights(weights);
surface_tool->add_color(bone_color);
surface_tool->add_vertex(point);
bones.write[0] = child_bone_idx;
surface_tool->add_bones(bones);
surface_tool->add_weights(weights);
surface_tool->add_color(bone_color);
surface_tool->add_vertex(v1);
points[pointidx++] = point;
}
}
SWAP(points[1], points[2]);
for (int j = 0; j < 4; j++) {
bones.write[0] = current_bone_idx;
surface_tool->add_bones(bones);
surface_tool->add_weights(weights);
surface_tool->add_color(bone_color);
surface_tool->add_vertex(points[j]);
surface_tool->add_bones(bones);
surface_tool->add_weights(weights);
surface_tool->add_color(bone_color);
surface_tool->add_vertex(points[(j + 1) % 4]);
}
// Add the bone's children to the list of bones to be processed.
bones_to_process.push_back(child_bones_vector[i]);
}
}
Ref<ArrayMesh> m = surface_tool->commit();
p_gizmo->add_mesh(m, Ref<Material>(), Transform(), skel->register_skin(Ref<Skin>()));
}

View File

@ -1,56 +0,0 @@
#ifndef MODULE_SPATIAL_EDITOR_GIZMOS_H
#define MODULE_SPATIAL_EDITOR_GIZMOS_H
/*************************************************************************/
/* spatial_editor_gizmos.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "editor/spatial_editor_gizmos.h"
#include "scene/3d/camera.h"
#include "core/local_vector.h"
class Camera;
class SkeletonSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
GDCLASS(SkeletonSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
Color skeleton_color = Color(1, 0.8, 0.4);
Color selected_bone_color = Color(1, 0, 0);
float bone_axis_length = 0.015;
Ref<ShaderMaterial> selected_mat;
Ref<Shader> selected_sh;
public:
bool has_gizmo(Spatial *p_spatial);
String get_gizmo_name() const;
int get_priority() const;
void redraw(EditorSpatialGizmo *p_gizmo);
SkeletonSpatialGizmoPlugin();
};
#endif // SPATIAL_EDITOR_GIZMOS_H

View File

@ -658,6 +658,7 @@ void Skeleton::set_bone_enabled(int p_bone, bool p_enabled) {
ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].enabled = p_enabled;
emit_signal(SceneStringNames::get_singleton()->bone_enabled_changed, p_bone);
_make_dirty();
}
@ -667,6 +668,16 @@ bool Skeleton::is_bone_enabled(int p_bone) const {
return bones[p_bone].enabled;
}
void Skeleton::set_show_rest_only(bool p_enabled) {
show_rest_only = p_enabled;
emit_signal(SceneStringNames::get_singleton()->show_rest_only_changed);
_make_dirty();
}
bool Skeleton::is_show_rest_only() const {
return show_rest_only;
}
void Skeleton::clear_bones() {
bones.clear();
process_order_dirty = true;
@ -1065,6 +1076,12 @@ Ref<SkinReference> Skeleton::register_skin(const Ref<Skin> &p_skin) {
return skin_ref;
}
void Skeleton::force_update_all_dirty_bones() {
if (dirty) {
const_cast<Skeleton *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
}
}
void Skeleton::force_update_all_bone_transforms() {
_update_process_order();
@ -1086,9 +1103,10 @@ void Skeleton::force_update_bone_children_transforms(int p_bone_idx) {
bones_to_process.erase(current_bone_idx);
Bone &b = bonesptr[current_bone_idx];
bool bone_enabled = b.enabled && !show_rest_only;
if (b.disable_rest) {
if (b.enabled) {
if (bone_enabled) {
b.update_pose_cache();
Transform pose = b.pose_cache;
if (b.custom_pose_enable) {
@ -1112,7 +1130,7 @@ void Skeleton::force_update_bone_children_transforms(int p_bone_idx) {
}
} else {
if (b.enabled) {
if (bone_enabled) {
b.update_pose_cache();
Transform pose = b.pose_cache;
if (b.custom_pose_enable) {
@ -1303,6 +1321,9 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_pose_rotation", "bone_idx"), &Skeleton::get_bone_pose_rotation);
ClassDB::bind_method(D_METHOD("get_bone_pose_scale", "bone_idx"), &Skeleton::get_bone_pose_scale);
ClassDB::bind_method(D_METHOD("is_bone_enabled", "bone_idx"), &Skeleton::is_bone_enabled);
ClassDB::bind_method(D_METHOD("set_bone_enabled", "bone_idx", "enabled"), &Skeleton::set_bone_enabled, true);
ClassDB::bind_method(D_METHOD("clear_bones_global_pose_override"), &Skeleton::clear_bones_global_pose_override);
ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton::set_bone_global_pose_override, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_bone_global_pose_override", "bone_idx"), &Skeleton::get_bone_global_pose_override);
@ -1326,6 +1347,10 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("local_pose_to_global_pose", "bone_idx", "local_pose"), &Skeleton::local_pose_to_global_pose);
ClassDB::bind_method(D_METHOD("global_pose_z_forward_to_bone_forward", "bone_idx", "basis"), &Skeleton::global_pose_z_forward_to_bone_forward);
ClassDB::bind_method(D_METHOD("set_show_rest_only"), &Skeleton::set_show_rest_only);
ClassDB::bind_method(D_METHOD("is_show_rest_only"), &Skeleton::is_show_rest_only);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_rest_only"), "set_show_rest_only", "is_show_rest_only");
#ifndef _3D_DISABLED
ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton::get_animate_physical_bones);
@ -1351,6 +1376,8 @@ void Skeleton::_bind_methods() {
ADD_SIGNAL(MethodInfo("bone_pose_changed", PropertyInfo(Variant::INT, "bone_idx")));
ADD_SIGNAL(MethodInfo("bones_updated"));
ADD_SIGNAL(MethodInfo("bone_enabled_changed", PropertyInfo(Variant::INT, "bone_idx")));
ADD_SIGNAL(MethodInfo("show_rest_only_changed"));
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
@ -1362,6 +1389,7 @@ Skeleton::Skeleton() {
dirty = false;
version = 1;
process_order_dirty = true;
show_rest_only = false;
}
Skeleton::~Skeleton() {

View File

@ -158,6 +158,8 @@ private:
void _make_dirty();
bool dirty;
bool show_rest_only;
uint64_t version;
void _update_process_order();
@ -220,6 +222,9 @@ public:
void set_bone_enabled(int p_bone, bool p_enabled);
bool is_bone_enabled(int p_bone) const;
void set_show_rest_only(bool p_enabled);
bool is_show_rest_only() const;
void clear_bones();
// posing api
@ -250,6 +255,7 @@ public:
Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
void force_update_all_dirty_bones();
void force_update_all_bone_transforms();
void force_update_bone_children_transforms(int bone_idx);

View File

@ -552,6 +552,20 @@ void Spatial::update_gizmos() {
#endif
}
void Spatial::set_subgizmo_selection(Ref<SpatialGizmo> p_gizmo, int p_id, Transform p_transform) {
#ifdef TOOLS_ENABLED
if (!is_inside_world()) {
return;
}
if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) {
get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_set_subgizmo_selection, this, p_gizmo, p_id, p_transform);
}
#endif
}
void Spatial::clear_subgizmo_selection() {
#ifdef TOOLS_ENABLED
if (!is_inside_world()) {
@ -940,6 +954,7 @@ void Spatial::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_gizmo", "gizmo"), &Spatial::add_gizmo);
ClassDB::bind_method(D_METHOD("get_gizmos"), &Spatial::get_gizmos_bind);
ClassDB::bind_method(D_METHOD("clear_gizmos"), &Spatial::clear_gizmos);
ClassDB::bind_method(D_METHOD("set_subgizmo_selection", "gizmo", "id", "transform"), &Spatial::set_subgizmo_selection);
ClassDB::bind_method(D_METHOD("clear_subgizmo_selection"), &Spatial::clear_subgizmo_selection);
ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Spatial::set_visible);
@ -1020,6 +1035,7 @@ Spatial::Spatial() :
#ifdef TOOLS_ENABLED
data.gizmos_disabled = false;
data.gizmos_dirty = false;
data.transform_gizmo_visible = true;
#endif
data.notify_local_transform = false;
data.notify_transform = false;

View File

@ -110,6 +110,7 @@ class Spatial : public Node {
Vector<Ref<SpatialGizmo>> gizmos;
bool gizmos_disabled : 1;
bool gizmos_dirty : 1;
bool transform_gizmo_visible : 1;
#endif
} data;
@ -180,6 +181,8 @@ public:
#ifdef TOOLS_ENABLED
virtual Transform get_global_gizmo_transform() const;
virtual Transform get_local_gizmo_transform() const;
virtual void set_transform_gizmo_visible(bool p_enabled) { data.transform_gizmo_visible = p_enabled; };
virtual bool is_transform_gizmo_visible() const { return data.transform_gizmo_visible; };
virtual AABB get_fallback_gizmo_aabb() const;
#endif
@ -191,6 +194,7 @@ public:
void set_disable_gizmos(bool p_enabled);
void update_gizmos();
void set_subgizmo_selection(Ref<SpatialGizmo> p_gizmo, int p_id, Transform p_transform = Transform());
void clear_subgizmo_selection();
Vector<Ref<SpatialGizmo>> get_gizmos() const;
Vector<Variant> get_gizmos_bind() const;

View File

@ -68,6 +68,8 @@ SceneStringNames::SceneStringNames() {
pose_updated = StaticCString::create("pose_updated");
bone_pose_changed = StaticCString::create("bone_pose_changed");
bone_enabled_changed = StaticCString::create("bone_enabled_changed");
show_rest_only_changed = StaticCString::create("show_rest_only_changed");
mouse_entered = StaticCString::create("mouse_entered");
mouse_exited = StaticCString::create("mouse_exited");
@ -142,6 +144,7 @@ SceneStringNames::SceneStringNames() {
_spatial_editor_group = StaticCString::create("_spatial_editor_group");
_request_gizmo = StaticCString::create("_request_gizmo");
_set_subgizmo_selection = StaticCString::create("_set_subgizmo_selection");
_clear_subgizmo_selection = StaticCString::create("_clear_subgizmo_selection");
offset = StaticCString::create("offset");

View File

@ -99,6 +99,8 @@ public:
StringName pose_updated;
StringName bone_pose_changed;
StringName bone_enabled_changed;
StringName show_rest_only_changed;
StringName body_shape_entered;
StringName body_entered;
@ -160,6 +162,7 @@ public:
StringName _spatial_editor_group;
StringName _request_gizmo;
StringName _set_subgizmo_selection;
StringName _clear_subgizmo_selection;
StringName offset;