From 59b5a3ceceacafffb83832dd2e80753b6dca4c8e Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Wed, 23 Jan 2013 13:06:59 +0100 Subject: [PATCH] _animblend_fixbone: try fixing the animations when blending animations This will ensure the aiming direction is always forward, at the cost of possibly screwing up the anims. --- qcsrc/client/autocvars.qh | 1 + qcsrc/client/player_skeleton.qc | 80 ++++++++++++++++++++++++++++++++- qcsrc/common/animdecide.qc | 1 + 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/qcsrc/client/autocvars.qh b/qcsrc/client/autocvars.qh index 0c926d43c..01f392519 100644 --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@ -408,4 +408,5 @@ float autocvar_cl_precacheplayermodels; float autocvar_cl_deathglow; float autocvar_developer_csqcentities; float autocvar__animblend; +float autocvar__animblend_fixbone; float autocvar_g_jetpack_attenuation; diff --git a/qcsrc/client/player_skeleton.qc b/qcsrc/client/player_skeleton.qc index 48fb8a34b..dd4d0a696 100644 --- a/qcsrc/client/player_skeleton.qc +++ b/qcsrc/client/player_skeleton.qc @@ -3,6 +3,9 @@ #define BONETYPE_UPPER 1 #define MAX_BONES 128 .float skeleton_bonetype[MAX_BONES]; +.float skeleton_fixrotatebone; +.float skeleton_fixtargetbone; +.float skeleton_bone; .float skeleton_aimbone; .float skeleton_numbones; @@ -11,6 +14,8 @@ void skeleton_identifybones(entity e) float s = e.skeletonindex; float n = (e.skeleton_numbones = skel_get_numbones(s)); e.skeleton_aimbone = 0; + e.skeleton_fixrotatebone = 0; + e.skeleton_fixtargetbone = 0; float i; for(i = 1; i <= n; ++i) { @@ -20,13 +25,62 @@ void skeleton_identifybones(entity e) t = e.(skeleton_bonetype[p-1]); string nm = skel_get_bonename(s, i); if(nm == "spine2") + { + e.skeleton_fixrotatebone = i; t = BONETYPE_UPPER; + } + if(nm == "weapon" || nm == "tag_weapon" || nm == "bip01 r hand") + if(t == BONETYPE_UPPER) + e.skeleton_fixtargetbone = i; if(nm == "upperarm_R") e.skeleton_aimbone = i; e.(skeleton_bonetype[i-1]) = t; } } +void skel_set_bone_lerp(float skel, float bone, vector org, float strength) +{ + if(strength >= 1) + return skel_set_bone(skel, bone, org); + + vector fo = v_forward; + vector ri = v_right; + vector up = v_up; + vector oldorg = skel_get_bonerel(skel, bone); + + org = org * strength + oldorg * (1 - strength); + v_forward = fo * strength + v_forward * (1 - strength); + v_right = ri * strength + v_right * (1 - strength); + v_up = up * strength + v_up * (1 - strength); + return skel_set_bone(skel, bone, org); +} + +void skeleton_fixbone(entity e, float strength) +{ + if(!e.skeleton_fixrotatebone) + return; + if(strength <= 0) + return; + // model: + // T = M_before_fixrotate * M_fixrotate * M_after_fixrotate + // T' = M_before_fixrotate^-1 * M_fixrotate' * M_after_fixrotate + // M_fixrotate' = M_before_fixrotate^-1 * T' * M_after_fixrotate^-1 + float s = e.skeletonindex; + + skel_get_boneabs(s, skel_get_boneparent(s, e.skeleton_fixrotatebone)); + vector M_before_fixrotate = fixedvectoangles2(v_forward, v_up); + skel_get_boneabs(s, e.skeleton_fixrotatebone); + vector M_including_fixrotate = fixedvectoangles2(v_forward, v_up); + skel_get_boneabs(s, e.skeleton_fixtargetbone); + vector T = fixedvectoangles2(v_forward, v_up); + vector M_after_fixrotate = AnglesTransform_LeftDivide(M_including_fixrotate, T); + vector T_ = '0 0 0'; + vector M_fixrotate_ = AnglesTransform_LeftDivide(M_before_fixrotate, AnglesTransform_RightDivide(T_, M_after_fixrotate)); + vector org = skel_get_bonerel(s, e.skeleton_fixrotatebone); + fixedmakevectors(M_fixrotate_); + skel_set_bone_lerp(s, e.skeleton_fixrotatebone, org, strength); +} + void free_skeleton_from_frames(entity e) { if(e.skeletonindex) @@ -86,6 +140,28 @@ void skeleton_from_frames(entity e) skel_build(s, e, m, 0, firstbone + 1, bone); } e.lerpfrac = savelerpfrac; - e.lerpfrac3 = savelerpfrac; - e.lerpfrac4 = savelerpfrac; + e.lerpfrac3 = savelerpfrac3; + e.lerpfrac4 = savelerpfrac4; + + if(autocvar__animblend_fixbone) + { + float l4 = e.lerpfrac4; + float l3 = e.lerpfrac3; + float l2 = e.lerpfrac; + float l1 = 1 - l2 - l3 - l4; + + // how much of upper body animates same way as lower body? + float equalamount = + (e.frame == e.frame2) * (l1 * l2) + + (e.frame == e.frame4) * (l1 * l4) + + (e.frame3 == e.frame2) * (l3 * l2) + + (e.frame3 == e.frame4) * (l3 * l4); + float maxequalamount = (l1 + l3) * (l2 + l4); + + // now how strong is the lerp? + float lerpstrength = 1 - equalamount / maxequalamount; + + // FIX IT + skeleton_fixbone(e, lerpstrength); + } } diff --git a/qcsrc/common/animdecide.qc b/qcsrc/common/animdecide.qc index f10c466be..3efdab4a3 100644 --- a/qcsrc/common/animdecide.qc +++ b/qcsrc/common/animdecide.qc @@ -225,6 +225,7 @@ void animdecide_setimplicitstate(entity e, float onground) vector v; v_x = e.velocity * v_forward; v_y = e.velocity * v_right; + v_z = 0; // we want to match like this: // the 8 directions shall be "evenly spaced" -- 2.39.2