Added skin support and simplified APIs to override bone position.

This commit is contained in:
Juan Linietsky 2019-09-18 19:46:32 -03:00
parent 2861fd9552
commit d81ddaf33e
29 changed files with 419 additions and 281 deletions

View File

@ -2570,12 +2570,6 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform);
if (skeleton) {
state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_IN_WORLD_COORDS, skeleton->use_world_transform);
state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_TRANSFORM, skeleton->world_transform);
state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_TRANSFORM_INVERSE, skeleton->world_transform_inverse);
}
if (use_lightmap_capture) { //this is per instance, must be set always if present if (use_lightmap_capture) { //this is per instance, must be set always if present
glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES2::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr()); glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES2::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr());
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHTMAP_CAPTURE_SKY, false); state.scene_shader.set_uniform(SceneShaderGLES2::LIGHTMAP_CAPTURE_SKY, false);

View File

@ -3663,23 +3663,6 @@ void RasterizerStorageGLES2::skeleton_set_base_transform_2d(RID p_skeleton, cons
skeleton->base_transform_2d = p_base_transform; skeleton->base_transform_2d = p_base_transform;
} }
void RasterizerStorageGLES2::skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform) {
Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
ERR_FAIL_COND(skeleton->use_2d);
skeleton->world_transform = p_world_transform;
skeleton->use_world_transform = p_enable;
if (p_enable) {
skeleton->world_transform_inverse = skeleton->world_transform.affine_inverse();
}
if (!skeleton->update_list.in_list()) {
skeleton_update_list.add(&skeleton->update_list);
}
}
void RasterizerStorageGLES2::_update_skeleton_transform_buffer(const PoolVector<float> &p_data, size_t p_size) { void RasterizerStorageGLES2::_update_skeleton_transform_buffer(const PoolVector<float> &p_data, size_t p_size) {
glBindBuffer(GL_ARRAY_BUFFER, resources.skeleton_transform_buffer); glBindBuffer(GL_ARRAY_BUFFER, resources.skeleton_transform_buffer);

View File

@ -868,16 +868,12 @@ public:
Set<RasterizerScene::InstanceBase *> instances; Set<RasterizerScene::InstanceBase *> instances;
Transform2D base_transform_2d; Transform2D base_transform_2d;
Transform world_transform;
Transform world_transform_inverse;
bool use_world_transform;
Skeleton() : Skeleton() :
use_2d(false), use_2d(false),
size(0), size(0),
tex_id(0), tex_id(0),
update_list(this), update_list(this) {
use_world_transform(false) {
} }
}; };
@ -895,7 +891,6 @@ public:
virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform);
virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const;
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform); virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform);
virtual void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform);
void _update_skeleton_transform_buffer(const PoolVector<float> &p_data, size_t p_size); void _update_skeleton_transform_buffer(const PoolVector<float> &p_data, size_t p_size);

View File

@ -61,9 +61,6 @@ uniform ivec2 skeleton_texture_size;
#endif #endif
uniform highp mat4 skeleton_transform;
uniform highp mat4 skeleton_transform_inverse;
uniform bool skeleton_in_world_coords;
#endif #endif
@ -410,12 +407,9 @@ void main() {
#endif #endif
if (skeleton_in_world_coords) {
bone_transform = skeleton_transform * (bone_transform * skeleton_transform_inverse);
world_matrix = bone_transform * world_matrix;
} else {
world_matrix = world_matrix * bone_transform; world_matrix = world_matrix * bone_transform;
}
#endif #endif

View File

@ -2260,11 +2260,6 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
_set_cull(e->sort_key & RenderList::SORT_KEY_MIRROR_FLAG, e->sort_key & RenderList::SORT_KEY_CULL_DISABLED_FLAG, p_reverse_cull); _set_cull(e->sort_key & RenderList::SORT_KEY_MIRROR_FLAG, e->sort_key & RenderList::SORT_KEY_CULL_DISABLED_FLAG, p_reverse_cull);
if (skeleton) {
state.scene_shader.set_uniform(SceneShaderGLES3::SKELETON_TRANSFORM, skeleton->world_transform);
state.scene_shader.set_uniform(SceneShaderGLES3::SKELETON_IN_WORLD_COORDS, skeleton->use_world_transform);
}
state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, e->instance->transform); state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, e->instance->transform);
_render_geometry(e); _render_geometry(e);

View File

@ -5160,20 +5160,6 @@ void RasterizerStorageGLES3::skeleton_set_base_transform_2d(RID p_skeleton, cons
skeleton->base_transform_2d = p_base_transform; skeleton->base_transform_2d = p_base_transform;
} }
void RasterizerStorageGLES3::skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform) {
Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
ERR_FAIL_COND(skeleton->use_2d);
skeleton->world_transform = p_world_transform;
skeleton->use_world_transform = p_enable;
if (!skeleton->update_list.in_list()) {
skeleton_update_list.add(&skeleton->update_list);
}
}
void RasterizerStorageGLES3::update_dirty_skeletons() { void RasterizerStorageGLES3::update_dirty_skeletons() {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);

View File

@ -892,15 +892,12 @@ public:
SelfList<Skeleton> update_list; SelfList<Skeleton> update_list;
Set<RasterizerScene::InstanceBase *> instances; //instances using skeleton Set<RasterizerScene::InstanceBase *> instances; //instances using skeleton
Transform2D base_transform_2d; Transform2D base_transform_2d;
bool use_world_transform;
Transform world_transform;
Skeleton() : Skeleton() :
use_2d(false), use_2d(false),
size(0), size(0),
texture(0), texture(0),
update_list(this), update_list(this) {
use_world_transform(false) {
} }
}; };
@ -918,7 +915,6 @@ public:
virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform);
virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const;
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform); virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform);
virtual void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform);
/* Light API */ /* Light API */

View File

@ -302,8 +302,6 @@ out highp float dp_clip;
#ifdef USE_SKELETON #ifdef USE_SKELETON
uniform highp sampler2D skeleton_texture; // texunit:-1 uniform highp sampler2D skeleton_texture; // texunit:-1
uniform highp mat4 skeleton_transform;
uniform bool skeleton_in_world_coords;
#endif #endif
out highp vec4 position_interp; out highp vec4 position_interp;
@ -432,14 +430,8 @@ void main() {
vec4(0.0, 0.0, 0.0, 1.0)) * vec4(0.0, 0.0, 0.0, 1.0)) *
bone_weights.w; bone_weights.w;
if (skeleton_in_world_coords) {
highp mat4 bone_matrix = skeleton_transform * (transpose(m) * inverse(skeleton_transform));
world_matrix = bone_matrix * world_matrix;
} else {
world_matrix = world_matrix * transpose(m); world_matrix = world_matrix * transpose(m);
}
} }
#endif #endif

View File

@ -176,7 +176,6 @@ Error ColladaImport::_create_scene_skeletons(Collada::Node *p_node) {
Skeleton *sk = memnew(Skeleton); Skeleton *sk = memnew(Skeleton);
int bone = 0; int bone = 0;
sk->set_use_bones_in_world_transform(true); // This improves compatibility in Collada
for (int i = 0; i < p_node->children.size(); i++) { for (int i = 0; i < p_node->children.size(); i++) {
_populate_skeleton(sk, p_node->children[i], bone, -1); _populate_skeleton(sk, p_node->children[i], bone, -1);

View File

@ -2133,7 +2133,7 @@ Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, int p_bake_f
Vector<Skeleton *> skeletons; Vector<Skeleton *> skeletons;
for (int i = 0; i < state.skins.size(); i++) { for (int i = 0; i < state.skins.size(); i++) {
Skeleton *s = memnew(Skeleton); Skeleton *s = memnew(Skeleton);
s->set_use_bones_in_world_transform(false); //GLTF does not need this since meshes are always local
String name = state.skins[i].name; String name = state.skins[i].name;
if (name == "") { if (name == "") {
name = _gen_unique_name(state, "Skeleton"); name = _gen_unique_name(state, "Skeleton");

View File

@ -58,6 +58,7 @@ public:
RID instance; RID instance;
Ref<ArrayMesh> mesh; Ref<ArrayMesh> mesh;
Ref<Material> material; Ref<Material> material;
Ref<SkinReference> skin_reference;
RID skeleton; RID skeleton;
bool billboard; bool billboard;
bool unscaled; bool unscaled;
@ -101,7 +102,7 @@ protected:
public: public:
void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false); void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false);
void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const RID &p_skeleton = RID(), const Ref<Material> &p_material = Ref<Material>()); void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const Ref<SkinReference> &p_skin_reference = Ref<SkinReference>(), const Ref<Material> &p_material = Ref<Material>());
void add_collision_segments(const Vector<Vector3> &p_lines); void add_collision_segments(const Vector<Vector3> &p_lines);
void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh); void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh);
void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1); void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1);

View File

@ -172,8 +172,8 @@ void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base, bool p_hidde
instance = VS::get_singleton()->instance_create2(mesh->get_rid(), p_base->get_world()->get_scenario()); instance = VS::get_singleton()->instance_create2(mesh->get_rid(), p_base->get_world()->get_scenario());
VS::get_singleton()->instance_attach_object_instance_id(instance, p_base->get_instance_id()); VS::get_singleton()->instance_attach_object_instance_id(instance, p_base->get_instance_id());
if (skeleton.is_valid()) if (skin_reference.is_valid())
VS::get_singleton()->instance_attach_skeleton(instance, skeleton); VS::get_singleton()->instance_attach_skeleton(instance, skin_reference->get_skeleton());
if (extra_margin) if (extra_margin)
VS::get_singleton()->instance_set_extra_visibility_margin(instance, 1); VS::get_singleton()->instance_set_extra_visibility_margin(instance, 1);
VS::get_singleton()->instance_geometry_set_cast_shadows_setting(instance, VS::SHADOW_CASTING_SETTING_OFF); VS::get_singleton()->instance_geometry_set_cast_shadows_setting(instance, VS::SHADOW_CASTING_SETTING_OFF);
@ -181,14 +181,14 @@ void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base, bool p_hidde
VS::get_singleton()->instance_set_layer_mask(instance, layer); //gizmos are 26 VS::get_singleton()->instance_set_layer_mask(instance, layer); //gizmos are 26
} }
void EditorSpatialGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard, const RID &p_skeleton, const Ref<Material> &p_material) { void EditorSpatialGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard, const Ref<SkinReference> &p_skin_reference, const Ref<Material> &p_material) {
ERR_FAIL_COND(!spatial_node); ERR_FAIL_COND(!spatial_node);
Instance ins; Instance ins;
ins.billboard = p_billboard; ins.billboard = p_billboard;
ins.mesh = p_mesh; ins.mesh = p_mesh;
ins.skeleton = p_skeleton; ins.skin_reference = p_skin_reference;
ins.material = p_material; ins.material = p_material;
if (valid) { if (valid) {
ins.create_instance(spatial_node, hidden); ins.create_instance(spatial_node, hidden);
@ -1789,7 +1789,7 @@ void SkeletonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
} }
Ref<ArrayMesh> m = surface_tool->commit(); Ref<ArrayMesh> m = surface_tool->commit();
p_gizmo->add_mesh(m, false, skel->get_skeleton()); p_gizmo->add_mesh(m, false, skel->register_skin(Ref<Skin>()));
} }
//// ////
@ -3712,7 +3712,7 @@ void CollisionShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
Ref<ConcavePolygonShape> cs2 = s; Ref<ConcavePolygonShape> cs2 = s;
Ref<ArrayMesh> mesh = cs2->get_debug_mesh(); Ref<ArrayMesh> mesh = cs2->get_debug_mesh();
p_gizmo->add_mesh(mesh, false, RID(), material); p_gizmo->add_mesh(mesh, false, Ref<SkinReference>(), material);
} }
if (Object::cast_to<RayShape>(*s)) { if (Object::cast_to<RayShape>(*s)) {
@ -3734,7 +3734,7 @@ void CollisionShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
Ref<HeightMapShape> hms = s; Ref<HeightMapShape> hms = s;
Ref<ArrayMesh> mesh = hms->get_debug_mesh(); Ref<ArrayMesh> mesh = hms->get_debug_mesh();
p_gizmo->add_mesh(mesh, false, RID(), material); p_gizmo->add_mesh(mesh, false, Ref<SkinReference>(), material);
} }
} }

View File

@ -377,7 +377,7 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
break; break;
} }
p_gizmo->add_mesh(mesh, false, RID(), solid_material); p_gizmo->add_mesh(mesh, false, Ref<SkinReference>(), solid_material);
} }
if (Object::cast_to<CSGSphere>(cs)) { if (Object::cast_to<CSGSphere>(cs)) {

View File

@ -149,12 +149,38 @@ Ref<Mesh> MeshInstance::get_mesh() const {
void MeshInstance::_resolve_skeleton_path() { void MeshInstance::_resolve_skeleton_path() {
if (skeleton_path.is_empty()) Ref<SkinReference> new_skin_reference;
return;
if (!skeleton_path.is_empty()) {
Skeleton *skeleton = Object::cast_to<Skeleton>(get_node(skeleton_path)); Skeleton *skeleton = Object::cast_to<Skeleton>(get_node(skeleton_path));
if (skeleton) if (skeleton) {
VisualServer::get_singleton()->instance_attach_skeleton(get_instance(), skeleton->get_skeleton()); new_skin_reference = skeleton->register_skin(skin);
if (skin.is_null()) {
//a skin was created for us
skin = new_skin_reference->get_skin();
_change_notify();
}
}
}
skin_ref = new_skin_reference;
if (skin_ref.is_valid()) {
VisualServer::get_singleton()->instance_attach_skeleton(get_instance(), skin_ref->get_skeleton());
} else {
VisualServer::get_singleton()->instance_attach_skeleton(get_instance(), RID());
}
}
void MeshInstance::set_skin(const Ref<Skin> &p_skin) {
skin = p_skin;
if (!is_inside_tree())
return;
_resolve_skeleton_path();
}
Ref<Skin> MeshInstance::get_skin() const {
return skin;
} }
void MeshInstance::set_skeleton_path(const NodePath &p_skeleton) { void MeshInstance::set_skeleton_path(const NodePath &p_skeleton) {
@ -365,6 +391,8 @@ void MeshInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mesh"), &MeshInstance::get_mesh); ClassDB::bind_method(D_METHOD("get_mesh"), &MeshInstance::get_mesh);
ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &MeshInstance::set_skeleton_path); ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &MeshInstance::set_skeleton_path);
ClassDB::bind_method(D_METHOD("get_skeleton_path"), &MeshInstance::get_skeleton_path); ClassDB::bind_method(D_METHOD("get_skeleton_path"), &MeshInstance::get_skeleton_path);
ClassDB::bind_method(D_METHOD("set_skin", "skin"), &MeshInstance::set_skin);
ClassDB::bind_method(D_METHOD("get_skin"), &MeshInstance::get_skin);
ClassDB::bind_method(D_METHOD("get_surface_material_count"), &MeshInstance::get_surface_material_count); ClassDB::bind_method(D_METHOD("get_surface_material_count"), &MeshInstance::get_surface_material_count);
ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material"), &MeshInstance::set_surface_material); ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material"), &MeshInstance::set_surface_material);
@ -380,6 +408,7 @@ void MeshInstance::_bind_methods() {
ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path");
} }

View File

@ -31,8 +31,10 @@
#ifndef MESH_INSTANCE_H #ifndef MESH_INSTANCE_H
#define MESH_INSTANCE_H #define MESH_INSTANCE_H
#include "scene/3d/skeleton.h"
#include "scene/3d/visual_instance.h" #include "scene/3d/visual_instance.h"
#include "scene/resources/mesh.h" #include "scene/resources/mesh.h"
#include "scene/resources/skin.h"
class MeshInstance : public GeometryInstance { class MeshInstance : public GeometryInstance {
@ -40,6 +42,8 @@ class MeshInstance : public GeometryInstance {
protected: protected:
Ref<Mesh> mesh; Ref<Mesh> mesh;
Ref<Skin> skin;
Ref<SkinReference> skin_ref;
NodePath skeleton_path; NodePath skeleton_path;
struct BlendShapeTrack { struct BlendShapeTrack {
@ -70,6 +74,9 @@ public:
void set_mesh(const Ref<Mesh> &p_mesh); void set_mesh(const Ref<Mesh> &p_mesh);
Ref<Mesh> get_mesh() const; Ref<Mesh> get_mesh() const;
void set_skin(const Ref<Skin> &p_skin);
Ref<Skin> get_skin() const;
void set_skeleton_path(const NodePath &p_skeleton); void set_skeleton_path(const NodePath &p_skeleton);
NodePath get_skeleton_path(); NodePath get_skeleton_path();

View File

@ -2182,7 +2182,7 @@ void PhysicalBone::_notification(int p_what) {
void PhysicalBone::_direct_state_changed(Object *p_state) { void PhysicalBone::_direct_state_changed(Object *p_state) {
if (!simulate_physics) { if (!simulate_physics || !_internal_simulate_physics) {
return; return;
} }
@ -2205,7 +2205,7 @@ void PhysicalBone::_direct_state_changed(Object *p_state) {
// Update skeleton // Update skeleton
if (parent_skeleton) { if (parent_skeleton) {
if (-1 != bone_id) { if (-1 != bone_id) {
parent_skeleton->set_bone_global_pose(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse)); parent_skeleton->set_bone_global_pose_override(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse), 1.0, true);
} }
} }
} }
@ -2716,7 +2716,6 @@ void PhysicalBone::_start_physics_simulation() {
PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
parent_skeleton->set_bone_ignore_animation(bone_id, true);
_internal_simulate_physics = true; _internal_simulate_physics = true;
} }
@ -2728,6 +2727,6 @@ void PhysicalBone::_stop_physics_simulation() {
PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0); PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0);
PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0); PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0);
PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, ""); PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, "");
parent_skeleton->set_bone_ignore_animation(bone_id, false); parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false);
_internal_simulate_physics = false; _internal_simulate_physics = false;
} }

View File

@ -36,6 +36,34 @@
#include "scene/3d/physics_body.h" #include "scene/3d/physics_body.h"
#include "scene/resources/surface_tool.h" #include "scene/resources/surface_tool.h"
void SkinReference::_skin_changed() {
if (skeleton_node) {
skeleton_node->_make_dirty();
}
}
void SkinReference::_bind_methods() {
ClassDB::bind_method(D_METHOD("_skin_changed"), &SkinReference::_skin_changed);
ClassDB::bind_method(D_METHOD("get_skeleton"), &SkinReference::get_skeleton);
ClassDB::bind_method(D_METHOD("get_skin"), &SkinReference::get_skin);
}
RID SkinReference::get_skeleton() const {
return skeleton;
}
Ref<Skin> SkinReference::get_skin() const {
return skin;
}
SkinReference::~SkinReference() {
if (skeleton_node) {
skeleton_node->skin_bindings.erase(this);
}
VS::get_singleton()->free(skeleton);
}
bool Skeleton::_set(const StringName &p_path, const Variant &p_value) { bool Skeleton::_set(const StringName &p_path, const Variant &p_value) {
String path = p_path; String path = p_path;
@ -196,62 +224,27 @@ void Skeleton::_notification(int p_what) {
switch (p_what) { switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform());
} break;
case NOTIFICATION_EXIT_WORLD: {
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform());
} break;
case NOTIFICATION_UPDATE_SKELETON: { case NOTIFICATION_UPDATE_SKELETON: {
VisualServer *vs = VisualServer::get_singleton(); VisualServer *vs = VisualServer::get_singleton();
Bone *bonesptr = bones.ptrw(); Bone *bonesptr = bones.ptrw();
int len = bones.size(); int len = bones.size();
vs->skeleton_allocate(skeleton, len); // if same size, nothing really happens
_update_process_order(); _update_process_order();
const int *order = process_order.ptr(); const int *order = process_order.ptr();
// pose changed, rebuild cache of inverses
if (rest_global_inverse_dirty) {
// calculate global rests and invert them
for (int i = 0; i < len; i++) {
Bone &b = bonesptr[order[i]];
if (b.parent >= 0)
b.rest_global_inverse = bonesptr[b.parent].rest_global_inverse * b.rest;
else
b.rest_global_inverse = b.rest;
}
for (int i = 0; i < len; i++) {
Bone &b = bonesptr[order[i]];
b.rest_global_inverse.affine_invert();
}
rest_global_inverse_dirty = false;
}
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
Bone &b = bonesptr[order[i]]; Bone &b = bonesptr[order[i]];
if (b.global_pose_override_amount >= 0.999) {
b.pose_global = b.global_pose_override;
} else {
if (b.disable_rest) { if (b.disable_rest) {
if (b.enabled) { if (b.enabled) {
Transform pose = b.pose; Transform pose = b.pose;
if (b.custom_pose_enable) {
pose = b.custom_pose * pose;
}
if (b.parent >= 0) { if (b.parent >= 0) {
b.pose_global = bonesptr[b.parent].pose_global * pose; b.pose_global = bonesptr[b.parent].pose_global * pose;
@ -274,10 +267,6 @@ void Skeleton::_notification(int p_what) {
if (b.enabled) { if (b.enabled) {
Transform pose = b.pose; Transform pose = b.pose;
if (b.custom_pose_enable) {
pose = b.custom_pose * pose;
}
if (b.parent >= 0) { if (b.parent >= 0) {
@ -298,8 +287,14 @@ void Skeleton::_notification(int p_what) {
} }
} }
b.transform_final = b.pose_global * b.rest_global_inverse; if (b.global_pose_override_amount >= CMP_EPSILON) {
vs->skeleton_bone_set_transform(skeleton, order[i], b.transform_final); b.pose_global = b.pose_global.interpolate_with(b.global_pose_override, b.global_pose_override_amount);
}
}
if (b.global_pose_override_reset) {
b.global_pose_override_amount = 0.0;
}
for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) { for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) {
@ -311,28 +306,37 @@ void Skeleton::_notification(int p_what) {
} }
} }
//update skins
for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
const Skin *skin = E->get()->skin.operator->();
RID skeleton = E->get()->skeleton;
uint32_t bind_count = skin->get_bind_count();
if (E->get()->bind_count != bind_count) {
VS::get_singleton()->skeleton_allocate(skeleton, bind_count);
E->get()->bind_count = bind_count;
}
for (uint32_t i = 0; i < bind_count; i++) {
uint32_t bone_index = skin->get_bind_bone(i);
ERR_CONTINUE(bone_index >= (uint32_t)len);
vs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i));
}
}
dirty = false; dirty = false;
} break; } break;
} }
} }
Transform Skeleton::get_bone_transform(int p_bone) const { void Skeleton::set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent) {
ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
if (dirty)
const_cast<Skeleton *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
return bones[p_bone].pose_global * bones[p_bone].rest_global_inverse;
}
void Skeleton::set_bone_global_pose(int p_bone, const Transform &p_pose) {
ERR_FAIL_INDEX(p_bone, bones.size()); ERR_FAIL_INDEX(p_bone, bones.size());
if (bones[p_bone].parent == -1) { bones.write[p_bone].global_pose_override_amount = p_amount;
bones.write[p_bone].global_pose_override = p_pose;
set_bone_pose(p_bone, bones[p_bone].rest_global_inverse * p_pose); //fast bones.write[p_bone].global_pose_override_reset = !p_persistent;
} else { _make_dirty();
set_bone_pose(p_bone, bones[p_bone].rest.affine_inverse() * (get_bone_global_pose(bones[p_bone].parent).affine_inverse() * p_pose)); //slow
}
} }
Transform Skeleton::get_bone_global_pose(int p_bone) const { Transform Skeleton::get_bone_global_pose(int p_bone) const {
@ -343,11 +347,6 @@ Transform Skeleton::get_bone_global_pose(int p_bone) const {
return bones[p_bone].pose_global; return bones[p_bone].pose_global;
} }
RID Skeleton::get_skeleton() const {
return skeleton;
}
// skeleton creation api // skeleton creation api
void Skeleton::add_bone(const String &p_name) { void Skeleton::add_bone(const String &p_name) {
@ -362,8 +361,6 @@ void Skeleton::add_bone(const String &p_name) {
b.name = p_name; b.name = p_name;
bones.push_back(b); bones.push_back(b);
process_order_dirty = true; process_order_dirty = true;
rest_global_inverse_dirty = true;
_make_dirty(); _make_dirty();
update_gizmo(); update_gizmo();
} }
@ -408,7 +405,6 @@ void Skeleton::set_bone_parent(int p_bone, int p_parent) {
ERR_FAIL_COND(p_parent != -1 && (p_parent < 0)); ERR_FAIL_COND(p_parent != -1 && (p_parent < 0));
bones.write[p_bone].parent = p_parent; bones.write[p_bone].parent = p_parent;
rest_global_inverse_dirty = true;
process_order_dirty = true; process_order_dirty = true;
_make_dirty(); _make_dirty();
} }
@ -426,23 +422,11 @@ void Skeleton::unparent_bone_and_rest(int p_bone) {
} }
bones.write[p_bone].parent = -1; bones.write[p_bone].parent = -1;
bones.write[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing
process_order_dirty = true; process_order_dirty = true;
_make_dirty(); _make_dirty();
} }
void Skeleton::set_bone_ignore_animation(int p_bone, bool p_ignore) {
ERR_FAIL_INDEX(p_bone, bones.size());
bones.write[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) { void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) {
ERR_FAIL_INDEX(p_bone, bones.size()); ERR_FAIL_INDEX(p_bone, bones.size());
@ -467,7 +451,6 @@ void Skeleton::set_bone_rest(int p_bone, const Transform &p_rest) {
ERR_FAIL_INDEX(p_bone, bones.size()); ERR_FAIL_INDEX(p_bone, bones.size());
bones.write[p_bone].rest = p_rest; bones.write[p_bone].rest = p_rest;
rest_global_inverse_dirty = true;
_make_dirty(); _make_dirty();
} }
Transform Skeleton::get_bone_rest(int p_bone) const { Transform Skeleton::get_bone_rest(int p_bone) const {
@ -482,7 +465,6 @@ void Skeleton::set_bone_enabled(int p_bone, bool p_enabled) {
ERR_FAIL_INDEX(p_bone, bones.size()); ERR_FAIL_INDEX(p_bone, bones.size());
bones.write[p_bone].enabled = p_enabled; bones.write[p_bone].enabled = p_enabled;
rest_global_inverse_dirty = true;
_make_dirty(); _make_dirty();
} }
bool Skeleton::is_bone_enabled(int p_bone) const { bool Skeleton::is_bone_enabled(int p_bone) const {
@ -529,7 +511,6 @@ void Skeleton::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound)
void Skeleton::clear_bones() { void Skeleton::clear_bones() {
bones.clear(); bones.clear();
rest_global_inverse_dirty = true;
process_order_dirty = true; process_order_dirty = true;
_make_dirty(); _make_dirty();
@ -552,23 +533,6 @@ Transform Skeleton::get_bone_pose(int p_bone) const {
return bones[p_bone].pose; return bones[p_bone].pose;
} }
void Skeleton::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose) {
ERR_FAIL_INDEX(p_bone, bones.size());
//ERR_FAIL_COND( !is_inside_scene() );
bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform());
bones.write[p_bone].custom_pose = p_custom_pose;
_make_dirty();
}
Transform Skeleton::get_bone_custom_pose(int p_bone) const {
ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
return bones[p_bone].custom_pose;
}
void Skeleton::_make_dirty() { void Skeleton::_make_dirty() {
if (dirty) if (dirty)
@ -747,14 +711,66 @@ void Skeleton::physical_bones_remove_collision_exception(RID p_exception) {
#endif // _3D_DISABLED #endif // _3D_DISABLED
void Skeleton::set_use_bones_in_world_transform(bool p_enable) { void Skeleton::_skin_changed() {
use_bones_in_world_transform = p_enable; _make_dirty();
if (is_inside_tree()) {
VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform());
}
} }
bool Skeleton::is_using_bones_in_world_transform() const {
return use_bones_in_world_transform; Ref<SkinReference> Skeleton::register_skin(const Ref<Skin> &p_skin) {
for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
if (E->get()->skin == p_skin) {
return Ref<SkinReference>(E->get());
}
}
Ref<Skin> skin = p_skin;
if (skin.is_null()) {
//need to create one from existing code, this is for compatibility only
//when skeletons did not support skins. It is also used by gizmo
//to display the skeleton.
skin.instance();
skin->set_bind_count(bones.size());
_update_process_order(); //just in case
// pose changed, rebuild cache of inverses
const Bone *bonesptr = bones.ptr();
int len = bones.size();
const int *order = process_order.ptr();
// calculate global rests and invert them
for (int i = 0; i < len; i++) {
const Bone &b = bonesptr[order[i]];
if (b.parent >= 0) {
skin->set_bind_pose(order[i], skin->get_bind_pose(b.parent) * b.rest);
} else {
skin->set_bind_pose(order[i], b.rest);
}
}
for (int i = 0; i < len; i++) {
//the inverse is what is actually required
skin->set_bind_bone(i, i);
skin->set_bind_pose(i, skin->get_bind_pose(i).affine_inverse());
}
}
ERR_FAIL_COND_V(skin.is_null(), Ref<SkinReference>());
Ref<SkinReference> skin_ref;
skin_ref.instance();
skin_ref->skeleton_node = this;
skin_ref->bind_count = 0;
skin_ref->skeleton = VisualServer::get_singleton()->skeleton_create();
skin_ref->skeleton_node = this;
skin_ref->skin = skin;
skin_bindings.insert(skin_ref.operator->());
skin->connect("changed", skin_ref.operator->(), "_skin_changed");
return skin_ref;
} }
void Skeleton::_bind_methods() { void Skeleton::_bind_methods() {
@ -773,6 +789,8 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton::get_bone_rest); ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton::get_bone_rest);
ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton::set_bone_rest); ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton::set_bone_rest);
ClassDB::bind_method(D_METHOD("register_skin", "skin"), &Skeleton::register_skin);
ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton::localize_rests); ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton::localize_rests);
ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton::set_bone_disable_rest); ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton::set_bone_disable_rest);
@ -787,17 +805,9 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton::get_bone_pose); ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton::get_bone_pose);
ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton::set_bone_pose); ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton::set_bone_pose);
ClassDB::bind_method(D_METHOD("set_bone_global_pose", "bone_idx", "pose"), &Skeleton::set_bone_global_pose); ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton::set_bone_global_pose_override, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton::get_bone_global_pose); ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton::get_bone_global_pose);
ClassDB::bind_method(D_METHOD("get_bone_custom_pose", "bone_idx"), &Skeleton::get_bone_custom_pose);
ClassDB::bind_method(D_METHOD("set_bone_custom_pose", "bone_idx", "custom_pose"), &Skeleton::set_bone_custom_pose);
ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform);
ClassDB::bind_method(D_METHOD("set_use_bones_in_world_transform", "enable"), &Skeleton::set_use_bones_in_world_transform);
ClassDB::bind_method(D_METHOD("is_using_bones_in_world_transform"), &Skeleton::is_using_bones_in_world_transform);
#ifndef _3D_DISABLED #ifndef _3D_DISABLED
ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation); ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation);
@ -807,22 +817,19 @@ void Skeleton::_bind_methods() {
#endif // _3D_DISABLED #endif // _3D_DISABLED
ClassDB::bind_method(D_METHOD("set_bone_ignore_animation", "bone", "ignore"), &Skeleton::set_bone_ignore_animation);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bones_in_world_transform"), "set_use_bones_in_world_transform", "is_using_bones_in_world_transform");
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON); BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
} }
Skeleton::Skeleton() { Skeleton::Skeleton() {
rest_global_inverse_dirty = true;
dirty = false; dirty = false;
process_order_dirty = true; process_order_dirty = true;
skeleton = VisualServer::get_singleton()->skeleton_create();
set_notify_transform(true);
use_bones_in_world_transform = false;
} }
Skeleton::~Skeleton() { Skeleton::~Skeleton() {
VisualServer::get_singleton()->free(skeleton);
//some skins may remain bound
for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
E->get()->skeleton_node = nullptr;
}
} }

View File

@ -33,6 +33,7 @@
#include "core/rid.h" #include "core/rid.h"
#include "scene/3d/spatial.h" #include "scene/3d/spatial.h"
#include "scene/resources/skin.h"
#ifndef _3D_DISABLED #ifndef _3D_DISABLED
typedef int BoneId; typedef int BoneId;
@ -40,10 +41,38 @@ typedef int BoneId;
class PhysicalBone; class PhysicalBone;
#endif // _3D_DISABLED #endif // _3D_DISABLED
class Skeleton;
class SkinReference : public Reference {
GDCLASS(SkinReference, Reference)
friend class Skeleton;
Skeleton *skeleton_node;
RID skeleton;
Ref<Skin> skin;
uint32_t bind_count = 0;
void _skin_changed();
protected:
static void _bind_methods();
public:
RID get_skeleton() const;
Ref<Skin> get_skin() const;
~SkinReference();
};
class Skeleton : public Spatial { class Skeleton : public Spatial {
GDCLASS(Skeleton, Spatial); GDCLASS(Skeleton, Spatial);
private:
friend class SkinReference;
Set<SkinReference *> skin_bindings;
void _skin_changed();
struct Bone { struct Bone {
String name; String name;
@ -52,19 +81,15 @@ class Skeleton : public Spatial {
int parent; int parent;
int sort_index; //used for re-sorting process order int sort_index; //used for re-sorting process order
bool ignore_animation;
bool disable_rest; bool disable_rest;
Transform rest; Transform rest;
Transform rest_global_inverse;
Transform pose; Transform pose;
Transform pose_global; Transform pose_global;
bool custom_pose_enable; float global_pose_override_amount;
Transform custom_pose; bool global_pose_override_reset;
Transform global_pose_override;
Transform transform_final;
#ifndef _3D_DISABLED #ifndef _3D_DISABLED
PhysicalBone *physical_bone; PhysicalBone *physical_bone;
@ -76,9 +101,9 @@ class Skeleton : public Spatial {
Bone() { Bone() {
parent = -1; parent = -1;
enabled = true; enabled = true;
ignore_animation = false;
custom_pose_enable = false;
disable_rest = false; disable_rest = false;
global_pose_override_amount = 0;
global_pose_override_reset = false;
#ifndef _3D_DISABLED #ifndef _3D_DISABLED
physical_bone = NULL; physical_bone = NULL;
cache_parent_physical_bone = NULL; cache_parent_physical_bone = NULL;
@ -86,17 +111,12 @@ class Skeleton : public Spatial {
} }
}; };
bool rest_global_inverse_dirty;
Vector<Bone> bones; Vector<Bone> bones;
Vector<int> process_order; Vector<int> process_order;
bool process_order_dirty; bool process_order_dirty;
RID skeleton;
void _make_dirty(); void _make_dirty();
bool dirty; bool dirty;
bool use_bones_in_world_transform;
// bind helpers // bind helpers
Array _get_bound_child_nodes_to_bone(int p_bone) const { Array _get_bound_child_nodes_to_bone(int p_bone) const {
@ -127,8 +147,6 @@ public:
NOTIFICATION_UPDATE_SKELETON = 50 NOTIFICATION_UPDATE_SKELETON = 50
}; };
RID get_skeleton() const;
// skeleton creation api // skeleton creation api
void add_bone(const String &p_name); void add_bone(const String &p_name);
int find_bone(const String &p_name) const; int find_bone(const String &p_name) const;
@ -141,9 +159,6 @@ public:
void unparent_bone_and_rest(int p_bone); 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); void set_bone_disable_rest(int p_bone, bool p_disable);
bool is_bone_rest_disabled(int p_bone) const; bool is_bone_rest_disabled(int p_bone) const;
@ -151,10 +166,9 @@ public:
void set_bone_rest(int p_bone, const Transform &p_rest); void set_bone_rest(int p_bone, const Transform &p_rest);
Transform get_bone_rest(int p_bone) const; Transform get_bone_rest(int p_bone) const;
Transform get_bone_transform(int p_bone) const;
Transform get_bone_global_pose(int p_bone) const; Transform get_bone_global_pose(int p_bone) const;
void set_bone_global_pose(int p_bone, const Transform &p_pose); void set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent = false);
void set_bone_enabled(int p_bone, bool p_enabled); void set_bone_enabled(int p_bone, bool p_enabled);
bool is_bone_enabled(int p_bone) const; bool is_bone_enabled(int p_bone) const;
@ -170,14 +184,10 @@ public:
void set_bone_pose(int p_bone, const Transform &p_pose); void set_bone_pose(int p_bone, const Transform &p_pose);
Transform get_bone_pose(int p_bone) const; Transform get_bone_pose(int p_bone) const;
void set_bone_custom_pose(int p_bone, const Transform &p_custom_pose);
Transform get_bone_custom_pose(int p_bone) const;
void localize_rests(); // used for loaders and tools void localize_rests(); // used for loaders and tools
int get_process_order(int p_idx); int get_process_order(int p_idx);
void set_use_bones_in_world_transform(bool p_enable); Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
bool is_using_bones_in_world_transform() const;
#ifndef _3D_DISABLED #ifndef _3D_DISABLED
// Physical bone API // Physical bone API

View File

@ -256,7 +256,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
Skeleton *sk = Object::cast_to<Skeleton>(child); Skeleton *sk = Object::cast_to<Skeleton>(child);
bone_idx = sk->find_bone(a->track_get_path(i).get_subname(0)); bone_idx = sk->find_bone(a->track_get_path(i).get_subname(0));
if (bone_idx == -1 || sk->is_bone_ignore_animation(bone_idx)) { if (bone_idx == -1) {
continue; continue;
} }

View File

@ -622,7 +622,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
Skeleton *sk = Object::cast_to<Skeleton>(spatial); Skeleton *sk = Object::cast_to<Skeleton>(spatial);
int bone_idx = sk->find_bone(path.get_subname(0)); int bone_idx = sk->find_bone(path.get_subname(0));
if (bone_idx != -1 && !sk->is_bone_ignore_animation(bone_idx)) { if (bone_idx != -1) {
track_xform->skeleton = sk; track_xform->skeleton = sk;
track_xform->bone_idx = bone_idx; track_xform->bone_idx = bone_idx;

View File

@ -820,12 +820,8 @@ void AnimationTreePlayer::_process_animation(float p_delta) {
t.value = t.object->get_indexed(t.subpath); t.value = t.object->get_indexed(t.subpath);
t.value.zero(); t.value.zero();
if (t.skeleton) {
t.skip = t.skeleton->is_bone_ignore_animation(t.bone_idx);
} else {
t.skip = false; t.skip = false;
} }
}
/* STEP 2 PROCESS ANIMATIONS */ /* STEP 2 PROCESS ANIMATIONS */

View File

@ -320,7 +320,7 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis; new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis;
} }
p_task->skeleton->set_bone_global_pose(ci->bone, new_bone_pose); p_task->skeleton->set_bone_global_pose_override(ci->bone, new_bone_pose, 1.0);
if (!ci->children.empty()) if (!ci->children.empty())
ci = &ci->children.write[0]; ci = &ci->children.write[0];

View File

@ -364,6 +364,9 @@ void register_scene_types() {
/* REGISTER 3D */ /* REGISTER 3D */
ClassDB::register_class<Skin>();
ClassDB::register_virtual_class<SkinReference>();
ClassDB::register_class<Spatial>(); ClassDB::register_class<Spatial>();
ClassDB::register_virtual_class<SpatialGizmo>(); ClassDB::register_virtual_class<SpatialGizmo>();
ClassDB::register_class<Skeleton>(); ClassDB::register_class<Skeleton>();

102
scene/resources/skin.cpp Normal file
View File

@ -0,0 +1,102 @@
#include "skin.h"
void Skin::set_bind_count(int p_size) {
ERR_FAIL_COND(p_size < 0);
binds.resize(p_size);
binds_ptr = binds.ptrw();
bind_count = p_size;
emit_changed();
}
void Skin::add_bind(int p_bone, const Transform &p_pose) {
uint32_t index = bind_count;
set_bind_count(bind_count + 1);
set_bind_bone(index, p_bone);
set_bind_pose(index, p_pose);
}
void Skin::set_bind_bone(int p_index, int p_bone) {
ERR_FAIL_INDEX(p_index, bind_count);
binds_ptr[p_index].bone = p_bone;
emit_changed();
}
void Skin::set_bind_pose(int p_index, const Transform &p_pose) {
ERR_FAIL_INDEX(p_index, bind_count);
binds_ptr[p_index].pose = p_pose;
emit_changed();
}
void Skin::clear_binds() {
binds.clear();
binds_ptr = nullptr;
bind_count = 0;
emit_changed();
}
bool Skin::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
if (name == "bind_count") {
set_bind_count(p_value);
return true;
} else if (name.begins_with("bind/")) {
int index = name.get_slicec('/', 1).to_int();
String what = name.get_slicec('/', 2);
if (what == "bone") {
set_bind_bone(index, p_value);
return true;
} else if (what == "pose") {
set_bind_pose(index, p_value);
return true;
}
}
return false;
}
bool Skin::_get(const StringName &p_name, Variant &r_ret) const {
String name = p_name;
if (name == "bind_count") {
r_ret = get_bind_count();
return true;
} else if (name.begins_with("bind/")) {
int index = name.get_slicec('/', 1).to_int();
String what = name.get_slicec('/', 2);
if (what == "bone") {
r_ret = get_bind_bone(index);
return true;
} else if (what == "pose") {
r_ret = get_bind_pose(index);
return true;
}
}
return false;
}
void Skin::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::INT, "bind_count", PROPERTY_HINT_RANGE, "0,16384,1,or_greater"));
for (int i = 0; i < get_bind_count(); i++) {
p_list->push_back(PropertyInfo(Variant::INT, "bind/" + itos(i) + "/bone", PROPERTY_HINT_RANGE, "0,16384,1,or_greater"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM, "bind/" + itos(i) + "/pose"));
}
}
void Skin::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bind_count", "bind_count"), &Skin::set_bind_count);
ClassDB::bind_method(D_METHOD("get_bind_count"), &Skin::get_bind_count);
ClassDB::bind_method(D_METHOD("add_bind", "bone", "pose"), &Skin::add_bind);
ClassDB::bind_method(D_METHOD("set_bind_pose", "bind_index", "pose"), &Skin::set_bind_pose);
ClassDB::bind_method(D_METHOD("get_bind_pose", "bind_index"), &Skin::get_bind_pose);
ClassDB::bind_method(D_METHOD("set_bind_bone", "bind_index", "bone"), &Skin::set_bind_bone);
ClassDB::bind_method(D_METHOD("get_bind_bone", "bind_index"), &Skin::get_bind_bone);
ClassDB::bind_method(D_METHOD("clear_binds"), &Skin::clear_binds);
}
Skin::Skin() {
bind_count = 0;
binds_ptr = nullptr;
}

54
scene/resources/skin.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef SKIN_H
#define SKIN_H
#include "core/resource.h"
class Skin : public Resource {
GDCLASS(Skin, Resource)
struct Bind {
int bone;
Transform pose;
};
Vector<Bind> binds;
Bind *binds_ptr;
int bind_count;
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;
static void _bind_methods();
public:
void set_bind_count(int p_size);
inline int get_bind_count() const { return bind_count; }
void add_bind(int p_bone, const Transform &p_pose);
void set_bind_bone(int p_index, int p_bone);
void set_bind_pose(int p_index, const Transform &p_pose);
inline int get_bind_bone(int p_index) const {
#ifdef DEBUG_ENABLED
ERR_FAIL_INDEX_V(p_index, bind_count, -1);
#endif
return binds_ptr[p_index].bone;
}
inline Transform get_bind_pose(int p_index) const {
#ifdef DEBUG_ENABLED
ERR_FAIL_INDEX_V(p_index, bind_count, Transform());
#endif
return binds_ptr[p_index].pose;
}
void clear_binds();
Skin();
};
#endif // SKIN_H

View File

@ -357,7 +357,6 @@ public:
virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0;
virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0;
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0;
virtual void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform) = 0;
/* Light API */ /* Light API */

View File

@ -294,7 +294,6 @@ public:
BIND3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &) BIND3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &)
BIND2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int) BIND2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int)
BIND2(skeleton_set_base_transform_2d, RID, const Transform2D &) BIND2(skeleton_set_base_transform_2d, RID, const Transform2D &)
BIND3(skeleton_set_world_transform, RID, bool, const Transform &)
/* Light API */ /* Light API */

View File

@ -230,7 +230,6 @@ public:
FUNC3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &) FUNC3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &)
FUNC2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int) FUNC2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int)
FUNC2(skeleton_set_base_transform_2d, RID, const Transform2D &) FUNC2(skeleton_set_base_transform_2d, RID, const Transform2D &)
FUNC3(skeleton_set_world_transform, RID, bool, const Transform &)
/* Light API */ /* Light API */

View File

@ -391,7 +391,6 @@ public:
virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0;
virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0;
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0;
virtual void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_base_transform) = 0;
/* Light API */ /* Light API */