]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
_animblend_fixbone: try fixing the animations when blending animations
authorRudolf Polzer <divverent@xonotic.org>
Wed, 23 Jan 2013 12:06:59 +0000 (13:06 +0100)
committerRudolf Polzer <divverent@xonotic.org>
Wed, 23 Jan 2013 12:06:59 +0000 (13:06 +0100)
This will ensure the aiming direction is always forward, at the cost of
possibly screwing up the anims.

qcsrc/client/autocvars.qh
qcsrc/client/player_skeleton.qc
qcsrc/common/animdecide.qc

index 0c926d43c9af408177f91e587eb949666ca8af93..01f3925199db205d29ace760acc23682ab9647d6 100644 (file)
@@ -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;
index 48fb8a34b7769a6cbfe0a503e41fafe408c8d4e5..dd4d0a6965ef29b54e65604b2fb356fd9a5d6c63 100644 (file)
@@ -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);
+       }
 }
index f10c466be0e7e609ed62d605941072e4aa934cb1..3efdab4a3311882013ba38fe49330a20e21301b7 100644 (file)
@@ -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"