diff options
| -rw-r--r-- | doc/classes/Animation.xml | 1 | ||||
| -rw-r--r-- | editor/animation_track_editor.cpp | 63 | ||||
| -rw-r--r-- | editor/animation_track_editor.h | 4 | ||||
| -rw-r--r-- | editor/animation_track_editor_plugins.cpp | 4 | ||||
| -rw-r--r-- | editor/icons/NewKey.svg | 1 | ||||
| -rw-r--r-- | editor/inspector_dock.cpp | 4 | ||||
| -rw-r--r-- | editor/plugins/skeleton_3d_editor_plugin.cpp | 268 | ||||
| -rw-r--r-- | editor/plugins/skeleton_3d_editor_plugin.h | 38 | ||||
| -rw-r--r-- | modules/gltf/gltf_document.cpp | 2 | ||||
| -rw-r--r-- | scene/3d/skeleton_3d.cpp | 22 | ||||
| -rw-r--r-- | scene/resources/animation.cpp | 6 | ||||
| -rw-r--r-- | scene/resources/animation.h | 3 | 
12 files changed, 255 insertions, 161 deletions
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index ebcced7dc4..52308d1438 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -226,6 +226,7 @@  		<method name="find_track" qualifiers="const">  			<return type="int" />  			<argument index="0" name="path" type="NodePath" /> +			<argument index="1" name="type" type="int" enum="Animation.TrackType" />  			<description>  				Returns the index of the specified track. If the track is not found, return -1.  			</description> diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 7f118532c9..4373523061 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -3487,7 +3487,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {  	for (const InsertData &E : insert_data) {  		// Prevent insertion of multiple tracks. -		if (E.path == p_id.path) { +		if (E.path == p_id.path && E.type == p_id.type) {  			return; // Already inserted a track this frame.  		}  	} @@ -3537,7 +3537,11 @@ void AnimationTrackEditor::_insert_track(bool p_create_reset, bool p_create_bezi  	}  } -void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Transform3D &p_xform) { +void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type, const Variant p_value) { +	ERR_FAIL_COND(!root); +	ERR_FAIL_COND_MSG( +			(p_type != Animation::TYPE_POSITION_3D && p_type != Animation::TYPE_ROTATION_3D && p_type != Animation::TYPE_SCALE_3D), +			"Track type must be Position/Rotation/Scale 3D.");  	if (!keying) {  		return;  	} @@ -3545,7 +3549,6 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_  		return;  	} -	ERR_FAIL_COND(!root);  	// Let's build a node path.  	String path = root->get_path_to(p_node);  	if (p_sub != "") { @@ -3554,24 +3557,16 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_  	NodePath np = path; -	int position_idx = -1; -	int rotation_idx = -1; -	int scale_idx = -1; +	int track_idx = -1;  	for (int i = 0; i < animation->get_track_count(); i++) {  		if (animation->track_get_path(i) != np) {  			continue;  		} - -		if (animation->track_get_type(i) == Animation::TYPE_POSITION_3D) { -			position_idx = i; -		} -		if (animation->track_get_type(i) == Animation::TYPE_ROTATION_3D) { -			rotation_idx = i; -		} -		if (animation->track_get_type(i) == Animation::TYPE_SCALE_3D) { -			scale_idx = i; +		if (animation->track_get_type(i) != p_type) { +			continue;  		} +		track_idx = i;  	}  	InsertData id; @@ -3579,48 +3574,30 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_  	// TRANSLATORS: This describes the target of new animation track, will be inserted into another string.  	id.query = vformat(TTR("node '%s'"), p_node->get_name());  	id.advance = false; - -	{ -		id.track_idx = position_idx; -		id.value = p_xform.origin; -		id.type = Animation::TYPE_POSITION_3D; -		_query_insert(id); -	} -	{ -		id.track_idx = rotation_idx; -		id.value = p_xform.basis.get_rotation_quaternion(); -		id.type = Animation::TYPE_ROTATION_3D; -		_query_insert(id); -	} -	{ -		id.track_idx = scale_idx; -		id.value = p_xform.basis.get_scale(); -		id.type = Animation::TYPE_SCALE_3D; -		_query_insert(id); -	} +	id.track_idx = track_idx; +	id.value = p_value; +	id.type = p_type; +	_query_insert(id);  } -bool AnimationTrackEditor::has_transform_track(Node3D *p_node, const String &p_sub) { +bool AnimationTrackEditor::has_track(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type) { +	ERR_FAIL_COND_V(!root, false);  	if (!keying) {  		return false;  	}  	if (!animation.is_valid()) {  		return false;  	} -	if (!root) { -		return false; -	} -	//let's build a node path +	// 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); + +	int track_id = animation->find_track(path, p_type);  	if (track_id >= 0) { -		if (animation->track_get_type(track_id) == Animation::TYPE_POSITION_3D || animation->track_get_type(track_id) == Animation::TYPE_ROTATION_3D || animation->track_get_type(track_id) == Animation::TYPE_SCALE_3D) { -			return true; -		} +		return true;  	}  	return false;  } diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 2555901557..05cf91de1d 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -527,8 +527,8 @@ public:  	void set_anim_pos(float p_pos);  	void insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists = false);  	void insert_value_key(const String &p_property, const Variant &p_value, bool p_advance); -	void insert_transform_key(Node3D *p_node, const String &p_sub, const Transform3D &p_xform); -	bool has_transform_track(Node3D *p_node, const String &p_sub); +	void insert_transform_key(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type, const Variant p_value); +	bool has_track(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type);  	void make_insert_queue();  	void commit_insert_queue(); diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index 4ee8b991e4..70ba806c37 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -419,7 +419,7 @@ Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_se  			// Go through other track to find if animation is set  			String animation_path = get_animation()->track_get_path(get_track());  			animation_path = animation_path.replace(":frame", ":animation"); -			int animation_track = get_animation()->find_track(animation_path); +			int animation_track = get_animation()->find_track(animation_path, get_animation()->track_get_type(get_track()));  			float track_time = get_animation()->track_get_key_time(get_track(), p_index);  			int animaiton_index = get_animation()->track_find_key(animation_track, track_time);  			animation = get_animation()->track_get_key_value(animation_track, animaiton_index); @@ -511,7 +511,7 @@ void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, in  			// Go through other track to find if animation is set  			String animation_path = get_animation()->track_get_path(get_track());  			animation_path = animation_path.replace(":frame", ":animation"); -			int animation_track = get_animation()->find_track(animation_path); +			int animation_track = get_animation()->find_track(animation_path, get_animation()->track_get_type(get_track()));  			float track_time = get_animation()->track_get_key_time(get_track(), p_index);  			int animaiton_index = get_animation()->track_find_key(animation_track, track_time);  			animation = get_animation()->track_get_key_value(animation_track, animaiton_index); diff --git a/editor/icons/NewKey.svg b/editor/icons/NewKey.svg new file mode 100644 index 0000000000..fc8507e6c4 --- /dev/null +++ b/editor/icons/NewKey.svg @@ -0,0 +1 @@ +<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-opacity=".9961"><path d="m13 9h-2v2h-2v2h2v2h2v-2h2v-2h-2z"/><path d="m10 9.723c-.596-.347-1-.985-1-1.723 0-1.104.896-2 2-2s2 .896 2 2h1v2h.445c.344-.591.555-1.268.555-2 0-2.209-1.791-4-4-4-1.822.002-3.414 1.235-3.869 3h-6.131v2h1v2h3v-2h2.133c.16.62.466 1.169.867 1.627v-.627h2z"/></g></svg> diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 59d0b92ba0..5622d0b145 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -391,7 +391,9 @@ void InspectorDock::_transform_keyed(Object *sp, const String &p_sub, const Tran  	if (!s) {  		return;  	} -	AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_transform_key(s, p_sub, p_key); +	AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_transform_key(s, p_sub, Animation::TYPE_POSITION_3D, p_key.origin); +	AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_transform_key(s, p_sub, Animation::TYPE_ROTATION_3D, p_key.basis.get_rotation_quaternion()); +	AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_transform_key(s, p_sub, Animation::TYPE_SCALE_3D, p_key.basis.get_scale());  }  void InspectorDock::_warning_pressed() { diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 708eaf2c46..0b8a56503c 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -54,6 +54,7 @@ void BoneTransformEditor::create_editors() {  	enabled_checkbox = memnew(EditorPropertyCheck());  	enabled_checkbox->set_label("Pose Enabled"); +	enabled_checkbox->set_selectable(false);  	enabled_checkbox->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed));  	section->get_vbox()->add_child(enabled_checkbox); @@ -61,21 +62,27 @@ void BoneTransformEditor::create_editors() {  	position_property = memnew(EditorPropertyVector3());  	position_property->setup(-10000, 10000, 0.001f, true);  	position_property->set_label("Position"); +	position_property->set_selectable(false);  	position_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed)); +	position_property->connect("property_keyed", callable_mp(this, &BoneTransformEditor::_property_keyed));  	section->get_vbox()->add_child(position_property);  	// Rotation property.  	rotation_property = memnew(EditorPropertyQuaternion());  	rotation_property->setup(-10000, 10000, 0.001f, true);  	rotation_property->set_label("Rotation"); +	rotation_property->set_selectable(false);  	rotation_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed)); +	rotation_property->connect("property_keyed", callable_mp(this, &BoneTransformEditor::_property_keyed));  	section->get_vbox()->add_child(rotation_property);  	// Scale property.  	scale_property = memnew(EditorPropertyVector3());  	scale_property->setup(-10000, 10000, 0.001f, true);  	scale_property->set_label("Scale"); +	scale_property->set_selectable(false);  	scale_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed)); +	scale_property->connect("property_keyed", callable_mp(this, &BoneTransformEditor::_property_keyed));  	section->get_vbox()->add_child(scale_property);  	// Transform/Matrix section. @@ -87,6 +94,7 @@ void BoneTransformEditor::create_editors() {  	rest_matrix = memnew(EditorPropertyTransform3D());  	rest_matrix->setup(-10000, 10000, 0.001f, true);  	rest_matrix->set_label("Transform"); +	rest_matrix->set_selectable(false);  	rest_section->get_vbox()->add_child(rest_matrix);  } @@ -116,6 +124,12 @@ BoneTransformEditor::BoneTransformEditor(Skeleton3D *p_skeleton) :  	undo_redo = EditorNode::get_undo_redo();  } +void BoneTransformEditor::set_keyable(const bool p_keyable) { +	position_property->set_keying(p_keyable); +	rotation_property->set_keying(p_keyable); +	scale_property->set_keying(p_keyable); +} +  void BoneTransformEditor::set_target(const String &p_prop) {  	enabled_checkbox->set_object_and_property(skeleton, p_prop + "enabled");  	enabled_checkbox->update_property(); @@ -133,6 +147,23 @@ void BoneTransformEditor::set_target(const String &p_prop) {  	rest_matrix->update_property();  } +void BoneTransformEditor::_property_keyed(const String &p_path, bool p_advance) { +	AnimationTrackEditor *te = AnimationPlayerEditor::get_singleton()->get_track_editor(); +	PackedStringArray split = p_path.split("/"); +	if (split.size() == 3 && split[0] == "bones") { +		int bone_idx = split[1].to_int(); +		if (split[2] == "position") { +			te->insert_transform_key(skeleton, skeleton->get_bone_name(bone_idx), Animation::TYPE_POSITION_3D, skeleton->get(p_path)); +		} +		if (split[2] == "rotation") { +			te->insert_transform_key(skeleton, skeleton->get_bone_name(bone_idx), Animation::TYPE_ROTATION_3D, skeleton->get(p_path)); +		} +		if (split[2] == "scale") { +			te->insert_transform_key(skeleton, skeleton->get_bone_name(bone_idx), Animation::TYPE_SCALE_3D, skeleton->get(p_path)); +		} +	} +} +  void BoneTransformEditor::_update_properties() {  	if (!skeleton) {  		return; @@ -141,30 +172,30 @@ void BoneTransformEditor::_update_properties() {  	List<PropertyInfo> props;  	skeleton->get_property_list(&props);  	for (const PropertyInfo &E : props) { -		PackedStringArray spr = E.name.split("/"); -		if (spr.size() == 3 && spr[0] == "bones") { -			if (spr[1].to_int() == selected) { -				if (spr[2] == "enabled") { +		PackedStringArray split = E.name.split("/"); +		if (split.size() == 3 && split[0] == "bones") { +			if (split[1].to_int() == selected) { +				if (split[2] == "enabled") {  					enabled_checkbox->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);  					enabled_checkbox->update_property();  					enabled_checkbox->update();  				} -				if (spr[2] == "position") { +				if (split[2] == "position") {  					position_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);  					position_property->update_property();  					position_property->update();  				} -				if (spr[2] == "rotation") { +				if (split[2] == "rotation") {  					rotation_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);  					rotation_property->update_property();  					rotation_property->update();  				} -				if (spr[2] == "scale") { +				if (split[2] == "scale") {  					scale_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);  					scale_property->update_property();  					scale_property->update();  				} -				if (spr[2] == "rest") { +				if (split[2] == "rest") {  					rest_matrix->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);  					rest_matrix->update_property();  					rest_matrix->update(); @@ -178,12 +209,16 @@ Skeleton3DEditor *Skeleton3DEditor::singleton = nullptr;  void Skeleton3DEditor::set_keyable(const bool p_keyable) {  	keyable = p_keyable; -	skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_INSERT_KEYS, !p_keyable); -	skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_INSERT_KEYS_EXISTED, !p_keyable); +	if (p_keyable) { +		animation_hb->show(); +	} else { +		animation_hb->hide(); +	}  }; -void Skeleton3DEditor::set_rest_options_enabled(const bool p_rest_options_enabled) { -	rest_options->get_popup()->set_item_disabled(REST_OPTION_POSE_TO_REST, !p_rest_options_enabled); +void Skeleton3DEditor::set_bone_options_enabled(const bool p_bone_options_enabled) { +	skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_INIT_SELECTED_POSES, !p_bone_options_enabled); +	skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_SELECTED_POSES_TO_RESTS, !p_bone_options_enabled);  };  void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) { @@ -192,62 +227,76 @@ void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) {  	}  	switch (p_skeleton_option) { -		case SKELETON_OPTION_CREATE_PHYSICAL_SKELETON: { -			create_physical_skeleton(); +		case SKELETON_OPTION_INIT_ALL_POSES: { +			init_pose(true);  			break;  		} -		case SKELETON_OPTION_INIT_POSE: { -			init_pose(); +		case SKELETON_OPTION_INIT_SELECTED_POSES: { +			init_pose(false);  			break;  		} -		case SKELETON_OPTION_INSERT_KEYS: { -			insert_keys(true); +		case SKELETON_OPTION_ALL_POSES_TO_RESTS: { +			pose_to_rest(true);  			break;  		} -		case SKELETON_OPTION_INSERT_KEYS_EXISTED: { -			insert_keys(false); +		case SKELETON_OPTION_SELECTED_POSES_TO_RESTS: { +			pose_to_rest(false); +			break; +		} +		case SKELETON_OPTION_CREATE_PHYSICAL_SKELETON: { +			create_physical_skeleton();  			break;  		}  	}  } -void Skeleton3DEditor::_on_click_rest_option(int p_rest_option) { +void Skeleton3DEditor::init_pose(const bool p_all_bones) {  	if (!skeleton) {  		return;  	} - -	switch (p_rest_option) { -		case REST_OPTION_POSE_TO_REST: { -			pose_to_rest(); -			break; -		} -	} -} - -void Skeleton3DEditor::init_pose() {  	const int bone_len = skeleton->get_bone_count();  	if (!bone_len) {  		return;  	} +  	UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();  	ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS); -	for (int i = 0; i < bone_len; i++) { -		Transform3D rest = skeleton->get_bone_rest(i); -		ur->add_do_method(skeleton, "set_bone_pose_position", i, rest.origin); -		ur->add_do_method(skeleton, "set_bone_pose_rotation", i, rest.basis.get_rotation_quaternion()); -		ur->add_do_method(skeleton, "set_bone_pose_scale", i, rest.basis.get_scale()); -		ur->add_undo_method(skeleton, "set_bone_pose_position", i, skeleton->get_bone_pose_position(i)); -		ur->add_undo_method(skeleton, "set_bone_pose_rotation", i, skeleton->get_bone_pose_rotation(i)); -		ur->add_undo_method(skeleton, "set_bone_pose_scale", i, skeleton->get_bone_pose_scale(i)); +	if (p_all_bones) { +		for (int i = 0; i < bone_len; i++) { +			Transform3D rest = skeleton->get_bone_rest(i); +			ur->add_do_method(skeleton, "set_bone_pose_position", i, rest.origin); +			ur->add_do_method(skeleton, "set_bone_pose_rotation", i, rest.basis.get_rotation_quaternion()); +			ur->add_do_method(skeleton, "set_bone_pose_scale", i, rest.basis.get_scale()); +			ur->add_undo_method(skeleton, "set_bone_pose_position", i, skeleton->get_bone_pose_position(i)); +			ur->add_undo_method(skeleton, "set_bone_pose_rotation", i, skeleton->get_bone_pose_rotation(i)); +			ur->add_undo_method(skeleton, "set_bone_pose_scale", i, skeleton->get_bone_pose_scale(i)); +		} +	} else { +		// Todo: Do method with multiple bone selection. +		if (selected_bone == -1) { +			ur->commit_action(); +			return; +		} +		Transform3D rest = skeleton->get_bone_rest(selected_bone); +		ur->add_do_method(skeleton, "set_bone_pose_position", selected_bone, rest.origin); +		ur->add_do_method(skeleton, "set_bone_pose_rotation", selected_bone, rest.basis.get_rotation_quaternion()); +		ur->add_do_method(skeleton, "set_bone_pose_scale", selected_bone, rest.basis.get_scale()); +		ur->add_undo_method(skeleton, "set_bone_pose_position", selected_bone, skeleton->get_bone_pose_position(selected_bone)); +		ur->add_undo_method(skeleton, "set_bone_pose_rotation", selected_bone, skeleton->get_bone_pose_rotation(selected_bone)); +		ur->add_undo_method(skeleton, "set_bone_pose_scale", selected_bone, skeleton->get_bone_pose_scale(selected_bone));  	}  	ur->commit_action();  } -void Skeleton3DEditor::insert_keys(bool p_all_bones) { +void Skeleton3DEditor::insert_keys(const bool p_all_bones) {  	if (!skeleton) {  		return;  	} +	bool pos_enabled = key_loc_button->is_pressed(); +	bool rot_enabled = key_rot_button->is_pressed(); +	bool scl_enabled = key_scale_button->is_pressed(); +  	int bone_len = skeleton->get_bone_count();  	Node *root = EditorNode::get_singleton()->get_tree()->get_root();  	String path = root->get_path_to(skeleton); @@ -261,26 +310,44 @@ void Skeleton3DEditor::insert_keys(bool p_all_bones) {  			continue;  		} -		if (!p_all_bones && !te->has_transform_track(skeleton, name)) { -			continue; +		if (pos_enabled && (p_all_bones || te->has_track(skeleton, name, Animation::TYPE_POSITION_3D))) { +			te->insert_transform_key(skeleton, name, Animation::TYPE_POSITION_3D, skeleton->get_bone_pose_position(i)); +		} +		if (rot_enabled && (p_all_bones || te->has_track(skeleton, name, Animation::TYPE_ROTATION_3D))) { +			te->insert_transform_key(skeleton, name, Animation::TYPE_ROTATION_3D, skeleton->get_bone_pose_rotation(i)); +		} +		if (scl_enabled && (p_all_bones || te->has_track(skeleton, name, Animation::TYPE_SCALE_3D))) { +			te->insert_transform_key(skeleton, name, Animation::TYPE_SCALE_3D, skeleton->get_bone_pose_scale(i));  		} - -		Transform3D tform = skeleton->get_bone_pose(i); -		te->insert_transform_key(skeleton, name, tform);  	}  	te->commit_insert_queue();  } -void Skeleton3DEditor::pose_to_rest() { +void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {  	if (!skeleton) {  		return;  	} +	const int bone_len = skeleton->get_bone_count(); +	if (!bone_len) { +		return; +	} -	// Todo: Do method with multiple bone selection.  	UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();  	ur->create_action(TTR("Set Bone Rest"), UndoRedo::MERGE_ENDS); -	ur->add_do_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_pose(selected_bone)); -	ur->add_undo_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_rest(selected_bone)); +	if (p_all_bones) { +		for (int i = 0; i < bone_len; i++) { +			ur->add_do_method(skeleton, "set_bone_rest", i, skeleton->get_bone_pose(i)); +			ur->add_undo_method(skeleton, "set_bone_rest", i, skeleton->get_bone_rest(i)); +		} +	} else { +		// Todo: Do method with multiple bone selection. +		if (selected_bone == -1) { +			ur->commit_action(); +			return; +		} +		ur->add_do_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_pose(selected_bone)); +		ur->add_undo_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_rest(selected_bone)); +	}  	ur->commit_action();  } @@ -466,11 +533,12 @@ void Skeleton3DEditor::_joint_tree_selection_changed() {  			const String bone_path = "bones/" + itos(b_idx) + "/";  			pose_editor->set_target(bone_path); +			pose_editor->set_keyable(keyable);  			selected_bone = b_idx;  		}  	}  	pose_editor->set_visible(selected); -	set_rest_options_enabled(selected); +	set_bone_options_enabled(selected);  	_update_properties();  	_update_gizmo_visible();  } @@ -549,43 +617,82 @@ void Skeleton3DEditor::create_editors() {  	skeleton_options->set_text(TTR("Skeleton3D"));  	skeleton_options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Skeleton3D"), SNAME("EditorIcons"))); -	skeleton_options->get_popup()->add_item(TTR("Init pose"), SKELETON_OPTION_INIT_POSE); -	skeleton_options->get_popup()->add_item(TTR("Insert key of all bone poses"), SKELETON_OPTION_INSERT_KEYS); -	skeleton_options->get_popup()->add_item(TTR("Insert key of bone poses already exist track"), SKELETON_OPTION_INSERT_KEYS_EXISTED); -	skeleton_options->get_popup()->add_item(TTR("Create physical skeleton"), SKELETON_OPTION_CREATE_PHYSICAL_SKELETON); - -	skeleton_options->get_popup()->connect("id_pressed", callable_mp(this, &Skeleton3DEditor::_on_click_skeleton_option)); +	// Skeleton options. +	PopupMenu *p = skeleton_options->get_popup(); +	p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/init_all_poses", TTR("Init all Poses")), SKELETON_OPTION_INIT_ALL_POSES); +	p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/init_selected_poses", TTR("Init selected Poses")), SKELETON_OPTION_INIT_SELECTED_POSES); +	p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/all_poses_to_rests", TTR("Apply all poses to rests")), SKELETON_OPTION_ALL_POSES_TO_RESTS); +	p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/selected_poses_to_rests", TTR("Apply selected poses to rests")), SKELETON_OPTION_SELECTED_POSES_TO_RESTS); +	p->add_item(TTR("Create physical skeleton"), SKELETON_OPTION_CREATE_PHYSICAL_SKELETON); -	// Create Rest Option in Top Menu Bar. -	rest_options = memnew(MenuButton); -	ne->add_control_to_menu_panel(rest_options); - -	rest_options->set_text(TTR("Edit Rest")); -	rest_options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("BoneAttachment3D"), SNAME("EditorIcons"))); - -	rest_options->get_popup()->add_item(TTR("Apply current pose to rest"), REST_OPTION_POSE_TO_REST); -	rest_options->get_popup()->connect("id_pressed", callable_mp(this, &Skeleton3DEditor::_on_click_rest_option)); -	set_rest_options_enabled(false); +	p->connect("id_pressed", callable_mp(this, &Skeleton3DEditor::_on_click_skeleton_option)); +	set_bone_options_enabled(false);  	Vector<Variant> button_binds;  	button_binds.resize(1);  	edit_mode_button = memnew(Button);  	ne->add_control_to_menu_panel(edit_mode_button); -	edit_mode_button->set_tooltip(TTR("Edit Mode\nShow buttons on joints.")); -	edit_mode_button->set_toggle_mode(true);  	edit_mode_button->set_flat(true); +	edit_mode_button->set_toggle_mode(true); +	edit_mode_button->set_focus_mode(FOCUS_NONE); +	edit_mode_button->set_tooltip(TTR("Edit Mode\nShow buttons on joints."));  	edit_mode_button->connect("toggled", callable_mp(this, &Skeleton3DEditor::edit_mode_toggled));  	edit_mode = false; -	set_keyable(te->has_keying()); -  	if (skeleton) {  		skeleton->add_child(handles_mesh_instance);  		handles_mesh_instance->set_skeleton_path(NodePath(""));  	} +	// Keying buttons. +	animation_hb = memnew(HBoxContainer); +	ne->add_control_to_menu_panel(animation_hb); +	animation_hb->add_child(memnew(VSeparator)); +	animation_hb->hide(); + +	key_loc_button = memnew(Button); +	key_loc_button->set_flat(true); +	key_loc_button->set_toggle_mode(true); +	key_loc_button->set_pressed(false); +	key_loc_button->set_focus_mode(FOCUS_NONE); +	key_loc_button->set_tooltip(TTR("Translation mask for inserting keys.")); +	animation_hb->add_child(key_loc_button); + +	key_rot_button = memnew(Button); +	key_rot_button->set_flat(true); +	key_rot_button->set_toggle_mode(true); +	key_rot_button->set_pressed(true); +	key_rot_button->set_focus_mode(FOCUS_NONE); +	key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys.")); +	animation_hb->add_child(key_rot_button); + +	key_scale_button = memnew(Button); +	key_scale_button->set_flat(true); +	key_scale_button->set_toggle_mode(true); +	key_scale_button->set_pressed(false); +	key_scale_button->set_focus_mode(FOCUS_NONE); +	key_scale_button->set_tooltip(TTR("Scale mask for inserting keys.")); +	animation_hb->add_child(key_scale_button); + +	key_insert_button = memnew(Button); +	key_insert_button->set_flat(true); +	key_insert_button->set_focus_mode(FOCUS_NONE); +	key_insert_button->connect("pressed", callable_mp(this, &Skeleton3DEditor::insert_keys), varray(false)); +	key_insert_button->set_tooltip(TTR("Insert key of bone poses already exist track.")); +	key_insert_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_to_existing_tracks", TTR("Insert Key (Existing Tracks)"), KEY_INSERT)); +	animation_hb->add_child(key_insert_button); + +	key_insert_all_button = memnew(Button); +	key_insert_all_button->set_flat(true); +	key_insert_all_button->set_focus_mode(FOCUS_NONE); +	key_insert_all_button->connect("pressed", callable_mp(this, &Skeleton3DEditor::insert_keys), varray(true)); +	key_insert_all_button->set_tooltip(TTR("Insert key of all bone poses.")); +	key_insert_all_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_of_all_bones", TTR("Insert Key (All Bones)"), KEY_MASK_CMD + KEY_INSERT)); +	animation_hb->add_child(key_insert_all_button); + +	// Bone tree.  	const Color section_color = get_theme_color(SNAME("prop_subsection"), SNAME("Editor"));  	EditorInspectorSection *bones_section = memnew(EditorInspectorSection); @@ -613,12 +720,19 @@ void Skeleton3DEditor::create_editors() {  	pose_editor->set_label(TTR("Bone Transform"));  	pose_editor->set_visible(false);  	add_child(pose_editor); + +	set_keyable(te->has_keying());  }  void Skeleton3DEditor::_notification(int p_what) {  	switch (p_what) {  		case NOTIFICATION_READY: { -			edit_mode_button->set_icon(get_theme_icon("ToolBoneSelect", "EditorIcons")); +			edit_mode_button->set_icon(get_theme_icon(SNAME("ToolBoneSelect"), SNAME("EditorIcons"))); +			key_loc_button->set_icon(get_theme_icon(SNAME("KeyPosition"), SNAME("EditorIcons"))); +			key_rot_button->set_icon(get_theme_icon(SNAME("KeyRotation"), SNAME("EditorIcons"))); +			key_scale_button->set_icon(get_theme_icon(SNAME("KeyScale"), SNAME("EditorIcons"))); +			key_insert_button->set_icon(get_theme_icon(SNAME("Key"), SNAME("EditorIcons"))); +			key_insert_all_button->set_icon(get_theme_icon(SNAME("NewKey"), SNAME("EditorIcons")));  			get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Vector<Variant>(), Object::CONNECT_ONESHOT);  			break;  		} @@ -643,7 +757,6 @@ void Skeleton3DEditor::_node_removed(Node *p_node) {  	if (skeleton && p_node == skeleton) {  		skeleton = nullptr;  		skeleton_options->hide(); -		rest_options->hide();  	}  	_update_properties(); @@ -655,7 +768,6 @@ void Skeleton3DEditor::_bind_methods() {  	ClassDB::bind_method(D_METHOD("_joint_tree_rmb_select"), &Skeleton3DEditor::_joint_tree_rmb_select);  	ClassDB::bind_method(D_METHOD("_update_properties"), &Skeleton3DEditor::_update_properties);  	ClassDB::bind_method(D_METHOD("_on_click_skeleton_option"), &Skeleton3DEditor::_on_click_skeleton_option); -	ClassDB::bind_method(D_METHOD("_on_click_rest_option"), &Skeleton3DEditor::_on_click_rest_option);  	ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &Skeleton3DEditor::get_drag_data_fw);  	ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &Skeleton3DEditor::can_drop_data_fw); @@ -866,6 +978,11 @@ Skeleton3DEditor::~Skeleton3DEditor() {  	Node3DEditor *ne = Node3DEditor::get_singleton(); +	if (animation_hb) { +		ne->remove_control_from_menu_panel(animation_hb); +		memdelete(animation_hb); +	} +  	if (separator) {  		ne->remove_control_from_menu_panel(separator);  		memdelete(separator); @@ -876,11 +993,6 @@ Skeleton3DEditor::~Skeleton3DEditor() {  		memdelete(skeleton_options);  	} -	if (rest_options) { -		ne->remove_control_from_menu_panel(rest_options); -		memdelete(rest_options); -	} -  	if (edit_mode_button) {  		ne->remove_control_from_menu_panel(edit_mode_button);  		memdelete(edit_mode_button); diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h index 3b4dd362fb..1dd2d2281d 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.h +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -45,7 +45,6 @@ class Joint;  class PhysicalBone3D;  class Skeleton3DEditorPlugin;  class Button; -class CheckBox;  class BoneTransformEditor : public VBoxContainer {  	GDCLASS(BoneTransformEditor, VBoxContainer); @@ -67,9 +66,6 @@ class BoneTransformEditor : public VBoxContainer {  	UndoRedo *undo_redo; -	// Button *key_button = nullptr; - -	bool keyable = false;  	bool toggle_enabled = false;  	bool updating = false; @@ -79,6 +75,8 @@ class BoneTransformEditor : public VBoxContainer {  	void _value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing); +	void _property_keyed(const String &p_path, bool p_advance); +  protected:  	void _notification(int p_what); @@ -88,6 +86,7 @@ public:  	// Which transform target to modify.  	void set_target(const String &p_prop);  	void set_label(const String &p_label) { label = p_label; } +	void set_keyable(const bool p_keyable);  	void _update_properties();  }; @@ -98,14 +97,11 @@ class Skeleton3DEditor : public VBoxContainer {  	friend class Skeleton3DEditorPlugin;  	enum SkeletonOption { -		SKELETON_OPTION_INIT_POSE, -		SKELETON_OPTION_INSERT_KEYS, -		SKELETON_OPTION_INSERT_KEYS_EXISTED, -		SKELETON_OPTION_CREATE_PHYSICAL_SKELETON -	}; - -	enum RestOption { -		REST_OPTION_POSE_TO_REST +		SKELETON_OPTION_INIT_ALL_POSES, +		SKELETON_OPTION_INIT_SELECTED_POSES, +		SKELETON_OPTION_ALL_POSES_TO_RESTS, +		SKELETON_OPTION_SELECTED_POSES_TO_RESTS, +		SKELETON_OPTION_CREATE_PHYSICAL_SKELETON,  	};  	struct BoneInfo { @@ -124,11 +120,17 @@ class Skeleton3DEditor : public VBoxContainer {  	VSeparator *separator;  	MenuButton *skeleton_options = nullptr; -	MenuButton *rest_options = nullptr;  	Button *edit_mode_button;  	bool edit_mode = false; +	HBoxContainer *animation_hb; +	Button *key_loc_button; +	Button *key_rot_button; +	Button *key_scale_button; +	Button *key_insert_button; +	Button *key_insert_all_button; +  	EditorFileDialog *file_dialog = nullptr;  	bool keyable; @@ -136,7 +138,6 @@ class Skeleton3DEditor : public VBoxContainer {  	static Skeleton3DEditor *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);  	TreeItem *_find(TreeItem *p_node, const NodePath &p_path);  	void edit_mode_toggled(const bool pressed); @@ -148,9 +149,10 @@ class Skeleton3DEditor : public VBoxContainer {  	void create_editors(); -	void init_pose(); -	void insert_keys(bool p_all_bones); -	void pose_to_rest(); +	void init_pose(const bool p_all_bones); +	void pose_to_rest(const bool p_all_bones); + +	void insert_keys(const bool p_all_bones);  	void create_physical_skeleton();  	PhysicalBone3D *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos); @@ -160,7 +162,7 @@ class Skeleton3DEditor : public VBoxContainer {  	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); +	void set_bone_options_enabled(const bool p_bone_options_enabled);  	// Handle.  	MeshInstance3D *handles_mesh_instance; diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index b8da3a713b..0df08a7996 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -6460,7 +6460,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,  				for (int32_t shape_i = 0; shape_i < mesh->get_blend_shape_count(); shape_i++) {  					String shape_name = mesh->get_blend_shape_name(shape_i);  					NodePath shape_path = String(path) + ":" + shape_name; -					int32_t shape_track_i = animation->find_track(shape_path); +					int32_t shape_track_i = animation->find_track(shape_path, Animation::TYPE_BLEND_SHAPE);  					if (shape_track_i == -1) {  						GLTFAnimation::Channel<float> weight;  						weight.interpolation = GLTFAnimation::INTERP_LINEAR; diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index fbc3767151..e3744ad5e9 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -178,32 +178,32 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const {  }  void Skeleton3D::_validate_property(PropertyInfo &property) const { -	PackedStringArray spr = property.name.split("/"); -	if (spr.size() == 3 && spr[0] == "bones") { -		if (spr[2] == "rest") { +	PackedStringArray split = property.name.split("/"); +	if (split.size() == 3 && split[0] == "bones") { +		if (split[2] == "rest") {  			property.usage |= PROPERTY_USAGE_READ_ONLY;  		}  		if (is_show_rest_only()) { -			if (spr[2] == "enabled") { +			if (split[2] == "enabled") {  				property.usage |= PROPERTY_USAGE_READ_ONLY;  			} -			if (spr[2] == "position") { +			if (split[2] == "position") {  				property.usage |= PROPERTY_USAGE_READ_ONLY;  			} -			if (spr[2] == "rotation") { +			if (split[2] == "rotation") {  				property.usage |= PROPERTY_USAGE_READ_ONLY;  			} -			if (spr[2] == "scale") { +			if (split[2] == "scale") {  				property.usage |= PROPERTY_USAGE_READ_ONLY;  			} -		} else if (!is_bone_enabled(spr[1].to_int())) { -			if (spr[2] == "position") { +		} else if (!is_bone_enabled(split[1].to_int())) { +			if (split[2] == "position") {  				property.usage |= PROPERTY_USAGE_READ_ONLY;  			} -			if (spr[2] == "rotation") { +			if (split[2] == "rotation") {  				property.usage |= PROPERTY_USAGE_READ_ONLY;  			} -			if (spr[2] == "scale") { +			if (split[2] == "scale") {  				property.usage |= PROPERTY_USAGE_READ_ONLY;  			}  		} diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 08b78a39b1..55d58bf156 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -837,9 +837,9 @@ NodePath Animation::track_get_path(int p_track) const {  	return tracks[p_track]->path;  } -int Animation::find_track(const NodePath &p_path) const { +int Animation::find_track(const NodePath &p_path, const TrackType p_type) const {  	for (int i = 0; i < tracks.size(); i++) { -		if (tracks[i]->path == p_path) { +		if (tracks[i]->path == p_path && tracks[i]->type == p_type) {  			return i;  		}  	}; @@ -3027,7 +3027,7 @@ void Animation::_bind_methods() {  	ClassDB::bind_method(D_METHOD("track_get_type", "track_idx"), &Animation::track_get_type);  	ClassDB::bind_method(D_METHOD("track_get_path", "track_idx"), &Animation::track_get_path);  	ClassDB::bind_method(D_METHOD("track_set_path", "track_idx", "path"), &Animation::track_set_path); -	ClassDB::bind_method(D_METHOD("find_track", "path"), &Animation::find_track); +	ClassDB::bind_method(D_METHOD("find_track", "path", "type"), &Animation::find_track);  	ClassDB::bind_method(D_METHOD("track_move_up", "track_idx"), &Animation::track_move_up);  	ClassDB::bind_method(D_METHOD("track_move_down", "track_idx"), &Animation::track_move_down); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 4ee0741d87..6de739f737 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -281,8 +281,7 @@ public:  	void track_set_path(int p_track, const NodePath &p_path);  	NodePath track_get_path(int p_track) const; -	int find_track(const NodePath &p_path) const; -	// transform +	int find_track(const NodePath &p_path, const TrackType p_type) const;  	void track_move_up(int p_track);  	void track_move_down(int p_track);  |