diff options
Diffstat (limited to 'scene/resources')
-rw-r--r-- | scene/resources/animation.cpp | 258 | ||||
-rw-r--r-- | scene/resources/animation.h | 15 | ||||
-rw-r--r-- | scene/resources/skeleton_modification_3d_fabrik.cpp | 76 | ||||
-rw-r--r-- | scene/resources/skeleton_modification_3d_fabrik.h | 2 | ||||
-rw-r--r-- | scene/resources/skeleton_modification_3d_jiggle.cpp | 7 | ||||
-rw-r--r-- | scene/resources/skeleton_modification_3d_lookat.cpp | 4 | ||||
-rw-r--r-- | scene/resources/skeleton_modification_3d_twoboneik.cpp | 26 |
7 files changed, 340 insertions, 48 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 6612c5ff3c..08b78a39b1 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -49,6 +49,8 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { add_track(TYPE_ROTATION_3D); } else if (type == "scale_3d") { add_track(TYPE_SCALE_3D); + } else if (type == "blend_shape") { + add_track(TYPE_BLEND_SHAPE); } else if (type == "value") { add_track(TYPE_VALUE); } else if (type == "method") { @@ -146,6 +148,25 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { sk.value.y = ofs[3]; sk.value.z = ofs[4]; } + } else if (track_get_type(track) == TYPE_BLEND_SHAPE) { + BlendShapeTrack *st = static_cast<BlendShapeTrack *>(tracks[track]); + Vector<real_t> values = p_value; + int vcount = values.size(); + ERR_FAIL_COND_V(vcount % BLEND_SHAPE_TRACK_SIZE, false); + + const real_t *r = values.ptr(); + + int64_t count = vcount / BLEND_SHAPE_TRACK_SIZE; + st->blend_shapes.resize(count); + + TKey<float> *sw = st->blend_shapes.ptrw(); + for (int i = 0; i < count; i++) { + TKey<float> &sk = sw[i]; + const real_t *ofs = &r[i * BLEND_SHAPE_TRACK_SIZE]; + sk.time = ofs[0]; + sk.transition = ofs[1]; + sk.value = ofs[2]; + } } else if (track_get_type(track) == TYPE_VALUE) { ValueTrack *vt = static_cast<ValueTrack *>(tracks[track]); @@ -369,6 +390,9 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { case TYPE_SCALE_3D: r_ret = "scale_3d"; break; + case TYPE_BLEND_SHAPE: + r_ret = "blend_shape"; + break; case TYPE_VALUE: r_ret = "value"; break; @@ -464,6 +488,25 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { r_ret = keys; return true; + } else if (track_get_type(track) == TYPE_BLEND_SHAPE) { + Vector<real_t> keys; + int kk = track_get_key_count(track); + keys.resize(kk * BLEND_SHAPE_TRACK_SIZE); + + real_t *w = keys.ptrw(); + + int idx = 0; + for (int i = 0; i < track_get_key_count(track); i++) { + float bs; + blend_shape_track_get_key(track, i, &bs); + + w[idx++] = track_get_key_time(track, i); + w[idx++] = track_get_key_transition(track, i); + w[idx++] = bs; + } + + r_ret = keys; + return true; } else if (track_get_type(track) == TYPE_VALUE) { const ValueTrack *vt = static_cast<const ValueTrack *>(tracks[track]); @@ -682,6 +725,10 @@ int Animation::add_track(TrackType p_type, int p_at_pos) { ScaleTrack *st = memnew(ScaleTrack); tracks.insert(p_at_pos, st); } break; + case TYPE_BLEND_SHAPE: { + BlendShapeTrack *bst = memnew(BlendShapeTrack); + tracks.insert(p_at_pos, bst); + } break; case TYPE_VALUE: { tracks.insert(p_at_pos, memnew(ValueTrack)); @@ -731,6 +778,11 @@ void Animation::remove_track(int p_track) { _clear(st->scales); } break; + case TYPE_BLEND_SHAPE: { + BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(t); + _clear(bst->blend_shapes); + + } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); _clear(vt->values); @@ -993,6 +1045,53 @@ Error Animation::scale_track_interpolate(int p_track, double p_time, Vector3 *r_ return OK; } +int Animation::blend_shape_track_insert_key(int p_track, double p_time, float p_blend_shape) { + ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_BLEND_SHAPE, -1); + + BlendShapeTrack *st = static_cast<BlendShapeTrack *>(t); + + TKey<float> tkey; + tkey.time = p_time; + tkey.value = p_blend_shape; + + int ret = _insert(p_time, st->blend_shapes, tkey); + emit_changed(); + return ret; +} + +Error Animation::blend_shape_track_get_key(int p_track, int p_key, float *r_blend_shape) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); + Track *t = tracks[p_track]; + + BlendShapeTrack *st = static_cast<BlendShapeTrack *>(t); + ERR_FAIL_COND_V(t->type != TYPE_BLEND_SHAPE, ERR_INVALID_PARAMETER); + ERR_FAIL_INDEX_V(p_key, st->blend_shapes.size(), ERR_INVALID_PARAMETER); + + *r_blend_shape = st->blend_shapes[p_key].value; + + return OK; +} + +Error Animation::blend_shape_track_interpolate(int p_track, double p_time, float *r_interpolation) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_BLEND_SHAPE, ERR_INVALID_PARAMETER); + + BlendShapeTrack *st = static_cast<BlendShapeTrack *>(t); + + bool ok = false; + + float tk = _interpolate(st->blend_shapes, p_time, st->interpolation, st->loop_wrap, &ok); + + if (!ok) { + return ERR_UNAVAILABLE; + } + *r_interpolation = tk; + return OK; +} + void Animation::track_remove_key_at_time(int p_track, double p_time) { int idx = track_find_key(p_track, p_time, true); ERR_FAIL_COND(idx < 0); @@ -1022,6 +1121,12 @@ void Animation::track_remove_key(int p_track, int p_idx) { st->scales.remove(p_idx); } break; + case TYPE_BLEND_SHAPE: { + BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(t); + ERR_FAIL_INDEX(p_idx, bst->blend_shapes.size()); + bst->blend_shapes.remove(p_idx); + + } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); ERR_FAIL_INDEX(p_idx, vt->values.size()); @@ -1087,12 +1192,24 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { } break; case TYPE_SCALE_3D: { - ScaleTrack *rt = static_cast<ScaleTrack *>(t); - int k = _find(rt->scales, p_time); - if (k < 0 || k >= rt->scales.size()) { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + int k = _find(st->scales, p_time); + if (k < 0 || k >= st->scales.size()) { + return -1; + } + if (st->scales[k].time != p_time && p_exact) { + return -1; + } + return k; + + } break; + case TYPE_BLEND_SHAPE: { + BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(t); + int k = _find(bst->blend_shapes, p_time); + if (k < 0 || k >= bst->blend_shapes.size()) { return -1; } - if (rt->scales[k].time != p_time && p_exact) { + if (bst->blend_shapes[k].time != p_time && p_exact) { return -1; } return k; @@ -1186,6 +1303,12 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke track_set_key_transition(p_track, idx, p_transition); } break; + case TYPE_BLEND_SHAPE: { + ERR_FAIL_COND((p_key.get_type() != Variant::FLOAT) && (p_key.get_type() != Variant::INT)); + int idx = blend_shape_track_insert_key(p_track, p_time, p_key); + track_set_key_transition(p_track, idx, p_transition); + + } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); @@ -1279,6 +1402,10 @@ int Animation::track_get_key_count(int p_track) const { ScaleTrack *st = static_cast<ScaleTrack *>(t); return st->scales.size(); } break; + case TYPE_BLEND_SHAPE: { + BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(t); + return bst->blend_shapes.size(); + } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); return vt->values.size(); @@ -1328,6 +1455,12 @@ Variant Animation::track_get_key_value(int p_track, int p_key_idx) const { return st->scales[p_key_idx].value; } break; + case TYPE_BLEND_SHAPE: { + BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, bst->blend_shapes.size(), Variant()); + + return bst->blend_shapes[p_key_idx].value; + } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); ERR_FAIL_INDEX_V(p_key_idx, vt->values.size(), Variant()); @@ -1400,6 +1533,11 @@ double Animation::track_get_key_time(int p_track, int p_key_idx) const { ERR_FAIL_INDEX_V(p_key_idx, st->scales.size(), -1); return st->scales[p_key_idx].time; } break; + case TYPE_BLEND_SHAPE: { + BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, bst->blend_shapes.size(), -1); + return bst->blend_shapes[p_key_idx].time; + } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); ERR_FAIL_INDEX_V(p_key_idx, vt->values.size(), -1); @@ -1467,6 +1605,15 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) { _insert(p_time, tt->scales, key); return; } + case TYPE_BLEND_SHAPE: { + BlendShapeTrack *tt = static_cast<BlendShapeTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, tt->blend_shapes.size()); + TKey<float> key = tt->blend_shapes[p_key_idx]; + key.time = p_time; + tt->blend_shapes.remove(p_key_idx); + _insert(p_time, tt->blend_shapes, key); + return; + } case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); ERR_FAIL_INDEX(p_key_idx, vt->values.size()); @@ -1537,6 +1684,11 @@ real_t Animation::track_get_key_transition(int p_track, int p_key_idx) const { ERR_FAIL_INDEX_V(p_key_idx, st->scales.size(), -1); return st->scales[p_key_idx].transition; } break; + case TYPE_BLEND_SHAPE: { + BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, bst->blend_shapes.size(), -1); + return bst->blend_shapes[p_key_idx].transition; + } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); ERR_FAIL_INDEX_V(p_key_idx, vt->values.size(), -1); @@ -1592,6 +1744,14 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p st->scales.write[p_key_idx].value = p_value; } break; + case TYPE_BLEND_SHAPE: { + ERR_FAIL_COND((p_value.get_type() != Variant::FLOAT) && (p_value.get_type() != Variant::INT)); + BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, bst->blend_shapes.size()); + + bst->blend_shapes.write[p_key_idx].value = p_value; + + } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); ERR_FAIL_INDEX(p_key_idx, vt->values.size()); @@ -1673,6 +1833,11 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, real_t p_tr ERR_FAIL_INDEX(p_key_idx, st->scales.size()); st->scales.write[p_key_idx].transition = p_transition; } break; + case TYPE_BLEND_SHAPE: { + BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, bst->blend_shapes.size()); + bst->blend_shapes.write[p_key_idx].transition = p_transition; + } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); ERR_FAIL_INDEX(p_key_idx, vt->values.size()); @@ -2185,6 +2350,12 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl _track_get_key_indices_in_range(st->scales, 0, to_time, p_indices); } break; + case TYPE_BLEND_SHAPE: { + const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t); + _track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices); + _track_get_key_indices_in_range(bst->blend_shapes, 0, to_time, p_indices); + + } break; case TYPE_VALUE: { const ValueTrack *vt = static_cast<const ValueTrack *>(t); _track_get_key_indices_in_range(vt->values, from_time, length, p_indices); @@ -2250,6 +2421,11 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl _track_get_key_indices_in_range(st->scales, from_time, to_time, p_indices); } break; + case TYPE_BLEND_SHAPE: { + const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t); + _track_get_key_indices_in_range(bst->blend_shapes, from_time, to_time, p_indices); + + } break; case TYPE_VALUE: { const ValueTrack *vt = static_cast<const ValueTrack *>(t); _track_get_key_indices_in_range(vt->values, from_time, to_time, p_indices); @@ -2867,6 +3043,7 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("position_track_insert_key", "track_idx", "time", "position"), &Animation::position_track_insert_key); ClassDB::bind_method(D_METHOD("rotation_track_insert_key", "track_idx", "time", "rotation"), &Animation::rotation_track_insert_key); ClassDB::bind_method(D_METHOD("scale_track_insert_key", "track_idx", "time", "scale"), &Animation::scale_track_insert_key); + ClassDB::bind_method(D_METHOD("blend_shape_track_insert_key", "track_idx", "time", "amount"), &Animation::blend_shape_track_insert_key); ClassDB::bind_method(D_METHOD("track_insert_key", "track_idx", "time", "key", "transition"), &Animation::track_insert_key, DEFVAL(1)); ClassDB::bind_method(D_METHOD("track_remove_key", "track_idx", "key_idx"), &Animation::track_remove_key); @@ -2943,6 +3120,7 @@ void Animation::_bind_methods() { BIND_ENUM_CONSTANT(TYPE_POSITION_3D); BIND_ENUM_CONSTANT(TYPE_ROTATION_3D); BIND_ENUM_CONSTANT(TYPE_SCALE_3D); + BIND_ENUM_CONSTANT(TYPE_BLEND_SHAPE); BIND_ENUM_CONSTANT(TYPE_METHOD); BIND_ENUM_CONSTANT(TYPE_BEZIER); BIND_ENUM_CONSTANT(TYPE_AUDIO); @@ -3089,6 +3267,41 @@ bool Animation::_scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Ve return true; } +bool Animation::_blend_shape_track_optimize_key(const TKey<float> &t0, const TKey<float> &t1, const TKey<float> &t2, real_t p_allowed_unit_error) { + float v0 = t0.value; + float v1 = t1.value; + float v2 = t2.value; + + if (Math::is_equal_approx(v1, v2, p_allowed_unit_error)) { + //0 and 2 are close, let's see if 1 is close + if (!Math::is_equal_approx(v0, v1, p_allowed_unit_error)) { + //not close, not optimizable + return false; + } + + } else { + /* + TODO eventually discuss a way to optimize these better. + float pd = (v2 - v0); + real_t d0 = pd.dot(v0); + real_t d1 = pd.dot(v1); + real_t d2 = pd.dot(v2); + if (d1 < d0 || d1 > d2) { + return false; //beyond segment range + } + + float s[2] = { v0, v2 }; + real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); + + if (d > pd.length() * p_allowed_linear_error) { + return false; //beyond allowed error for colinearity + } +*/ + } + + return true; +} + void Animation::_position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err) { ERR_FAIL_INDEX(p_idx, tracks.size()); ERR_FAIL_COND(tracks[p_idx]->type != TYPE_POSITION_3D); @@ -3197,6 +3410,41 @@ void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_linear_err) { } } +void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_linear_err) { + ERR_FAIL_INDEX(p_idx, tracks.size()); + ERR_FAIL_COND(tracks[p_idx]->type != TYPE_BLEND_SHAPE); + BlendShapeTrack *tt = static_cast<BlendShapeTrack *>(tracks[p_idx]); + bool prev_erased = false; + TKey<float> first_erased; + first_erased.value = 0.0; + + for (int i = 1; i < tt->blend_shapes.size() - 1; i++) { + TKey<float> &t0 = tt->blend_shapes.write[i - 1]; + TKey<float> &t1 = tt->blend_shapes.write[i]; + TKey<float> &t2 = tt->blend_shapes.write[i + 1]; + + bool erase = _blend_shape_track_optimize_key(t0, t1, t2, p_allowed_linear_err); + + if (prev_erased && !_blend_shape_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err)) { + //avoid error to go beyond first erased key + erase = false; + } + + if (erase) { + if (!prev_erased) { + first_erased = t1; + prev_erased = true; + } + + tt->blend_shapes.remove(i); + i--; + + } else { + prev_erased = false; + } + } +} + void Animation::optimize(real_t p_allowed_linear_err, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) { for (int i = 0; i < tracks.size(); i++) { if (tracks[i]->type == TYPE_POSITION_3D) { @@ -3205,6 +3453,8 @@ void Animation::optimize(real_t p_allowed_linear_err, real_t p_allowed_angular_e _rotation_track_optimize(i, p_allowed_angular_err, p_max_optimizable_angle); } else if (tracks[i]->type == TYPE_SCALE_3D) { _scale_track_optimize(i, p_allowed_linear_err); + } else if (tracks[i]->type == TYPE_BLEND_SHAPE) { + _blend_shape_track_optimize(i, p_allowed_linear_err); } } } diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 614e12a560..4ee0741d87 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -45,6 +45,7 @@ public: TYPE_POSITION_3D, ///< Position 3D track TYPE_ROTATION_3D, ///< Rotation 3D track TYPE_SCALE_3D, ///< Scale 3D track + TYPE_BLEND_SHAPE, ///< Blend Shape track TYPE_METHOD, ///< Call any method on a specific node. TYPE_BEZIER, ///< Bezier curve TYPE_AUDIO, @@ -91,6 +92,7 @@ private: const int32_t POSITION_TRACK_SIZE = 5; const int32_t ROTATION_TRACK_SIZE = 6; const int32_t SCALE_TRACK_SIZE = 5; + const int32_t BLEND_SHAPE_TRACK_SIZE = 3; /* POSITION TRACK */ @@ -115,6 +117,13 @@ private: ScaleTrack() { type = TYPE_SCALE_3D; } }; + /* BLEND SHAPE TRACK */ + + struct BlendShapeTrack : public Track { + Vector<TKey<float>> blend_shapes; + BlendShapeTrack() { type = TYPE_BLEND_SHAPE; } + }; + /* PROPERTY VALUE TRACK */ struct ValueTrack : public Track { @@ -247,10 +256,12 @@ private: bool _position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_alowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm); bool _rotation_track_optimize_key(const TKey<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle); bool _scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error); + bool _blend_shape_track_optimize_key(const TKey<float> &t0, const TKey<float> &t1, const TKey<float> &t2, real_t p_allowed_unit_error); void _position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err); void _rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle); void _scale_track_optimize(int p_idx, real_t p_allowed_linear_err); + void _blend_shape_track_optimize(int p_idx, real_t p_allowed_unit_error); protected: bool _set(const StringName &p_name, const Variant &p_value); @@ -308,6 +319,10 @@ public: Error scale_track_get_key(int p_track, int p_key, Vector3 *r_scale) const; Error scale_track_interpolate(int p_track, double p_time, Vector3 *r_interpolation) const; + int blend_shape_track_insert_key(int p_track, double p_time, float p_blend); + Error blend_shape_track_get_key(int p_track, int p_key, float *r_blend) const; + Error blend_shape_track_interpolate(int p_track, double p_time, float *r_blend) const; + void track_set_interpolation_type(int p_track, InterpolationType p_interp); InterpolationType track_get_interpolation_type(int p_track) const; diff --git a/scene/resources/skeleton_modification_3d_fabrik.cpp b/scene/resources/skeleton_modification_3d_fabrik.cpp index 20ebbda256..dedea3e282 100644 --- a/scene/resources/skeleton_modification_3d_fabrik.cpp +++ b/scene/resources/skeleton_modification_3d_fabrik.cpp @@ -149,6 +149,11 @@ void SkeletonModification3DFABRIK::_execute(real_t p_delta) { return; } + // Make sure the transform cache is the correct size + if (fabrik_transforms.size() != fabrik_data_chain.size()) { + fabrik_transforms.resize(fabrik_data_chain.size()); + } + // Verify that all joints have a valid bone ID, and that all bone lengths are zero or more // Also, while we are here, apply magnet positions. for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) { @@ -162,27 +167,24 @@ void SkeletonModification3DFABRIK::_execute(real_t p_delta) { if (_print_execution_error(fabrik_data_chain[i].length < 0, "FABRIK Joint " + itos(i) + " has an invalid joint length. Cannot execute!")) { return; } - - Transform3D local_pose_override = stack->skeleton->get_bone_local_pose_override(fabrik_data_chain[i].bone_idx); + fabrik_transforms[i] = stack->skeleton->get_bone_global_pose(fabrik_data_chain[i].bone_idx); // Apply magnet positions: if (stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx) >= 0) { int parent_bone_idx = stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx); Transform3D conversion_transform = (stack->skeleton->get_bone_global_pose(parent_bone_idx)); - local_pose_override.origin += conversion_transform.basis.xform_inv(fabrik_data_chain[i].magnet_position); + fabrik_transforms[i].origin += conversion_transform.basis.xform_inv(fabrik_data_chain[i].magnet_position); } else { - local_pose_override.origin += fabrik_data_chain[i].magnet_position; + fabrik_transforms[i].origin += fabrik_data_chain[i].magnet_position; } - - stack->skeleton->set_bone_local_pose_override(fabrik_data_chain[i].bone_idx, local_pose_override, stack->strength, true); } + Transform3D origin_global_pose_trans = stack->skeleton->get_bone_global_pose_no_override(fabrik_data_chain[0].bone_idx); target_global_pose = stack->skeleton->world_transform_to_global_pose(node_target->get_global_transform()); - origin_global_pose = stack->skeleton->local_pose_to_global_pose( - fabrik_data_chain[0].bone_idx, stack->skeleton->get_bone_local_pose_override(fabrik_data_chain[0].bone_idx)); + origin_global_pose = origin_global_pose_trans; final_joint_idx = fabrik_data_chain.size() - 1; - real_t target_distance = stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[final_joint_idx].bone_idx, target_global_pose).origin.length(); + real_t target_distance = fabrik_transforms[final_joint_idx].origin.distance_to(target_global_pose.origin); chain_iterations = 0; while (target_distance > chain_tolerance) { @@ -190,7 +192,7 @@ void SkeletonModification3DFABRIK::_execute(real_t p_delta) { chain_forwards(); // update the target distance - target_distance = stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[final_joint_idx].bone_idx, target_global_pose).origin.length(); + target_distance = fabrik_transforms[final_joint_idx].origin.distance_to(target_global_pose.origin); // update chain iterations chain_iterations += 1; @@ -205,7 +207,7 @@ void SkeletonModification3DFABRIK::_execute(real_t p_delta) { void SkeletonModification3DFABRIK::chain_backwards() { int final_bone_idx = fabrik_data_chain[final_joint_idx].bone_idx; - Transform3D final_joint_trans = stack->skeleton->local_pose_to_global_pose(final_bone_idx, stack->skeleton->get_bone_local_pose_override(final_bone_idx)); + Transform3D final_joint_trans = fabrik_transforms[final_joint_idx]; // Get the direction the final bone is facing in. stack->skeleton->update_bone_rest_forward_vector(final_bone_idx); @@ -220,52 +222,46 @@ void SkeletonModification3DFABRIK::chain_backwards() { // set the position of the final joint to the target position final_joint_trans.origin = target_global_pose.origin - (direction * fabrik_data_chain[final_joint_idx].length); - final_joint_trans = stack->skeleton->global_pose_to_local_pose(final_bone_idx, final_joint_trans); - stack->skeleton->set_bone_local_pose_override(final_bone_idx, final_joint_trans, stack->strength, true); + fabrik_transforms[final_joint_idx] = final_joint_trans; // for all other joints, move them towards the target int i = final_joint_idx; while (i >= 1) { - int next_bone_idx = fabrik_data_chain[i].bone_idx; - Transform3D next_bone_trans = stack->skeleton->local_pose_to_global_pose(next_bone_idx, stack->skeleton->get_bone_local_pose_override(next_bone_idx)); + Transform3D next_bone_trans = fabrik_transforms[i]; i -= 1; - int current_bone_idx = fabrik_data_chain[i].bone_idx; - Transform3D current_trans = stack->skeleton->local_pose_to_global_pose(current_bone_idx, stack->skeleton->get_bone_local_pose_override(current_bone_idx)); + Transform3D current_trans = fabrik_transforms[i]; real_t length = fabrik_data_chain[i].length / (current_trans.origin.distance_to(next_bone_trans.origin)); current_trans.origin = next_bone_trans.origin.lerp(current_trans.origin, length); - // Apply it back to the skeleton - stack->skeleton->set_bone_local_pose_override(current_bone_idx, stack->skeleton->global_pose_to_local_pose(current_bone_idx, current_trans), stack->strength, true); + // Save the result + fabrik_transforms[i] = current_trans; } } void SkeletonModification3DFABRIK::chain_forwards() { // Set root at the initial position. - int origin_bone_idx = fabrik_data_chain[0].bone_idx; - Transform3D root_transform = stack->skeleton->local_pose_to_global_pose(origin_bone_idx, stack->skeleton->get_bone_local_pose_override(origin_bone_idx)); + Transform3D root_transform = fabrik_transforms[0]; + root_transform.origin = origin_global_pose.origin; - stack->skeleton->set_bone_local_pose_override(origin_bone_idx, stack->skeleton->global_pose_to_local_pose(origin_bone_idx, root_transform), stack->strength, true); + fabrik_transforms[0] = origin_global_pose; for (uint32_t i = 0; i < fabrik_data_chain.size() - 1; i++) { - int current_bone_idx = fabrik_data_chain[i].bone_idx; - Transform3D current_trans = stack->skeleton->local_pose_to_global_pose(current_bone_idx, stack->skeleton->get_bone_local_pose_override(current_bone_idx)); - int next_bone_idx = fabrik_data_chain[i + 1].bone_idx; - Transform3D next_bone_trans = stack->skeleton->local_pose_to_global_pose(next_bone_idx, stack->skeleton->get_bone_local_pose_override(next_bone_idx)); + Transform3D current_trans = fabrik_transforms[i]; + Transform3D next_bone_trans = fabrik_transforms[i + 1]; real_t length = fabrik_data_chain[i].length / (next_bone_trans.origin.distance_to(current_trans.origin)); next_bone_trans.origin = current_trans.origin.lerp(next_bone_trans.origin, length); - // Apply it back to the skeleton - stack->skeleton->set_bone_local_pose_override(next_bone_idx, stack->skeleton->global_pose_to_local_pose(next_bone_idx, next_bone_trans), stack->strength, true); + // Save the result + fabrik_transforms[i + 1] = next_bone_trans; } } void SkeletonModification3DFABRIK::chain_apply() { for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) { int current_bone_idx = fabrik_data_chain[i].bone_idx; - Transform3D current_trans = stack->skeleton->get_bone_local_pose_override(current_bone_idx); - current_trans = stack->skeleton->local_pose_to_global_pose(current_bone_idx, current_trans); + Transform3D current_trans = fabrik_transforms[i]; // If this is the last bone in the chain... if (i == fabrik_data_chain.size() - 1) { @@ -280,8 +276,7 @@ void SkeletonModification3DFABRIK::chain_apply() { current_trans.basis = target_global_pose.basis.orthonormalized().scaled(current_trans.basis.get_scale()); } } else { // every other bone in the chain... - int next_bone_idx = fabrik_data_chain[i + 1].bone_idx; - Transform3D next_trans = stack->skeleton->local_pose_to_global_pose(next_bone_idx, stack->skeleton->get_bone_local_pose_override(next_bone_idx)); + Transform3D next_trans = fabrik_transforms[i + 1]; // Get the forward direction that the basis is facing in right now. stack->skeleton->update_bone_rest_forward_vector(current_bone_idx); @@ -290,9 +285,7 @@ void SkeletonModification3DFABRIK::chain_apply() { current_trans.basis.rotate_to_align(forward_vector, current_trans.origin.direction_to(next_trans.origin)); current_trans.basis.rotate_local(forward_vector, fabrik_data_chain[i].roll); } - current_trans = stack->skeleton->global_pose_to_local_pose(current_bone_idx, current_trans); - current_trans.origin = Vector3(0, 0, 0); - stack->skeleton->set_bone_local_pose_override(current_bone_idx, current_trans, stack->strength, true); + stack->skeleton->set_bone_local_pose_override(current_bone_idx, stack->skeleton->global_pose_to_local_pose(current_bone_idx, current_trans), stack->strength, true); } // Update all the bones so the next modification has up-to-date data. @@ -374,6 +367,7 @@ int SkeletonModification3DFABRIK::get_fabrik_data_chain_length() { void SkeletonModification3DFABRIK::set_fabrik_data_chain_length(int p_length) { ERR_FAIL_COND(p_length < 0); fabrik_data_chain.resize(p_length); + fabrik_transforms.resize(p_length); execution_error_found = false; notify_property_list_changed(); } @@ -513,8 +507,11 @@ void SkeletonModification3DFABRIK::fabrik_joint_auto_calculate_length(int p_join Transform3D node_trans = tip_node->get_global_transform(); node_trans = stack->skeleton->world_transform_to_global_pose(node_trans); - node_trans = stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[p_joint_idx].bone_idx, node_trans); - fabrik_data_chain[p_joint_idx].length = node_trans.origin.length(); + //node_trans = stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[p_joint_idx].bone_idx, node_trans); + //fabrik_data_chain[p_joint_idx].length = node_trans.origin.length(); + + fabrik_data_chain[p_joint_idx].length = stack->skeleton->get_bone_global_pose(fabrik_data_chain[p_joint_idx].bone_idx).origin.distance_to(node_trans.origin); + } else { // Use child bone(s) to update joint length, if possible Vector<int> bone_children = stack->skeleton->get_bone_children(fabrik_data_chain[p_joint_idx].bone_idx); if (bone_children.size() <= 0) { @@ -522,10 +519,13 @@ void SkeletonModification3DFABRIK::fabrik_joint_auto_calculate_length(int p_join return; } + Transform3D bone_trans = stack->skeleton->get_bone_global_pose(fabrik_data_chain[p_joint_idx].bone_idx); + real_t final_length = 0; for (int i = 0; i < bone_children.size(); i++) { Transform3D child_transform = stack->skeleton->get_bone_global_pose(bone_children[i]); - final_length += stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[p_joint_idx].bone_idx, child_transform).origin.length(); + final_length += bone_trans.origin.distance_to(child_transform.origin); + //final_length += stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[p_joint_idx].bone_idx, child_transform).origin.length(); } fabrik_data_chain[p_joint_idx].length = final_length / bone_children.size(); } diff --git a/scene/resources/skeleton_modification_3d_fabrik.h b/scene/resources/skeleton_modification_3d_fabrik.h index 9b5da883d4..6c58b8a07a 100644 --- a/scene/resources/skeleton_modification_3d_fabrik.h +++ b/scene/resources/skeleton_modification_3d_fabrik.h @@ -55,6 +55,8 @@ private: }; LocalVector<FABRIK_Joint_Data> fabrik_data_chain; + LocalVector<Transform3D> fabrik_transforms; + NodePath target_node; ObjectID target_node_cache; diff --git a/scene/resources/skeleton_modification_3d_jiggle.cpp b/scene/resources/skeleton_modification_3d_jiggle.cpp index 1fb7dad2ad..a6bcb0176a 100644 --- a/scene/resources/skeleton_modification_3d_jiggle.cpp +++ b/scene/resources/skeleton_modification_3d_jiggle.cpp @@ -172,7 +172,12 @@ void SkeletonModification3DJiggle::_execute_jiggle_joint(int p_joint_idx, Node3D return; } - Transform3D new_bone_trans = stack->skeleton->local_pose_to_global_pose(jiggle_data_chain[p_joint_idx].bone_idx, stack->skeleton->get_bone_local_pose_override(jiggle_data_chain[p_joint_idx].bone_idx)); + Transform3D bone_local_pos = stack->skeleton->get_bone_local_pose_override(jiggle_data_chain[p_joint_idx].bone_idx); + if (bone_local_pos == Transform3D()) { + bone_local_pos = stack->skeleton->get_bone_pose(jiggle_data_chain[p_joint_idx].bone_idx); + } + + Transform3D new_bone_trans = stack->skeleton->local_pose_to_global_pose(jiggle_data_chain[p_joint_idx].bone_idx, bone_local_pos); Vector3 target_position = stack->skeleton->world_transform_to_global_pose(p_target->get_global_transform()).origin; jiggle_data_chain[p_joint_idx].force = (target_position - jiggle_data_chain[p_joint_idx].dynamic_position) * jiggle_data_chain[p_joint_idx].stiffness * p_delta; diff --git a/scene/resources/skeleton_modification_3d_lookat.cpp b/scene/resources/skeleton_modification_3d_lookat.cpp index afdb077e71..f3b0f41d60 100644 --- a/scene/resources/skeleton_modification_3d_lookat.cpp +++ b/scene/resources/skeleton_modification_3d_lookat.cpp @@ -96,8 +96,10 @@ void SkeletonModification3DLookAt::_execute(real_t p_delta) { if (_print_execution_error(bone_idx <= -1, "Bone index is invalid. Cannot execute modification!")) { return; } - Transform3D new_bone_trans = stack->skeleton->get_bone_local_pose_override(bone_idx); + if (new_bone_trans == Transform3D()) { + new_bone_trans = stack->skeleton->get_bone_pose(bone_idx); + } Vector3 target_pos = stack->skeleton->global_pose_to_local_pose(bone_idx, stack->skeleton->world_transform_to_global_pose(target->get_global_transform())).origin; // Lock the rotation to a plane relative to the bone by changing the target position diff --git a/scene/resources/skeleton_modification_3d_twoboneik.cpp b/scene/resources/skeleton_modification_3d_twoboneik.cpp index c1a71148a7..93ec155a88 100644 --- a/scene/resources/skeleton_modification_3d_twoboneik.cpp +++ b/scene/resources/skeleton_modification_3d_twoboneik.cpp @@ -178,7 +178,16 @@ void SkeletonModification3DTwoBoneIK::_execute(real_t p_delta) { } Transform3D pole_trans = stack->skeleton->world_transform_to_global_pose(pole->get_global_transform()); - bone_one_trans = stack->skeleton->local_pose_to_global_pose(joint_one_bone_idx, stack->skeleton->get_bone_local_pose_override(joint_one_bone_idx)); + Transform3D bone_one_local_pos = stack->skeleton->get_bone_local_pose_override(joint_one_bone_idx); + if (bone_one_local_pos == Transform3D()) { + bone_one_local_pos = stack->skeleton->get_bone_pose(joint_one_bone_idx); + } + Transform3D bone_two_local_pos = stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx); + if (bone_two_local_pos == Transform3D()) { + bone_two_local_pos = stack->skeleton->get_bone_pose(joint_two_bone_idx); + } + + bone_one_trans = stack->skeleton->local_pose_to_global_pose(joint_one_bone_idx, bone_one_local_pos); bone_one_trans = bone_one_trans.looking_at(pole_trans.origin, Vector3(0, 1, 0)); bone_one_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(joint_one_bone_idx, bone_one_trans.basis); stack->skeleton->update_bone_rest_forward_vector(joint_one_bone_idx); @@ -186,7 +195,7 @@ void SkeletonModification3DTwoBoneIK::_execute(real_t p_delta) { stack->skeleton->set_bone_local_pose_override(joint_one_bone_idx, stack->skeleton->global_pose_to_local_pose(joint_one_bone_idx, bone_one_trans), stack->strength, true); stack->skeleton->force_update_bone_children_transforms(joint_one_bone_idx); - bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx)); + bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, bone_two_local_pos); bone_two_trans = bone_two_trans.looking_at(target_trans.origin, Vector3(0, 1, 0)); bone_two_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(joint_two_bone_idx, bone_two_trans.basis); stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx); @@ -194,8 +203,17 @@ void SkeletonModification3DTwoBoneIK::_execute(real_t p_delta) { stack->skeleton->set_bone_local_pose_override(joint_two_bone_idx, stack->skeleton->global_pose_to_local_pose(joint_two_bone_idx, bone_two_trans), stack->strength, true); stack->skeleton->force_update_bone_children_transforms(joint_two_bone_idx); } else { - bone_one_trans = stack->skeleton->local_pose_to_global_pose(joint_one_bone_idx, stack->skeleton->get_bone_local_pose_override(joint_one_bone_idx)); - bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx)); + Transform3D bone_one_local_pos = stack->skeleton->get_bone_local_pose_override(joint_one_bone_idx); + if (bone_one_local_pos == Transform3D()) { + bone_one_local_pos = stack->skeleton->get_bone_pose(joint_one_bone_idx); + } + Transform3D bone_two_local_pos = stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx); + if (bone_two_local_pos == Transform3D()) { + bone_two_local_pos = stack->skeleton->get_bone_pose(joint_two_bone_idx); + } + + bone_one_trans = stack->skeleton->local_pose_to_global_pose(joint_one_bone_idx, bone_one_local_pos); + bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, bone_two_local_pos); } Transform3D bone_two_tip_trans; |