Implemented ragdoll
Implementing ragdoll Implementing ragdoll Implementing ragdoll Implementing ragdoll Implementing ragdoll a Implemented implicit hierarchy. Improved Added some physics properties Added bone offset to preserve COM, partially fixed scaling work in progress WIP wip Implemented Joint Gizmos Implemented pin joint joint Implemented all joints
This commit is contained in:
parent
8c30337565
commit
9e57a07fb6
|
@ -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.
|
||||
|
|
|
@ -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 |
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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…
Reference in New Issue