Merge pull request #11973 from AndreaCatania/ragdoll

Ragdoll - Physical bone node
This commit is contained in:
Juan Linietsky 2018-05-07 16:12:27 -03:00 committed by GitHub
commit 6d46f73ec3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 2269 additions and 22 deletions

View file

@ -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.

View 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

View 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);
}

View 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

View 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);
}

View 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

View file

@ -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();
}

View file

@ -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)));

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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();
};

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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

View file

@ -107,6 +107,8 @@ private:
Vector3 scale;
Variant value;
bool skip;
};
typedef Map<TrackKey, Track> TrackMap;

View file

@ -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>();