Merge pull request #11973 from AndreaCatania/ragdoll
Ragdoll - Physical bone node
This commit is contained in:
commit
6d46f73ec3
20 changed files with 2269 additions and 22 deletions
|
@ -93,6 +93,7 @@
|
|||
#include "editor/plugins/particles_editor_plugin.h"
|
||||
#include "editor/plugins/path_2d_editor_plugin.h"
|
||||
#include "editor/plugins/path_editor_plugin.h"
|
||||
#include "editor/plugins/physical_bone_plugin.h"
|
||||
#include "editor/plugins/polygon_2d_editor_plugin.h"
|
||||
#include "editor/plugins/resource_preloader_editor_plugin.h"
|
||||
#include "editor/plugins/script_editor_plugin.h"
|
||||
|
@ -100,6 +101,7 @@
|
|||
#include "editor/plugins/shader_editor_plugin.h"
|
||||
#include "editor/plugins/shader_graph_editor_plugin.h"
|
||||
#include "editor/plugins/skeleton_2d_editor_plugin.h"
|
||||
#include "editor/plugins/skeleton_editor_plugin.h"
|
||||
#include "editor/plugins/spatial_editor_plugin.h"
|
||||
#include "editor/plugins/sprite_editor_plugin.h"
|
||||
#include "editor/plugins/sprite_frames_editor_plugin.h"
|
||||
|
@ -5881,6 +5883,8 @@ EditorNode::EditorNode() {
|
|||
add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor)));
|
||||
add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor)));
|
||||
add_editor_plugin(memnew(NavigationMeshEditorPlugin(this)));
|
||||
add_editor_plugin(memnew(SkeletonEditorPlugin(this)));
|
||||
add_editor_plugin(memnew(PhysicalBonePlugin(this)));
|
||||
|
||||
// FIXME: Disabled as (according to reduz) users were complaining that it gets in the way
|
||||
// Waiting for PropertyEditor rewrite (planned for 3.1) to be refactored.
|
||||
|
|
77
editor/icons/icon_physical_bone.svg
Normal file
77
editor/icons/icon_physical_bone.svg
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 16"
|
||||
id="svg2"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="icon_physical_bone.svg">
|
||||
<metadata
|
||||
id="metadata12">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1027"
|
||||
id="namedview8"
|
||||
showgrid="false"
|
||||
inkscape:zoom="16"
|
||||
inkscape:cx="14.674088"
|
||||
inkscape:cy="7.3239349"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" />
|
||||
<g
|
||||
id="g4505"
|
||||
transform="translate(-2.5625,-18.4375)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6-9-8"
|
||||
d="m 13.107422,19.382812 a 2.4664,2.4663 0 0 0 -1.78125,0.720704 2.4664,2.4663 0 0 0 -0.185547,0.21289 L 12.472656,22.75 10.867187,23.353516 7.453125,26.767578 a 2.4664,2.4663 0 0 0 -3.1015625,0.3125 2.4664,2.4663 0 0 0 0,3.488281 2.4664,2.4663 0 0 0 1.3964844,0.695313 2.4664,2.4663 0 0 0 0.6953125,1.396484 2.4664,2.4663 0 0 0 3.4882812,0 2.4664,2.4663 0 0 0 0.3144534,-3.103515 l 3.560547,-3.560547 a 2.4664,2.4663 0 0 0 3.099609,-0.310547 2.4664,2.4663 0 0 0 0,-3.488281 A 2.4664,2.4663 0 0 0 15.509766,21.5 2.4664,2.4663 0 0 0 14.814453,20.103516 2.4664,2.4663 0 0 0 13.107422,19.382812 Z"
|
||||
style="fill:#fc9c9c" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
id="rect4140-5-1-4-3-7-9-03"
|
||||
d="m 3.7211033,21.208326 0.9608286,4.82644 1.3962404,-0.524494 z"
|
||||
style="opacity:1;fill:#fc9c9c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42799997;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
id="rect4140-5-1-4-3-7-9-5-3"
|
||||
d="m 6.4843278,19.465234 0.9608285,4.82644 1.3962404,-0.524494 z"
|
||||
style="opacity:1;fill:#fc9c9c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42799997;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
id="rect4140-5-1-4-3-7-9-5-3-8"
|
||||
d="m 9.6964655,19.33678 0.7108285,3.51394 1.39624,-0.524494 z"
|
||||
style="opacity:1;fill:#fc9c9c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42799997;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.4 KiB |
123
editor/plugins/physical_bone_plugin.cpp
Normal file
123
editor/plugins/physical_bone_plugin.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*************************************************************************/
|
||||
/* physical_bone_plugin.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "physical_bone_plugin.h"
|
||||
#include "editor/plugins/spatial_editor_plugin.h"
|
||||
#include "scene/3d/physics_body.h"
|
||||
|
||||
void PhysicalBoneEditor::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("_on_toggle_button_transform_joint", "is_pressed"), &PhysicalBoneEditor::_on_toggle_button_transform_joint);
|
||||
}
|
||||
|
||||
void PhysicalBoneEditor::_on_toggle_button_transform_joint(bool p_is_pressed) {
|
||||
|
||||
_set_move_joint();
|
||||
}
|
||||
|
||||
void PhysicalBoneEditor::_set_move_joint() {
|
||||
if (selected) {
|
||||
selected->_set_gizmo_move_joint(button_transform_joint->is_pressed());
|
||||
}
|
||||
}
|
||||
|
||||
PhysicalBoneEditor::PhysicalBoneEditor(EditorNode *p_editor) :
|
||||
editor(p_editor),
|
||||
selected(NULL) {
|
||||
|
||||
spatial_editor_hb = memnew(HBoxContainer);
|
||||
spatial_editor_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
spatial_editor_hb->set_alignment(BoxContainer::ALIGN_BEGIN);
|
||||
SpatialEditor::get_singleton()->add_control_to_menu_panel(spatial_editor_hb);
|
||||
|
||||
spatial_editor_hb->add_child(memnew(VSeparator));
|
||||
|
||||
button_transform_joint = memnew(ToolButton);
|
||||
spatial_editor_hb->add_child(button_transform_joint);
|
||||
|
||||
button_transform_joint->set_text(TTR("Move joint"));
|
||||
button_transform_joint->set_icon(SpatialEditor::get_singleton()->get_icon("PhysicalBone", "EditorIcons"));
|
||||
button_transform_joint->set_toggle_mode(true);
|
||||
button_transform_joint->connect("toggled", this, "_on_toggle_button_transform_joint");
|
||||
|
||||
hide();
|
||||
}
|
||||
|
||||
PhysicalBoneEditor::~PhysicalBoneEditor() {
|
||||
// TODO the spatial_editor_hb should be removed from SpatialEditor, but in this moment it's not possible
|
||||
for (int i = spatial_editor_hb->get_child_count() - 1; 0 <= i; --i) {
|
||||
Node *n = spatial_editor_hb->get_child(i);
|
||||
spatial_editor_hb->remove_child(n);
|
||||
memdelete(n);
|
||||
}
|
||||
memdelete(spatial_editor_hb);
|
||||
}
|
||||
|
||||
void PhysicalBoneEditor::set_selected(PhysicalBone *p_pb) {
|
||||
|
||||
button_transform_joint->set_pressed(false);
|
||||
|
||||
_set_move_joint();
|
||||
selected = p_pb;
|
||||
_set_move_joint();
|
||||
}
|
||||
|
||||
void PhysicalBoneEditor::hide() {
|
||||
spatial_editor_hb->hide();
|
||||
}
|
||||
|
||||
void PhysicalBoneEditor::show() {
|
||||
spatial_editor_hb->show();
|
||||
}
|
||||
|
||||
PhysicalBonePlugin::PhysicalBonePlugin(EditorNode *p_editor) :
|
||||
editor(p_editor),
|
||||
selected(NULL) {
|
||||
|
||||
physical_bone_editor = memnew(PhysicalBoneEditor(editor));
|
||||
}
|
||||
|
||||
void PhysicalBonePlugin::make_visible(bool p_visible) {
|
||||
if (p_visible) {
|
||||
|
||||
physical_bone_editor->show();
|
||||
} else {
|
||||
|
||||
physical_bone_editor->hide();
|
||||
physical_bone_editor->set_selected(NULL);
|
||||
selected = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalBonePlugin::edit(Object *p_node) {
|
||||
selected = static_cast<PhysicalBone *>(p_node); // Trust it
|
||||
ERR_FAIL_COND(!selected);
|
||||
|
||||
physical_bone_editor->set_selected(selected);
|
||||
}
|
78
editor/plugins/physical_bone_plugin.h
Normal file
78
editor/plugins/physical_bone_plugin.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*************************************************************************/
|
||||
/* physical_bone_plugin.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef PHYSICAL_BONE_PLUGIN_H
|
||||
#define PHYSICAL_BONE_PLUGIN_H
|
||||
|
||||
#include "editor/editor_node.h"
|
||||
|
||||
class PhysicalBoneEditor : public Object {
|
||||
GDCLASS(PhysicalBoneEditor, Object);
|
||||
|
||||
EditorNode *editor;
|
||||
HBoxContainer *spatial_editor_hb;
|
||||
ToolButton *button_transform_joint;
|
||||
|
||||
PhysicalBone *selected;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
private:
|
||||
void _on_toggle_button_transform_joint(bool p_is_pressed);
|
||||
void _set_move_joint();
|
||||
|
||||
public:
|
||||
PhysicalBoneEditor(EditorNode *p_editor);
|
||||
~PhysicalBoneEditor();
|
||||
|
||||
void set_selected(PhysicalBone *p_pb);
|
||||
|
||||
void hide();
|
||||
void show();
|
||||
};
|
||||
|
||||
class PhysicalBonePlugin : public EditorPlugin {
|
||||
GDCLASS(PhysicalBonePlugin, EditorPlugin);
|
||||
|
||||
EditorNode *editor;
|
||||
PhysicalBone *selected;
|
||||
PhysicalBoneEditor *physical_bone_editor;
|
||||
|
||||
public:
|
||||
virtual String get_name() const { return "PhysicalBone"; }
|
||||
virtual bool handles(Object *p_object) const { return p_object->is_class("PhysicalBone"); }
|
||||
virtual void make_visible(bool p_visible);
|
||||
virtual void edit(Object *p_node);
|
||||
|
||||
PhysicalBonePlugin(EditorNode *p_editor);
|
||||
};
|
||||
|
||||
#endif
|
189
editor/plugins/skeleton_editor_plugin.cpp
Normal file
189
editor/plugins/skeleton_editor_plugin.cpp
Normal file
|
@ -0,0 +1,189 @@
|
|||
/*************************************************************************/
|
||||
/* skeleton_editor_plugin.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "skeleton_editor_plugin.h"
|
||||
#include "scene/3d/collision_shape.h"
|
||||
#include "scene/3d/physics_body.h"
|
||||
#include "scene/3d/physics_joint.h";
|
||||
#include "scene/resources/capsule_shape.h"
|
||||
#include "scene/resources/sphere_shape.h"
|
||||
#include "spatial_editor_plugin.h"
|
||||
|
||||
void SkeletonEditor::_on_click_option(int p_option) {
|
||||
if (!skeleton) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (p_option) {
|
||||
case MENU_OPTION_CREATE_PHYSICAL_SKELETON: {
|
||||
create_physical_skeleton();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonEditor::create_physical_skeleton() {
|
||||
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
|
||||
Node *owner = skeleton == get_tree()->get_edited_scene_root() ? skeleton : skeleton->get_owner();
|
||||
|
||||
const int bc = skeleton->get_bone_count();
|
||||
|
||||
if (!bc) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<BoneInfo> bones_infos;
|
||||
bones_infos.resize(bc);
|
||||
|
||||
for (int bone_id = 0; bc > bone_id; ++bone_id) {
|
||||
|
||||
const int parent = skeleton->get_bone_parent(bone_id);
|
||||
const int parent_parent = skeleton->get_bone_parent(parent);
|
||||
|
||||
if (parent < 0) {
|
||||
|
||||
bones_infos[bone_id].relative_rest = skeleton->get_bone_rest(bone_id);
|
||||
|
||||
} else {
|
||||
|
||||
bones_infos[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id);
|
||||
|
||||
/// create physical bone on parent
|
||||
if (!bones_infos[parent].physical_bone) {
|
||||
|
||||
bones_infos[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos);
|
||||
|
||||
ur->create_action(TTR("Create physical bones"));
|
||||
ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone);
|
||||
ur->add_do_reference(bones_infos[parent].physical_bone);
|
||||
ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone);
|
||||
ur->commit_action();
|
||||
|
||||
bones_infos[parent].physical_bone->set_bone_name(skeleton->get_bone_name(parent));
|
||||
bones_infos[parent].physical_bone->set_owner(owner);
|
||||
bones_infos[parent].physical_bone->get_child(0)->set_owner(owner); // set shape owner
|
||||
|
||||
/// Create joint between parent of parent
|
||||
if (-1 != parent_parent) {
|
||||
|
||||
bones_infos[parent].physical_bone->set_joint_type(PhysicalBone::JOINT_TYPE_PIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PhysicalBone *SkeletonEditor::create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos) {
|
||||
|
||||
real_t half_height(skeleton->get_bone_rest(bone_child_id).origin.length() * 0.5);
|
||||
real_t radius(half_height * 0.2);
|
||||
|
||||
CapsuleShape *bone_shape_capsule = memnew(CapsuleShape);
|
||||
bone_shape_capsule->set_height((half_height - radius) * 2);
|
||||
bone_shape_capsule->set_radius(radius);
|
||||
|
||||
CollisionShape *bone_shape = memnew(CollisionShape);
|
||||
bone_shape->set_shape(bone_shape_capsule);
|
||||
|
||||
Transform body_transform;
|
||||
body_transform.origin = Vector3(0, 0, -half_height);
|
||||
|
||||
Transform joint_transform;
|
||||
joint_transform.origin = Vector3(0, 0, half_height);
|
||||
|
||||
PhysicalBone *physical_bone = memnew(PhysicalBone);
|
||||
physical_bone->add_child(bone_shape);
|
||||
physical_bone->set_name("Physical Bone " + skeleton->get_bone_name(bone_id));
|
||||
physical_bone->set_body_offset(body_transform);
|
||||
physical_bone->set_joint_offset(joint_transform);
|
||||
return physical_bone;
|
||||
}
|
||||
|
||||
void SkeletonEditor::edit(Skeleton *p_node) {
|
||||
skeleton = p_node;
|
||||
}
|
||||
|
||||
void SkeletonEditor::_node_removed(Node *p_node) {
|
||||
|
||||
if (p_node == skeleton) {
|
||||
skeleton = NULL;
|
||||
options->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonEditor::_bind_methods() {
|
||||
ClassDB::bind_method("_on_click_option", &SkeletonEditor::_on_click_option);
|
||||
}
|
||||
|
||||
SkeletonEditor::SkeletonEditor() {
|
||||
options = memnew(MenuButton);
|
||||
SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
|
||||
|
||||
options->set_text(TTR("Skeleton"));
|
||||
options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Skeleton", "EditorIcons"));
|
||||
|
||||
options->get_popup()->add_item(TTR("Create physical skeleton"), MENU_OPTION_CREATE_PHYSICAL_SKELETON);
|
||||
|
||||
options->get_popup()->connect("id_pressed", this, "_on_click_option");
|
||||
options->hide();
|
||||
}
|
||||
|
||||
SkeletonEditor::~SkeletonEditor() {
|
||||
SpatialEditor::get_singleton()->remove_child(options);
|
||||
memdelete(options);
|
||||
}
|
||||
|
||||
void SkeletonEditorPlugin::edit(Object *p_object) {
|
||||
skeleton_editor->edit(Object::cast_to<Skeleton>(p_object));
|
||||
}
|
||||
|
||||
bool SkeletonEditorPlugin::handles(Object *p_object) const {
|
||||
return p_object->is_class("Skeleton");
|
||||
}
|
||||
|
||||
void SkeletonEditorPlugin::make_visible(bool p_visible) {
|
||||
if (p_visible) {
|
||||
skeleton_editor->options->show();
|
||||
} else {
|
||||
|
||||
skeleton_editor->options->hide();
|
||||
skeleton_editor->edit(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
SkeletonEditorPlugin::SkeletonEditorPlugin(EditorNode *p_node) {
|
||||
editor = p_node;
|
||||
skeleton_editor = memnew(SkeletonEditor);
|
||||
editor->get_viewport()->add_child(skeleton_editor);
|
||||
}
|
||||
|
||||
SkeletonEditorPlugin::~SkeletonEditorPlugin() {
|
||||
editor->get_viewport()->remove_child(skeleton_editor);
|
||||
memdelete(skeleton_editor);
|
||||
}
|
95
editor/plugins/skeleton_editor_plugin.h
Normal file
95
editor/plugins/skeleton_editor_plugin.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*************************************************************************/
|
||||
/* skeleton_editor_plugin.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef SKELETON_EDITOR_PLUGIN_H
|
||||
#define SKELETON_EDITOR_PLUGIN_H
|
||||
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_plugin.h"
|
||||
#include "scene/3d/skeleton.h"
|
||||
|
||||
class PhysicalBone;
|
||||
class Joint;
|
||||
|
||||
class SkeletonEditor : public Node {
|
||||
GDCLASS(SkeletonEditor, Node);
|
||||
|
||||
enum Menu {
|
||||
MENU_OPTION_CREATE_PHYSICAL_SKELETON
|
||||
};
|
||||
|
||||
struct BoneInfo {
|
||||
PhysicalBone *physical_bone;
|
||||
Transform relative_rest; // Relative to skeleton node
|
||||
BoneInfo() :
|
||||
physical_bone(NULL) {}
|
||||
};
|
||||
|
||||
Skeleton *skeleton;
|
||||
|
||||
MenuButton *options;
|
||||
|
||||
void _on_click_option(int p_option);
|
||||
|
||||
friend class SkeletonEditorPlugin;
|
||||
|
||||
protected:
|
||||
void _node_removed(Node *p_node);
|
||||
static void _bind_methods();
|
||||
|
||||
void create_physical_skeleton();
|
||||
PhysicalBone *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos);
|
||||
|
||||
public:
|
||||
void edit(Skeleton *p_mesh);
|
||||
|
||||
SkeletonEditor();
|
||||
~SkeletonEditor();
|
||||
};
|
||||
|
||||
class SkeletonEditorPlugin : public EditorPlugin {
|
||||
|
||||
GDCLASS(SkeletonEditorPlugin, EditorPlugin);
|
||||
|
||||
EditorNode *editor;
|
||||
SkeletonEditor *skeleton_editor;
|
||||
|
||||
public:
|
||||
virtual String get_name() const { return "Skeleton"; }
|
||||
virtual bool has_main_screen() const { return false; }
|
||||
virtual void edit(Object *p_object);
|
||||
virtual bool handles(Object *p_object) const;
|
||||
virtual void make_visible(bool p_visible);
|
||||
|
||||
SkeletonEditorPlugin(EditorNode *p_node);
|
||||
~SkeletonEditorPlugin();
|
||||
};
|
||||
|
||||
#endif // SKELETON_EDITOR_PLUGIN_H
|
|
@ -72,6 +72,14 @@
|
|||
#define MIN_FOV 0.01
|
||||
#define MAX_FOV 179
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#define get_global_gizmo_transform get_global_gizmo_transform
|
||||
#define get_local_gizmo_transform get_local_gizmo_transform
|
||||
#else
|
||||
#define get_global_gizmo_transform get_global_transform
|
||||
#define get_local_gizmo_transform get_transform
|
||||
#endif
|
||||
|
||||
void SpatialEditorViewport::_update_camera(float p_interp_delta) {
|
||||
|
||||
bool is_orthogonal = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL;
|
||||
|
@ -584,8 +592,8 @@ void SpatialEditorViewport::_compute_edit(const Point2 &p_point) {
|
|||
if (!se)
|
||||
continue;
|
||||
|
||||
se->original = se->sp->get_global_transform();
|
||||
se->original_local = se->sp->get_transform();
|
||||
se->original = se->sp->get_global_gizmo_transform();
|
||||
se->original_local = se->sp->get_local_gizmo_transform();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1184,7 +1192,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
|||
if (!se)
|
||||
continue;
|
||||
|
||||
undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_transform());
|
||||
undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
|
||||
undo_redo->add_undo_method(sp, "set_global_transform", se->original);
|
||||
}
|
||||
undo_redo->commit_action();
|
||||
|
@ -2150,7 +2158,7 @@ void SpatialEditorViewport::_notification(int p_what) {
|
|||
se->aabb = vi ? vi->get_aabb() : AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
|
||||
}
|
||||
|
||||
Transform t = sp->get_global_transform();
|
||||
Transform t = sp->get_global_gizmo_transform();
|
||||
t.translate(se->aabb.position);
|
||||
|
||||
// apply AABB scaling before item's global transform
|
||||
|
@ -2503,7 +2511,7 @@ void SpatialEditorViewport::_menu_option(int p_option) {
|
|||
xform.scale_basis(sp->get_scale());
|
||||
|
||||
undo_redo->add_do_method(sp, "set_global_transform", xform);
|
||||
undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform());
|
||||
undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
|
||||
}
|
||||
undo_redo->commit_action();
|
||||
} break;
|
||||
|
@ -2961,7 +2969,7 @@ void SpatialEditorViewport::focus_selection() {
|
|||
if (!se)
|
||||
continue;
|
||||
|
||||
center += sp->get_global_transform().origin;
|
||||
center += sp->get_global_gizmo_transform().origin;
|
||||
count++;
|
||||
}
|
||||
|
||||
|
@ -3043,7 +3051,7 @@ AABB SpatialEditorViewport::_calculate_spatial_bounds(const Spatial *p_parent, c
|
|||
MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(child);
|
||||
if (mesh_instance) {
|
||||
AABB mesh_instance_bounds = mesh_instance->get_aabb();
|
||||
mesh_instance_bounds.position += mesh_instance->get_global_transform().origin - p_parent->get_global_transform().origin;
|
||||
mesh_instance_bounds.position += mesh_instance->get_global_gizmo_transform().origin - p_parent->get_global_gizmo_transform().origin;
|
||||
bounds.merge_with(mesh_instance_bounds);
|
||||
}
|
||||
bounds = _calculate_spatial_bounds(child, bounds);
|
||||
|
@ -3154,7 +3162,7 @@ bool SpatialEditorViewport::_create_instance(Node *parent, String &path, const P
|
|||
Transform global_transform;
|
||||
Spatial *parent_spatial = Object::cast_to<Spatial>(parent);
|
||||
if (parent_spatial)
|
||||
global_transform = parent_spatial->get_global_transform();
|
||||
global_transform = parent_spatial->get_global_gizmo_transform();
|
||||
|
||||
global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point));
|
||||
|
||||
|
@ -3787,7 +3795,8 @@ void SpatialEditor::update_transform_gizmo() {
|
|||
if (!se)
|
||||
continue;
|
||||
|
||||
Transform xf = se->sp->get_global_transform();
|
||||
Transform xf = se->sp->get_global_gizmo_transform();
|
||||
|
||||
if (first) {
|
||||
center.position = xf.origin;
|
||||
first = false;
|
||||
|
@ -4054,7 +4063,7 @@ void SpatialEditor::_xform_dialog_action() {
|
|||
|
||||
bool post = xform_type->get_selected() > 0;
|
||||
|
||||
Transform tr = sp->get_global_transform();
|
||||
Transform tr = sp->get_global_gizmo_transform();
|
||||
if (post)
|
||||
tr = tr * t;
|
||||
else {
|
||||
|
@ -4064,7 +4073,7 @@ void SpatialEditor::_xform_dialog_action() {
|
|||
}
|
||||
|
||||
undo_redo->add_do_method(sp, "set_global_transform", tr);
|
||||
undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform());
|
||||
undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
|
||||
}
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
|
|
@ -1534,6 +1534,120 @@ SkeletonSpatialGizmo::SkeletonSpatialGizmo(Skeleton *p_skel) {
|
|||
set_spatial_node(p_skel);
|
||||
}
|
||||
|
||||
PhysicalBoneSpatialGizmo::PhysicalBoneSpatialGizmo(PhysicalBone *p_pb) :
|
||||
EditorSpatialGizmo(),
|
||||
physical_bone(p_pb) {
|
||||
set_spatial_node(p_pb);
|
||||
}
|
||||
|
||||
void PhysicalBoneSpatialGizmo::redraw() {
|
||||
|
||||
clear();
|
||||
|
||||
if (!physical_bone)
|
||||
return;
|
||||
|
||||
Skeleton *sk(physical_bone->find_skeleton_parent());
|
||||
PhysicalBone *pb(sk->get_physical_bone(physical_bone->get_bone_id()));
|
||||
PhysicalBone *pbp(sk->get_physical_bone_parent(physical_bone->get_bone_id()));
|
||||
|
||||
Vector<Vector3> points;
|
||||
|
||||
switch (physical_bone->get_joint_type()) {
|
||||
case PhysicalBone::JOINT_TYPE_PIN: {
|
||||
|
||||
PinJointSpatialGizmo::CreateGizmo(physical_bone->get_joint_offset(), points);
|
||||
} break;
|
||||
case PhysicalBone::JOINT_TYPE_CONE: {
|
||||
|
||||
const PhysicalBone::ConeJointData *cjd(static_cast<const PhysicalBone::ConeJointData *>(physical_bone->get_joint_data()));
|
||||
ConeTwistJointSpatialGizmo::CreateGizmo(
|
||||
physical_bone->get_joint_offset(),
|
||||
physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
|
||||
pb ? pb->get_global_transform() : Transform(),
|
||||
pbp ? pbp->get_global_transform() : Transform(),
|
||||
cjd->swing_span,
|
||||
cjd->twist_span,
|
||||
points,
|
||||
pb ? &points : NULL,
|
||||
pbp ? &points : NULL);
|
||||
} break;
|
||||
case PhysicalBone::JOINT_TYPE_HINGE: {
|
||||
|
||||
const PhysicalBone::HingeJointData *hjd(static_cast<const PhysicalBone::HingeJointData *>(physical_bone->get_joint_data()));
|
||||
HingeJointSpatialGizmo::CreateGizmo(
|
||||
physical_bone->get_joint_offset(),
|
||||
physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
|
||||
pb ? pb->get_global_transform() : Transform(),
|
||||
pbp ? pbp->get_global_transform() : Transform(),
|
||||
hjd->angular_limit_lower,
|
||||
hjd->angular_limit_upper,
|
||||
hjd->angular_limit_enabled,
|
||||
points,
|
||||
pb ? &points : NULL,
|
||||
pbp ? &points : NULL);
|
||||
} break;
|
||||
case PhysicalBone::JOINT_TYPE_SLIDER: {
|
||||
|
||||
const PhysicalBone::SliderJointData *sjd(static_cast<const PhysicalBone::SliderJointData *>(physical_bone->get_joint_data()));
|
||||
SliderJointSpatialGizmo::CreateGizmo(
|
||||
physical_bone->get_joint_offset(),
|
||||
physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
|
||||
pb ? pb->get_global_transform() : Transform(),
|
||||
pbp ? pbp->get_global_transform() : Transform(),
|
||||
sjd->angular_limit_lower,
|
||||
sjd->angular_limit_upper,
|
||||
sjd->linear_limit_lower,
|
||||
sjd->linear_limit_upper,
|
||||
points,
|
||||
pb ? &points : NULL,
|
||||
pbp ? &points : NULL);
|
||||
} break;
|
||||
case PhysicalBone::JOINT_TYPE_6DOF: {
|
||||
|
||||
const PhysicalBone::SixDOFJointData *sdofjd(static_cast<const PhysicalBone::SixDOFJointData *>(physical_bone->get_joint_data()));
|
||||
Generic6DOFJointSpatialGizmo::CreateGizmo(
|
||||
physical_bone->get_joint_offset(),
|
||||
|
||||
physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
|
||||
pb ? pb->get_global_transform() : Transform(),
|
||||
pbp ? pbp->get_global_transform() : Transform(),
|
||||
|
||||
sdofjd->axis_data[0].angular_limit_lower,
|
||||
sdofjd->axis_data[0].angular_limit_upper,
|
||||
sdofjd->axis_data[0].linear_limit_lower,
|
||||
sdofjd->axis_data[0].linear_limit_upper,
|
||||
sdofjd->axis_data[0].angular_limit_enabled,
|
||||
sdofjd->axis_data[0].linear_limit_enabled,
|
||||
|
||||
sdofjd->axis_data[1].angular_limit_lower,
|
||||
sdofjd->axis_data[1].angular_limit_upper,
|
||||
sdofjd->axis_data[1].linear_limit_lower,
|
||||
sdofjd->axis_data[1].linear_limit_upper,
|
||||
sdofjd->axis_data[1].angular_limit_enabled,
|
||||
sdofjd->axis_data[1].linear_limit_enabled,
|
||||
|
||||
sdofjd->axis_data[2].angular_limit_lower,
|
||||
sdofjd->axis_data[2].angular_limit_upper,
|
||||
sdofjd->axis_data[2].linear_limit_lower,
|
||||
sdofjd->axis_data[2].linear_limit_upper,
|
||||
sdofjd->axis_data[2].angular_limit_enabled,
|
||||
sdofjd->axis_data[2].linear_limit_enabled,
|
||||
|
||||
points,
|
||||
pb ? &points : NULL,
|
||||
pbp ? &points : NULL);
|
||||
} break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
|
||||
|
||||
add_collision_segments(points);
|
||||
add_lines(points, material);
|
||||
}
|
||||
|
||||
// FIXME: Kept as reference for reimplementation in 3.1+
|
||||
#if 0
|
||||
void RoomSpatialGizmo::redraw() {
|
||||
|
@ -3735,6 +3849,12 @@ Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) {
|
|||
return lsg;
|
||||
}
|
||||
|
||||
if (Object::cast_to<PhysicalBone>(p_spatial)) {
|
||||
|
||||
Ref<PhysicalBoneSpatialGizmo> pbsg = memnew(PhysicalBoneSpatialGizmo(Object::cast_to<PhysicalBone>(p_spatial)));
|
||||
return pbsg;
|
||||
}
|
||||
|
||||
if (Object::cast_to<Position3D>(p_spatial)) {
|
||||
|
||||
Ref<Position3DSpatialGizmo> lsg = memnew(Position3DSpatialGizmo(Object::cast_to<Position3D>(p_spatial)));
|
||||
|
|
|
@ -214,6 +214,17 @@ public:
|
|||
SkeletonSpatialGizmo(Skeleton *p_skel = NULL);
|
||||
};
|
||||
|
||||
class PhysicalBoneSpatialGizmo : public EditorSpatialGizmo {
|
||||
GDCLASS(PhysicalBoneSpatialGizmo, EditorSpatialGizmo);
|
||||
|
||||
PhysicalBone *physical_bone;
|
||||
|
||||
public:
|
||||
//virtual Transform get_global_gizmo_transform();
|
||||
virtual void redraw();
|
||||
PhysicalBoneSpatialGizmo(PhysicalBone *p_pb = NULL);
|
||||
};
|
||||
|
||||
#if 0
|
||||
class PortalSpatialGizmo : public EditorSpatialGizmo {
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *prox
|
|||
if (gObj->getType() == CollisionObjectBullet::TYPE_AREA)
|
||||
return false;
|
||||
|
||||
if (m_self_object->has_collision_exception(gObj))
|
||||
if (m_self_object->has_collision_exception(gObj) || gObj->has_collision_exception(m_self_object))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "scene/3d/collision_object.h"
|
||||
#include "servers/physics_server.h"
|
||||
#include "skeleton.h"
|
||||
#include "vset.h"
|
||||
|
||||
class PhysicsBody : public CollisionObject {
|
||||
|
@ -342,4 +343,267 @@ public:
|
|||
KinematicCollision();
|
||||
};
|
||||
|
||||
class PhysicalBone : public PhysicsBody {
|
||||
|
||||
GDCLASS(PhysicalBone, PhysicsBody);
|
||||
|
||||
public:
|
||||
enum JointType {
|
||||
JOINT_TYPE_NONE,
|
||||
JOINT_TYPE_PIN,
|
||||
JOINT_TYPE_CONE,
|
||||
JOINT_TYPE_HINGE,
|
||||
JOINT_TYPE_SLIDER,
|
||||
JOINT_TYPE_6DOF
|
||||
};
|
||||
|
||||
struct JointData {
|
||||
virtual JointType get_joint_type() { return JOINT_TYPE_NONE; }
|
||||
|
||||
/// "j" is used to set the parameter inside the PhysicsServer
|
||||
virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
|
||||
virtual bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
virtual void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
};
|
||||
|
||||
struct PinJointData : public JointData {
|
||||
virtual JointType get_joint_type() { return JOINT_TYPE_PIN; }
|
||||
|
||||
virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
|
||||
virtual bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
virtual void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
|
||||
real_t bias;
|
||||
real_t damping;
|
||||
real_t impulse_clamp;
|
||||
|
||||
PinJointData() :
|
||||
bias(0.3),
|
||||
damping(1.),
|
||||
impulse_clamp(0) {}
|
||||
};
|
||||
|
||||
struct ConeJointData : public JointData {
|
||||
virtual JointType get_joint_type() { return JOINT_TYPE_CONE; }
|
||||
|
||||
virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
|
||||
virtual bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
virtual void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
|
||||
real_t swing_span;
|
||||
real_t twist_span;
|
||||
real_t bias;
|
||||
real_t softness;
|
||||
real_t relaxation;
|
||||
|
||||
ConeJointData() :
|
||||
swing_span(Math_PI * 0.25),
|
||||
twist_span(Math_PI),
|
||||
bias(0.3),
|
||||
softness(0.8),
|
||||
relaxation(1.) {}
|
||||
};
|
||||
|
||||
struct HingeJointData : public JointData {
|
||||
virtual JointType get_joint_type() { return JOINT_TYPE_HINGE; }
|
||||
|
||||
virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
|
||||
virtual bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
virtual void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
|
||||
bool angular_limit_enabled;
|
||||
real_t angular_limit_upper;
|
||||
real_t angular_limit_lower;
|
||||
real_t angular_limit_bias;
|
||||
real_t angular_limit_softness;
|
||||
real_t angular_limit_relaxation;
|
||||
|
||||
HingeJointData() :
|
||||
angular_limit_enabled(false),
|
||||
angular_limit_upper(Math_PI * 0.5),
|
||||
angular_limit_lower(-Math_PI * 0.5),
|
||||
angular_limit_bias(0.3),
|
||||
angular_limit_softness(0.9),
|
||||
angular_limit_relaxation(1.) {}
|
||||
};
|
||||
|
||||
struct SliderJointData : public JointData {
|
||||
virtual JointType get_joint_type() { return JOINT_TYPE_SLIDER; }
|
||||
|
||||
virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
|
||||
virtual bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
virtual void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
|
||||
real_t linear_limit_upper;
|
||||
real_t linear_limit_lower;
|
||||
real_t linear_limit_softness;
|
||||
real_t linear_limit_restitution;
|
||||
real_t linear_limit_damping;
|
||||
real_t angular_limit_upper;
|
||||
real_t angular_limit_lower;
|
||||
real_t angular_limit_softness;
|
||||
real_t angular_limit_restitution;
|
||||
real_t angular_limit_damping;
|
||||
|
||||
SliderJointData() :
|
||||
linear_limit_upper(1.),
|
||||
linear_limit_lower(-1.),
|
||||
linear_limit_softness(1.),
|
||||
linear_limit_restitution(0.7),
|
||||
linear_limit_damping(1.),
|
||||
angular_limit_upper(0),
|
||||
angular_limit_lower(0),
|
||||
angular_limit_softness(1.),
|
||||
angular_limit_restitution(0.7),
|
||||
angular_limit_damping(1.) {}
|
||||
};
|
||||
|
||||
struct SixDOFJointData : public JointData {
|
||||
struct SixDOFAxisData {
|
||||
bool linear_limit_enabled;
|
||||
real_t linear_limit_upper;
|
||||
real_t linear_limit_lower;
|
||||
real_t linear_limit_softness;
|
||||
real_t linear_restitution;
|
||||
real_t linear_damping;
|
||||
bool angular_limit_enabled;
|
||||
real_t angular_limit_upper;
|
||||
real_t angular_limit_lower;
|
||||
real_t angular_limit_softness;
|
||||
real_t angular_restitution;
|
||||
real_t angular_damping;
|
||||
real_t erp;
|
||||
|
||||
SixDOFAxisData() :
|
||||
linear_limit_enabled(true),
|
||||
linear_limit_upper(0),
|
||||
linear_limit_lower(0),
|
||||
linear_limit_softness(0.7),
|
||||
linear_restitution(0.5),
|
||||
linear_damping(1.),
|
||||
angular_limit_enabled(true),
|
||||
angular_limit_upper(0),
|
||||
angular_limit_lower(0),
|
||||
angular_limit_softness(0.5),
|
||||
angular_restitution(0),
|
||||
angular_damping(1.),
|
||||
erp(0.5) {}
|
||||
};
|
||||
|
||||
virtual JointType get_joint_type() { return JOINT_TYPE_6DOF; }
|
||||
|
||||
virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
|
||||
virtual bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
virtual void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
|
||||
SixDOFAxisData axis_data[3];
|
||||
|
||||
SixDOFJointData() {}
|
||||
};
|
||||
|
||||
private:
|
||||
#ifdef TOOLS_ENABLED
|
||||
// if false gizmo move body
|
||||
bool gizmo_move_joint;
|
||||
#endif
|
||||
|
||||
JointData *joint_data;
|
||||
Transform joint_offset;
|
||||
RID joint;
|
||||
|
||||
Skeleton *parent_skeleton;
|
||||
Transform body_offset;
|
||||
Transform body_offset_inverse;
|
||||
bool static_body;
|
||||
bool _internal_static_body;
|
||||
bool simulate_physics;
|
||||
bool _internal_simulate_physics;
|
||||
int bone_id;
|
||||
|
||||
String bone_name;
|
||||
real_t bounce;
|
||||
real_t mass;
|
||||
real_t friction;
|
||||
real_t gravity_scale;
|
||||
|
||||
protected:
|
||||
bool _set(const StringName &p_name, const Variant &p_value);
|
||||
bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
void _notification(int p_what);
|
||||
void _direct_state_changed(Object *p_state);
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
private:
|
||||
static Skeleton *find_skeleton_parent(Node *p_parent);
|
||||
void _fix_joint_offset();
|
||||
void _reload_joint();
|
||||
|
||||
public:
|
||||
void _on_bone_parent_changed();
|
||||
void _set_gizmo_move_joint(bool p_move_joint);
|
||||
|
||||
public:
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual Transform get_global_gizmo_transform() const;
|
||||
virtual Transform get_local_gizmo_transform() const;
|
||||
#endif
|
||||
|
||||
const JointData *get_joint_data() const;
|
||||
Skeleton *find_skeleton_parent();
|
||||
|
||||
int get_bone_id() const { return bone_id; }
|
||||
|
||||
void set_joint_type(JointType p_joint_type);
|
||||
JointType get_joint_type() const;
|
||||
|
||||
void set_joint_offset(const Transform &p_offset);
|
||||
const Transform &get_joint_offset() const;
|
||||
|
||||
void set_body_offset(const Transform &p_offset);
|
||||
const Transform &get_body_offset() const;
|
||||
|
||||
void set_static_body(bool p_static);
|
||||
bool is_static_body();
|
||||
|
||||
void set_simulate_physics(bool p_simulate);
|
||||
bool get_simulate_physics();
|
||||
bool is_simulating_physics();
|
||||
|
||||
void set_bone_name(const String &p_name);
|
||||
const String &get_bone_name() const;
|
||||
|
||||
void set_mass(real_t p_mass);
|
||||
real_t get_mass() const;
|
||||
|
||||
void set_weight(real_t p_weight);
|
||||
real_t get_weight() const;
|
||||
|
||||
void set_friction(real_t p_friction);
|
||||
real_t get_friction() const;
|
||||
|
||||
void set_bounce(real_t p_bounce);
|
||||
real_t get_bounce() const;
|
||||
|
||||
void set_gravity_scale(real_t p_gravity_scale);
|
||||
real_t get_gravity_scale() const;
|
||||
|
||||
PhysicalBone();
|
||||
~PhysicalBone();
|
||||
|
||||
private:
|
||||
void update_bone_id();
|
||||
void update_offset();
|
||||
void reset_to_rest_position();
|
||||
|
||||
void _reset_physics_simulation_state();
|
||||
void _reset_staticness_state();
|
||||
|
||||
void _start_physics_simulation();
|
||||
void _stop_physics_simulation();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(PhysicalBone::JointType);
|
||||
|
||||
#endif // PHYSICS_BODY__H
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "message_queue.h"
|
||||
|
||||
#include "core/project_settings.h"
|
||||
#include "scene/3d/physics_body.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
bool Skeleton::_set(const StringName &p_path, const Variant &p_value) {
|
||||
|
@ -377,6 +378,17 @@ void Skeleton::unparent_bone_and_rest(int p_bone) {
|
|||
_make_dirty();
|
||||
}
|
||||
|
||||
void Skeleton::set_bone_ignore_animation(int p_bone, bool p_ignore) {
|
||||
ERR_FAIL_INDEX(p_bone, bones.size());
|
||||
bones[p_bone].ignore_animation = p_ignore;
|
||||
}
|
||||
|
||||
bool Skeleton::is_bone_ignore_animation(int p_bone) const {
|
||||
|
||||
ERR_FAIL_INDEX_V(p_bone, bones.size(), false);
|
||||
return bones[p_bone].ignore_animation;
|
||||
}
|
||||
|
||||
void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) {
|
||||
|
||||
ERR_FAIL_INDEX(p_bone, bones.size());
|
||||
|
@ -522,6 +534,103 @@ void Skeleton::localize_rests() {
|
|||
}
|
||||
}
|
||||
|
||||
void _notify_physical_bones_simulation(bool start, Node *p_node) {
|
||||
|
||||
for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
|
||||
_notify_physical_bones_simulation(start, p_node->get_child(i));
|
||||
}
|
||||
|
||||
PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
|
||||
if (pb) {
|
||||
pb->set_simulate_physics(start);
|
||||
}
|
||||
}
|
||||
|
||||
void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone) {
|
||||
ERR_FAIL_INDEX(p_bone, bones.size());
|
||||
ERR_FAIL_COND(bones[p_bone].physical_bone);
|
||||
ERR_FAIL_COND(!p_physical_bone);
|
||||
bones[p_bone].physical_bone = p_physical_bone;
|
||||
|
||||
_rebuild_physical_bones_cache();
|
||||
}
|
||||
|
||||
void Skeleton::unbind_physical_bone_from_bone(int p_bone) {
|
||||
ERR_FAIL_INDEX(p_bone, bones.size());
|
||||
bones[p_bone].physical_bone = NULL;
|
||||
|
||||
_rebuild_physical_bones_cache();
|
||||
}
|
||||
|
||||
PhysicalBone *Skeleton::get_physical_bone(int p_bone) {
|
||||
ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL);
|
||||
|
||||
return bones[p_bone].physical_bone;
|
||||
}
|
||||
|
||||
PhysicalBone *Skeleton::get_physical_bone_parent(int p_bone) {
|
||||
ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL);
|
||||
|
||||
if (bones[p_bone].cache_parent_physical_bone) {
|
||||
return bones[p_bone].cache_parent_physical_bone;
|
||||
}
|
||||
|
||||
return _get_physical_bone_parent(p_bone);
|
||||
}
|
||||
|
||||
PhysicalBone *Skeleton::_get_physical_bone_parent(int p_bone) {
|
||||
ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL);
|
||||
|
||||
const int parent_bone = bones[p_bone].parent;
|
||||
if (0 > parent_bone) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PhysicalBone *pb = bones[parent_bone].physical_bone;
|
||||
if (pb) {
|
||||
return pb;
|
||||
} else {
|
||||
return get_physical_bone_parent(parent_bone);
|
||||
}
|
||||
}
|
||||
|
||||
void Skeleton::_rebuild_physical_bones_cache() {
|
||||
const int b_size = bones.size();
|
||||
for (int i = 0; i < b_size; ++i) {
|
||||
bones[i].cache_parent_physical_bone = _get_physical_bone_parent(i);
|
||||
if (bones[i].physical_bone)
|
||||
bones[i].physical_bone->_on_bone_parent_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void Skeleton::physical_bones_simulation(bool start) {
|
||||
_notify_physical_bones_simulation(start, this);
|
||||
}
|
||||
|
||||
void _physical_bones_add_remove_collision_exception(bool p_add, Node *p_node, RID p_exception) {
|
||||
|
||||
for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
|
||||
_physical_bones_add_remove_collision_exception(p_add, p_node->get_child(i), p_exception);
|
||||
}
|
||||
|
||||
CollisionObject *co = Object::cast_to<CollisionObject>(p_node);
|
||||
if (co) {
|
||||
if (p_add) {
|
||||
PhysicsServer::get_singleton()->body_add_collision_exception(co->get_rid(), p_exception);
|
||||
} else {
|
||||
PhysicsServer::get_singleton()->body_remove_collision_exception(co->get_rid(), p_exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Skeleton::physical_bones_add_collision_exception(RID p_exception) {
|
||||
_physical_bones_add_remove_collision_exception(true, this, p_exception);
|
||||
}
|
||||
|
||||
void Skeleton::physical_bones_remove_collision_exception(RID p_exception) {
|
||||
_physical_bones_add_remove_collision_exception(false, this, p_exception);
|
||||
}
|
||||
|
||||
void Skeleton::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton::add_bone);
|
||||
|
@ -558,6 +667,10 @@ void Skeleton::_bind_methods() {
|
|||
|
||||
ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("physical_bones_simulation", "start"), &Skeleton::physical_bones_simulation);
|
||||
ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton::physical_bones_add_collision_exception);
|
||||
ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton::physical_bones_remove_collision_exception);
|
||||
|
||||
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
|
||||
class PhysicalBone;
|
||||
class Skeleton : public Spatial {
|
||||
|
||||
GDCLASS(Skeleton, Spatial);
|
||||
|
@ -48,6 +50,8 @@ class Skeleton : public Spatial {
|
|||
bool enabled;
|
||||
int parent;
|
||||
|
||||
bool ignore_animation;
|
||||
|
||||
bool disable_rest;
|
||||
Transform rest;
|
||||
Transform rest_global_inverse;
|
||||
|
@ -60,13 +64,19 @@ class Skeleton : public Spatial {
|
|||
|
||||
Transform transform_final;
|
||||
|
||||
PhysicalBone *physical_bone;
|
||||
PhysicalBone *cache_parent_physical_bone;
|
||||
|
||||
List<uint32_t> nodes_bound;
|
||||
|
||||
Bone() {
|
||||
parent = -1;
|
||||
enabled = true;
|
||||
ignore_animation = false;
|
||||
custom_pose_enable = false;
|
||||
disable_rest = false;
|
||||
physical_bone = NULL;
|
||||
cache_parent_physical_bone = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -118,6 +128,9 @@ public:
|
|||
|
||||
void unparent_bone_and_rest(int p_bone);
|
||||
|
||||
void set_bone_ignore_animation(int p_bone, bool p_ignore);
|
||||
bool is_bone_ignore_animation(int p_bone) const;
|
||||
|
||||
void set_bone_disable_rest(int p_bone, bool p_disable);
|
||||
bool is_bone_rest_disabled(int p_bone) const;
|
||||
|
||||
|
@ -149,6 +162,25 @@ public:
|
|||
|
||||
void localize_rests(); // used for loaders and tools
|
||||
|
||||
// Physical bone API
|
||||
|
||||
void bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone);
|
||||
void unbind_physical_bone_from_bone(int p_bone);
|
||||
|
||||
PhysicalBone *get_physical_bone(int p_bone);
|
||||
PhysicalBone *get_physical_bone_parent(int p_bone);
|
||||
|
||||
private:
|
||||
/// This is a slow API os it's cached
|
||||
PhysicalBone *_get_physical_bone_parent(int p_bone);
|
||||
void _rebuild_physical_bones_cache();
|
||||
|
||||
public:
|
||||
void physical_bones_simulation(bool start);
|
||||
void physical_bones_add_collision_exception(RID p_exception);
|
||||
void physical_bones_remove_collision_exception(RID p_exception);
|
||||
|
||||
public:
|
||||
Skeleton();
|
||||
~Skeleton();
|
||||
};
|
||||
|
|
|
@ -286,6 +286,16 @@ Transform Spatial::get_global_transform() const {
|
|||
return data.global_transform;
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
Transform Spatial::get_global_gizmo_transform() const {
|
||||
return get_global_transform();
|
||||
}
|
||||
|
||||
Transform Spatial::get_local_gizmo_transform() const {
|
||||
return get_transform();
|
||||
}
|
||||
#endif
|
||||
|
||||
Spatial *Spatial::get_parent_spatial() const {
|
||||
|
||||
return data.parent;
|
||||
|
|
|
@ -145,6 +145,11 @@ public:
|
|||
Transform get_transform() const;
|
||||
Transform get_global_transform() const;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual Transform get_global_gizmo_transform() const;
|
||||
virtual Transform get_local_gizmo_transform() const;
|
||||
#endif
|
||||
|
||||
void set_as_toplevel(bool p_enabled);
|
||||
bool is_set_as_toplevel() const;
|
||||
|
||||
|
|
|
@ -246,8 +246,9 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
|
|||
|
||||
if (a->track_get_path(i).get_subname_count() == 1 && Object::cast_to<Skeleton>(child)) {
|
||||
|
||||
bone_idx = Object::cast_to<Skeleton>(child)->find_bone(a->track_get_path(i).get_subname(0));
|
||||
if (bone_idx == -1) {
|
||||
Skeleton *sk = Object::cast_to<Skeleton>(child);
|
||||
bone_idx = sk->find_bone(a->track_get_path(i).get_subname(0));
|
||||
if (bone_idx == -1 || sk->is_bone_ignore_animation(bone_idx)) {
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -579,16 +580,14 @@ void AnimationPlayer::_animation_process2(float p_delta) {
|
|||
}
|
||||
|
||||
void AnimationPlayer::_animation_update_transforms() {
|
||||
{
|
||||
Transform t;
|
||||
for (int i = 0; i < cache_update_size; i++) {
|
||||
|
||||
for (int i = 0; i < cache_update_size; i++) {
|
||||
TrackNodeCache *nc = cache_update[i];
|
||||
|
||||
TrackNodeCache *nc = cache_update[i];
|
||||
ERR_CONTINUE(nc->accum_pass != accum_pass);
|
||||
|
||||
ERR_CONTINUE(nc->accum_pass != accum_pass);
|
||||
|
||||
if (nc->spatial) {
|
||||
|
||||
Transform t;
|
||||
t.origin = nc->loc_accum;
|
||||
t.basis.set_quat_scale(nc->rot_accum, nc->scale_accum);
|
||||
if (nc->skeleton && nc->bone_idx >= 0) {
|
||||
|
|
|
@ -812,6 +812,12 @@ void AnimationTreePlayer::_process_animation(float p_delta) {
|
|||
|
||||
t.value = t.object->get_indexed(t.subpath);
|
||||
t.value.zero();
|
||||
|
||||
if (t.skeleton) {
|
||||
t.skip = t.skeleton->is_bone_ignore_animation(t.bone_idx);
|
||||
} else {
|
||||
t.skip = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* STEP 2 PROCESS ANIMATIONS */
|
||||
|
@ -884,7 +890,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) {
|
|||
|
||||
Track &t = E->get();
|
||||
|
||||
if (!t.object)
|
||||
if (t.skip || !t.object)
|
||||
continue;
|
||||
|
||||
if (t.subpath.size()) { // value track
|
||||
|
|
|
@ -107,6 +107,8 @@ private:
|
|||
Vector3 scale;
|
||||
|
||||
Variant value;
|
||||
|
||||
bool skip;
|
||||
};
|
||||
|
||||
typedef Map<TrackKey, Track> TrackMap;
|
||||
|
|
|
@ -390,6 +390,7 @@ void register_scene_types() {
|
|||
ClassDB::register_class<RigidBody>();
|
||||
ClassDB::register_class<KinematicCollision>();
|
||||
ClassDB::register_class<KinematicBody>();
|
||||
ClassDB::register_class<PhysicalBone>();
|
||||
|
||||
ClassDB::register_class<VehicleBody>();
|
||||
ClassDB::register_class<VehicleWheel>();
|
||||
|
|
Loading…
Add table
Reference in a new issue