| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- /******************************************************************************/
- #include "stdafx.h"
- namespace EE{
- namespace Game{
- /******************************************************************************/
- static SkelAnim* GetAnim(AnimatedSkeleton &anim_skel, C ObjectPtr &obj, CChar8 *anim)
- {
- if(obj)if(Param *param=obj->findParam(anim))return anim_skel.findSkelAnim(param->asID());
- return null;
- }
- void Chr::SkelAnimCache::set(AnimatedSkeleton &anim_skel, C ObjectPtr &obj)
- {
- // set default animations
- fist_l =GetAnim(anim_skel, obj, "anim fist left");
- fist_r =GetAnim(anim_skel, obj, "anim fist right");
- stand =GetAnim(anim_skel, obj, "anim stand");
- crouch =GetAnim(anim_skel, obj, "anim crouch");
- turn_l =GetAnim(anim_skel, obj, "anim turn left");
- turn_r =GetAnim(anim_skel, obj, "anim turn right");
- walk =GetAnim(anim_skel, obj, "anim walk");
- run =GetAnim(anim_skel, obj, "anim run");
- crouch_f =GetAnim(anim_skel, obj, "anim crouch forward");
- crouch_l =GetAnim(anim_skel, obj, "anim crouch left");
- crouch_r =GetAnim(anim_skel, obj, "anim crouch right");
- strafe_wl=GetAnim(anim_skel, obj, "anim walk left");
- strafe_wr=GetAnim(anim_skel, obj, "anim walk right");
- strafe_l =GetAnim(anim_skel, obj, "anim run left");
- strafe_r =GetAnim(anim_skel, obj, "anim run right");
- dodge_l =GetAnim(anim_skel, obj, "anim dodge left");
- dodge_r =GetAnim(anim_skel, obj, "anim dodge right");
- floating =GetAnim(anim_skel, obj, "anim float");
- // detect indexes of skeleton bones
- head =anim_skel.findBoneI(BONE_HEAD);
- neck =anim_skel.findBoneI(BONE_NECK);
- body =anim_skel.findBoneI(BONE_SPINE);
- arm_lu=anim_skel.findBoneI(BONE_UPPER_ARM, -1);
- arm_ru=anim_skel.findBoneI(BONE_UPPER_ARM, 0);
- arm_ld=anim_skel.findBoneI(BONE_FOREARM , -1);
- arm_rd=anim_skel.findBoneI(BONE_FOREARM , 0);
- leg_lu=anim_skel.findBoneI(BONE_UPPER_LEG, -1);
- leg_ru=anim_skel.findBoneI(BONE_UPPER_LEG, 0);
- leg_ld=anim_skel.findBoneI(BONE_LOWER_LEG, -1);
- leg_rd=anim_skel.findBoneI(BONE_LOWER_LEG, 0);
- hand_l=anim_skel.findBoneI(BONE_HAND , -1);
- hand_r=anim_skel.findBoneI(BONE_HAND , 0);
- toe_l =anim_skel.findBoneI(BONE_TOE , -1);
- toe_r =anim_skel.findBoneI(BONE_TOE , 0);
- if(C Skeleton *skel=anim_skel.skeleton())
- {
- Int spines=0; REPA(skel->bones)if(skel->bones[i].type==BONE_SPINE)MAX(spines, skel->bones[i].type_sub); // skeletons may have many spine bones, calculate how many
- body_u=anim_skel.findBoneI(BONE_SPINE, 0, (spines+1)/2); // chose spine bone in the middle
- }else body_u=-1;
- }
- /******************************************************************************/
- Flt Chr::animateFaceBlend() // facial animation blending value, dependent on distance from camera, returns value 0..1 (0 disables facial animation)
- {
- Flt distance =Dist2(pos(), ActiveCam.matrix.pos),
- full_blend_range=Sqr (3),
- no_blend_range=Sqr (4);
- return LerpRS(no_blend_range, full_blend_range, distance);
- }
- Bool Chr::animateFingers() // if animate hand/foot fingers, dependent on distance from camera, returns value true/false (false disables fingers animation)
- {
- Flt distance2 =Dist2(pos(), ActiveCam.matrix.pos);
- return distance2<=Sqr (14);
- }
- Flt Chr::animateAlignFeet() // how much to align feet on to the ground, returns value 0..1 (0 disables feet aligning)
- {
- if(anim.fly<1-EPS_ANIM_BLEND) // don't align when flying
- {
- Flt strafe= (anim.stop_move)*( anim.straight_strafe),
- crouch=(1-(anim.stop_move)*(1-anim. stand_crouch))*Sat(anim.stand_crouch*10);
- Flt align=strafe;
- align =Lerp(align, 1.0f, crouch);
- align*=1-anim.fly;
- return align;
- }
- return 0;
- }
- /******************************************************************************/
- static void AlignFeet(Chr &chr, Flt step) // align character feet by 'step'=0..1 factor
- {
- if(step>EPS_ANIM_BLEND && chr.sac.toe_l>=0 && chr.sac.toe_r>=0)
- {
- Flt y = chr.ctrl.center().y-chr.ctrl.height()*0.5f, // get controller bottom Y position
- yl=(chr.skel.skeleton()->bones[chr.sac.toe_l].pos * chr.skel.bones[chr.sac.toe_l].matrix()).y, // get left foot bottom Y position
- yr=(chr.skel.skeleton()->bones[chr.sac.toe_r].pos * chr.skel.bones[chr.sac.toe_r].matrix()).y; // get right foot bottom Y position
- chr.skel.offset(Vec(0, (y-Min(yl, yr)+0.03f)*step, 0)); // offset the animation skeleton according to feet placement
- }
- }
- /******************************************************************************/
- void Chr::updateAnimationAnim() // update all 'Chr::anim' parameters
- {
- Bool set=(anim.stop_move==0.0f); // 'set' is a helper value for setting animation blending values (which are in range 0..1) immediately to 1
- Flt dt = Time.d()*anim.speed ; // animations time delta
- // optimizations
- {
- Bool disable;
- // disable fingers animations
- disable=(animateFingers()==0);
- skel.disable (sac.toe_l , disable);
- skel.disable (sac.toe_r , disable);
- skel.disableChildren(sac.hand_l, disable);
- skel.disableChildren(sac.hand_r, disable);
- // disable facial animations
- disable=(animateFaceBlend()<=0);
- skel.disableChildren(sac.head, disable);
- }
- // turn
- {
- AdjustValBool(anim.b_turn_l, input.turn.x>0 && !ctrl.flying(), Time.d()*15, Time.d()*4);
- AdjustValBool(anim.b_turn_r, input.turn.x<0 && !ctrl.flying(), Time.d()*15, Time.d()*4);
- if(!anim.b_turn_l)anim.t_turn_l=0;else anim.t_turn_l+=Abs(input_turn.x)*Time.d();
- if(!anim.b_turn_r)anim.t_turn_r=0;else anim.t_turn_r+=Abs(input_turn.x)*Time.d();
- }
- // walk <-> run
- Bool running=false;
- if(input.move.x || input.move.z || (input.move.y && ctrl.flying()))
- {
- running=!(input.walk || input.crouch || ctrl.crouched());
- AdjustValBoolSet(anim.walk_run, running, set, Time.d()*6);
- }
- // forward <-> back
- if(input.move.z)
- {
- AdjustValBoolSet(anim.forward_back, input.move.z<0, set, Time.d()*4);
- }
- // strafe
- {
- AdjustValDir (anim.strafe_yaw , input.move.z*input.move.x*!ctrl.flying(), Time.d()*6);
- if(input.move.x )AdjustValBoolSet(anim.left_right , input.move.x==1 , set, Time.d()*6);
- if(input.move.x || input.move.z)AdjustValBoolSet(anim.straight_strafe, !input.move.z && input.move.x , set, Time.d()*6);
- }
- // stand <-> crouch
- AdjustValBool(anim.stand_crouch, input.crouch || ctrl.crouched(), Time.d()*2, Time.d()*1.5f);
- // stop <-> move
- AdjustValBool(anim.stop_move, (input.move.x || input.move.z) && !ctrl.flying(), Time.d()*6);
- // lean
- {
- Flt desired_lean=Mid(input_turn.x, -1.0f, 1.0f)*anim.stop_move*Lerp(0.035f, 0.12f, anim.walk_run)*!ctrl.flying();
- AdjustValTime(anim.lean, desired_lean, 0.000001f);
- }
- // flying
- {
- AdjustValTime(anim.fly, ctrl.flying(), 0.001f);
- if(anim.fly>EPS_ANIM_BLEND)
- {
- Bool fly_full_body=(input.move.z==1 && running);
- Flt desired_strafe=(fly_full_body ? input_move.x*PI_4 : 0),
- desired_x =(fly_full_body ? 0 : input_move.x*-0.3f ),
- desired_z =(fly_full_body ? (PI_2-0.2f)-Max(input_move.y, -0.5f)*PI_4 : input_move.z*0.3f); // use 'Max' to avoid "neck breaks"
- AdjustValTime(anim.fly_x , desired_x , 0.02f);
- AdjustValTime(anim.fly_z , desired_z , 0.02f);
- AdjustValTime(anim.fly_strafe , desired_strafe , 0.02f);
- AdjustValTime(anim.fly_full_body, fly_full_body , 0.02f);
- AdjustValTime(anim.fly_turn , fly_full_body ? input.turn.x*PI_6 : 0, 0.05f);
- }else
- {
- anim.fly_x =0;
- anim.fly_z =0;
- anim.fly_strafe =0;
- anim.fly_turn =0;
- anim.fly_full_body=0;
- }
- }
- if(set)anim.time =0 ;
- else anim.time+=dt;
- }
- /******************************************************************************/
- static Flt AnimTime(Chr &chr) // get global animation time for the character according to current time and character's 'unique' value
- {
- return Time.time()+chr.anim.unique*10;
- }
- void Chr::animate()
- {
- // animation blend values
- Flt b_stand = (1-anim.stand_crouch )*(1-anim.stop_move ),
- b_crc_stop= ( anim.stand_crouch )*(1-anim.stop_move ),
- b_crc_move= ( anim.stand_crouch )*( anim.stop_move ),
- b_turn_l = (1-anim.stand_crouch )*(1-anim.stop_move )*( anim.b_turn_l),
- b_turn_r = (1-anim.stand_crouch )*(1-anim.stop_move )*( anim.b_turn_r),
- b_walk = (1-anim.stand_crouch )*( anim.stop_move )*(1-anim.walk_run),
- b_run = (1-anim.stand_crouch )*( anim.stop_move )*( anim.walk_run),
- b_walk_z =b_walk *(1-anim.straight_strafe) ,
- b_run_z =b_run *(1-anim.straight_strafe) ,
- b_crc_z =b_crc_move*(1-anim.straight_strafe) ,
- b_walk_f =b_walk_z *(1-anim.forward_back ) ,
- b_walk_b =b_walk_z *( anim.forward_back ) ,
- b_run_f =b_run_z *(1-anim.forward_back ) ,
- b_run_b =b_run_z *( anim.forward_back ) ,
- b_crc_f =b_crc_z *(1-anim.forward_back ) ,
- b_crc_b =b_crc_z *( anim.forward_back ) ,
- b_crc_l =b_crc_move*( anim.straight_strafe)*(1-anim.left_right),
- b_crc_r =b_crc_move*( anim.straight_strafe)*( anim.left_right),
- b_walk_l =b_walk *( anim.straight_strafe)*(1-anim.left_right),
- b_walk_r =b_walk *( anim.straight_strafe)*( anim.left_right),
- b_run_l =b_run *( anim.straight_strafe)*(1-anim.left_right),
- b_run_r =b_run *( anim.straight_strafe)*( anim.left_right);
- b_turn_l=LerpSmoothPow(0, 1, b_turn_l, 2.5f);
- b_turn_r=LerpSmoothPow(0, 1, b_turn_r, 2.5f);
- // detect "step" sound (event when character foot landed on the ground while moving)
- if(ctrl.onGround() && anim.stop_move>0.25f)
- {
- Flt blend =0;
- SkelAnim *skel_anim=null;
- // find most significant movement animation
- if(b_crc_z >blend){blend=b_crc_z ; skel_anim=sac.crouch_f ;}
- if(b_walk_z>blend){blend=b_walk_z; skel_anim=sac.walk ;}
- if(b_run_z >blend){blend=b_run_z ; skel_anim=sac.run ;}
- if(b_crc_l >blend){blend=b_crc_l ; skel_anim=sac.crouch_l ;}
- if(b_crc_r >blend){blend=b_crc_r ; skel_anim=sac.crouch_r ;}
- if(b_walk_l>blend){blend=b_walk_l; skel_anim=sac.strafe_wl;}
- if(b_walk_r>blend){blend=b_walk_r; skel_anim=sac.strafe_wr;}
- if(b_run_l >blend){blend=b_run_l ; skel_anim=sac.strafe_l ;}
- if(b_run_r >blend){blend=b_run_r ; skel_anim=sac.strafe_r ;}
- // check if "step" event occurred
- if(skel_anim && blend>0.25f)
- {
- Flt dt=Time.d()*anim.speed;
- if(skel_anim->eventOccurred("step", anim.time-dt, dt))animateStepOccurred(); // anim.time was already updated before this method was called so we need to set it back (-dt)
- }
- }
- Flt time=AnimTime(T);
- // animate the skeleton
- skel.clear()
- .animate(sac.fist_r , time , 1)
- .animate(sac.fist_l , time , 1)
- .animate(sac.stand , time , b_stand)
- .animate(sac.crouch , time , b_crc_stop)
- .animate(sac.turn_l , anim.t_turn_l, b_turn_l, true)
- .animate(sac.turn_r , anim.t_turn_r, b_turn_r, true)
- .animate(sac.walk , anim.time , b_walk_f)
- .animate(sac.walk ,-anim.time , b_walk_b)
- .animate(sac.run , anim.time , b_run_f)
- .animate(sac.run ,-anim.time , b_run_b)
- .animate(sac.crouch_f , anim.time , b_crc_f)
- .animate(sac.crouch_f ,-anim.time , b_crc_b)
- .animate(sac.crouch_l , anim.time , b_crc_l)
- .animate(sac.crouch_r , anim.time , b_crc_r)
- .animate(sac.strafe_wl, anim.time , b_walk_l)
- .animate(sac.strafe_wr, anim.time , b_walk_r)
- .animate(sac.strafe_l , anim.time , b_run_l)
- .animate(sac.strafe_r , anim.time , b_run_r)
- .animate(sac.floating , time , anim.fly, true);
- if(dodging)skel.animate((dodging<0) ? sac.dodge_l : sac.dodge_r, 1-dodge_step, Sqrt(Sin(dodge_step*PI)), true);
- }
- /******************************************************************************/
- void Chr::updateAnimation()
- {
- updateAnimationAnim();
- // first animate using only basic animations (standing or crouching) to detect 'foot_offset' (it will be used to align the whole body matrix while crouching so that the foot will always be in constant position - "attached" to certain position on the ground)
- Bool use_foot_offset=false;
- Vec foot_offset;
- if(anim.fly<1-EPS_ANIM_BLEND // only when not flying
- && sac.toe_l>=0 // left foot was detected
- && anim.stand_crouch>EPS_ANIM_BLEND) // crouching
- {
- use_foot_offset=true;
- Flt time =AnimTime(T);
- Vec pos_foot=skel.skeleton()->bones[sac.toe_l].pos;
- skel.clear ();
- skel.animate(sac.stand , time, 1 ).updateMatrixParents(MatrixIdentity, sac.toe_l); foot_offset= pos_foot*skel.bones[sac.toe_l].matrix();
- skel.animate(sac.crouch, time, anim.stand_crouch, true).updateMatrixParents(MatrixIdentity, sac.toe_l); foot_offset=foot_offset-pos_foot*skel.bones[sac.toe_l].matrix(); foot_offset.y=0;
- }
- // set animations
- animate();
- // manually adjust body, neck and head bones (according to look angles, movement, ...)
- Int body_sign =((sac.body>=0) ? Sign(skel.skeleton()->bones[sac.body].perp.z) : 1);
- Flt body_pitch =angle.y*body_sign;
- body_pitch *=1-anim.fly_full_body*anim.fly; // when flying with full body, disable body pitch bending, and rotate main matrix instead
- Flt body_pitch_part=body_pitch/(4+anim.fly), // body_pitch rotation is split into 4 bones rotations (body,body_u,neck,head), when flying also the main matrix is used (making a total of 5 splits)
- head_neck_pitch=body_pitch_part + anim.fly*anim.fly_z*0.5f*body_sign; // add flying adjustment split into 2 bones
- {
- Flt body_roll =(-PI_4/4)*anim.strafe_yaw, // body roll is split into 4 bones (body, body_u, neck, head)
- head_neck_roll=body_roll;//-angle_head/2
- Vec v;
- Matrix3 m;
- // body
- v=skel.root.orn.cross(); if(!v.any())v.x=1; CHS(v.z); // body x-axis
- if(sac.body>=0){m.setRotate(v, body_pitch_part*-body_sign).rotateY(body_roll); skel.bones[sac.body].orn*=m;}
- // body_u
- if(sac.head>=0)
- {
- v=skel.bones[sac.head].orn.cross(); // lucky guess for upper bones rotation
- if(sac.body_u>=0){m.setRotate(v, body_pitch_part).rotateZ(body_roll); skel.bones[sac.body_u].orn*=m;}
-
- // neck + head
- m.setRotate(v, head_neck_pitch).rotateZ(head_neck_roll);
- if(sac.neck>=0)skel.bones[sac.neck].orn*=m;
- skel.bones[sac.head].orn*=m;
- skel.bones[sac.head].rot.axis.z-=anim.fly_strafe*anim.fly;
- }
- }
- // main matrix
- Matrix m;
- {
- Flt body_pitch_rest=body_pitch-4*body_pitch_part; // part of the 'body_pitch' which was left to set in the main matrix
- // orientation
- m.orn().setRotateY( anim.fly*anim.fly_turn + anim.strafe_yaw*PI_4)
- . rotateZ( anim.lean*(1-anim.straight_strafe) + anim.fly*(anim.fly_x - anim.fly_strafe ) )
- . rotateX( anim.lean*( anim.straight_strafe)*(anim.left_right*2-1) + anim.fly*(anim.fly_z - anim.fly_full_body*angle.y) + body_pitch_rest*-body_sign)
- . rotateY(-angle.x);
- // position
- m.pos =ctrl.actor.pos() ; // set initial position from the controller actor
- m.pos+=ctrl.shapeOffset() - ctrl.shapeOffset()*m.orn(); // this operation forces the custom 'm.orn' rotations to be done relative to the center of character controller
- if(use_foot_offset)
- {
- foot_offset*=m.orn();
- m.pos+=foot_offset;
- }
- // adjust legs flying fake movement
- if(anim.fly>EPS_ANIM_BLEND)
- {
- Vec vec =ctrl.actor.vel(); vec.y=-6;
- Flt angle =AbsAngleBetween(vec, Vec(0,-1,0));
- angle*=0.2f;
- angle =Log2(angle+1);
- angle*=(1-anim.fly_full_body)*anim.fly;
- if( angle>EPS)
- {
- MIN(angle, 0.4f);
- Vec axis=CrossN(vec, Vec(0,-1,0))/m.orn()*angle;
- if(sac.leg_lu>=0)skel.bones[sac.leg_lu].rot.axis+=axis;
- if(sac.leg_ru>=0)skel.bones[sac.leg_ru].rot.axis+=axis;
- if(axis.x>EPS)
- {
- if(sac.leg_ld>=0)skel.bones[sac.leg_ld].rot.axis.x+=axis.x;
- if(sac.leg_rd>=0)skel.bones[sac.leg_rd].rot.axis.x+=axis.x;
- }
- }
- }
- }
- // set the skeleton according to the matrix
- animateUpdateMatrix(m);
- // align feet
- AlignFeet(T, animateAlignFeet());
- // blend the ragdoll with the skeleton
- if(ragdoll_mode==RAGDOLL_PART)
- {
- Flt length=0.34f;
- ragdoll_time+=Time.d();
- if(ragdoll_time>=length)
- {
- ragdoll_mode=RAGDOLL_NONE;
- ragdoll.active(false);
- }else
- {
- Flt step =ragdoll_time/length,
- blend=1-step*step; if(step<0.1f)blend*=step/0.1f;
- ragdoll.toSkelBlend(skel, blend*0.45f);
- }
- }
- }
- /******************************************************************************/
- }}
- /******************************************************************************/
|