Character Animation.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace Game{
  5. /******************************************************************************/
  6. static SkelAnim* GetAnim(AnimatedSkeleton &anim_skel, C ObjectPtr &obj, CChar8 *anim)
  7. {
  8. if(obj)if(Param *param=obj->findParam(anim))return anim_skel.findSkelAnim(param->asID());
  9. return null;
  10. }
  11. void Chr::SkelAnimCache::set(AnimatedSkeleton &anim_skel, C ObjectPtr &obj)
  12. {
  13. // set default animations
  14. fist_l =GetAnim(anim_skel, obj, "anim fist left");
  15. fist_r =GetAnim(anim_skel, obj, "anim fist right");
  16. stand =GetAnim(anim_skel, obj, "anim stand");
  17. crouch =GetAnim(anim_skel, obj, "anim crouch");
  18. turn_l =GetAnim(anim_skel, obj, "anim turn left");
  19. turn_r =GetAnim(anim_skel, obj, "anim turn right");
  20. walk =GetAnim(anim_skel, obj, "anim walk");
  21. run =GetAnim(anim_skel, obj, "anim run");
  22. crouch_f =GetAnim(anim_skel, obj, "anim crouch forward");
  23. crouch_l =GetAnim(anim_skel, obj, "anim crouch left");
  24. crouch_r =GetAnim(anim_skel, obj, "anim crouch right");
  25. strafe_wl=GetAnim(anim_skel, obj, "anim walk left");
  26. strafe_wr=GetAnim(anim_skel, obj, "anim walk right");
  27. strafe_l =GetAnim(anim_skel, obj, "anim run left");
  28. strafe_r =GetAnim(anim_skel, obj, "anim run right");
  29. dodge_l =GetAnim(anim_skel, obj, "anim dodge left");
  30. dodge_r =GetAnim(anim_skel, obj, "anim dodge right");
  31. floating =GetAnim(anim_skel, obj, "anim float");
  32. // detect indexes of skeleton bones
  33. head =anim_skel.findBoneI(BONE_HEAD);
  34. neck =anim_skel.findBoneI(BONE_NECK);
  35. body =anim_skel.findBoneI(BONE_SPINE);
  36. arm_lu=anim_skel.findBoneI(BONE_UPPER_ARM, -1);
  37. arm_ru=anim_skel.findBoneI(BONE_UPPER_ARM, 0);
  38. arm_ld=anim_skel.findBoneI(BONE_FOREARM , -1);
  39. arm_rd=anim_skel.findBoneI(BONE_FOREARM , 0);
  40. leg_lu=anim_skel.findBoneI(BONE_UPPER_LEG, -1);
  41. leg_ru=anim_skel.findBoneI(BONE_UPPER_LEG, 0);
  42. leg_ld=anim_skel.findBoneI(BONE_LOWER_LEG, -1);
  43. leg_rd=anim_skel.findBoneI(BONE_LOWER_LEG, 0);
  44. hand_l=anim_skel.findBoneI(BONE_HAND , -1);
  45. hand_r=anim_skel.findBoneI(BONE_HAND , 0);
  46. toe_l =anim_skel.findBoneI(BONE_TOE , -1);
  47. toe_r =anim_skel.findBoneI(BONE_TOE , 0);
  48. if(C Skeleton *skel=anim_skel.skeleton())
  49. {
  50. 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
  51. body_u=anim_skel.findBoneI(BONE_SPINE, 0, (spines+1)/2); // chose spine bone in the middle
  52. }else body_u=-1;
  53. }
  54. /******************************************************************************/
  55. Flt Chr::animateFaceBlend() // facial animation blending value, dependent on distance from camera, returns value 0..1 (0 disables facial animation)
  56. {
  57. Flt distance =Dist2(pos(), ActiveCam.matrix.pos),
  58. full_blend_range=Sqr (3),
  59. no_blend_range=Sqr (4);
  60. return LerpRS(no_blend_range, full_blend_range, distance);
  61. }
  62. Bool Chr::animateFingers() // if animate hand/foot fingers, dependent on distance from camera, returns value true/false (false disables fingers animation)
  63. {
  64. Flt distance2 =Dist2(pos(), ActiveCam.matrix.pos);
  65. return distance2<=Sqr (14);
  66. }
  67. Flt Chr::animateAlignFeet() // how much to align feet on to the ground, returns value 0..1 (0 disables feet aligning)
  68. {
  69. if(anim.fly<1-EPS_ANIM_BLEND) // don't align when flying
  70. {
  71. Flt strafe= (anim.stop_move)*( anim.straight_strafe),
  72. crouch=(1-(anim.stop_move)*(1-anim. stand_crouch))*Sat(anim.stand_crouch*10);
  73. Flt align=strafe;
  74. align =Lerp(align, 1.0f, crouch);
  75. align*=1-anim.fly;
  76. return align;
  77. }
  78. return 0;
  79. }
  80. /******************************************************************************/
  81. static void AlignFeet(Chr &chr, Flt step) // align character feet by 'step'=0..1 factor
  82. {
  83. if(step>EPS_ANIM_BLEND && chr.sac.toe_l>=0 && chr.sac.toe_r>=0)
  84. {
  85. Flt y = chr.ctrl.center().y-chr.ctrl.height()*0.5f, // get controller bottom Y position
  86. 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
  87. 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
  88. chr.skel.offset(Vec(0, (y-Min(yl, yr)+0.03f)*step, 0)); // offset the animation skeleton according to feet placement
  89. }
  90. }
  91. /******************************************************************************/
  92. void Chr::updateAnimationAnim() // update all 'Chr::anim' parameters
  93. {
  94. 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
  95. Flt dt = Time.d()*anim.speed ; // animations time delta
  96. // optimizations
  97. {
  98. Bool disable;
  99. // disable fingers animations
  100. disable=(animateFingers()==0);
  101. skel.disable (sac.toe_l , disable);
  102. skel.disable (sac.toe_r , disable);
  103. skel.disableChildren(sac.hand_l, disable);
  104. skel.disableChildren(sac.hand_r, disable);
  105. // disable facial animations
  106. disable=(animateFaceBlend()<=0);
  107. skel.disableChildren(sac.head, disable);
  108. }
  109. // turn
  110. {
  111. AdjustValBool(anim.b_turn_l, input.turn.x>0 && !ctrl.flying(), Time.d()*15, Time.d()*4);
  112. AdjustValBool(anim.b_turn_r, input.turn.x<0 && !ctrl.flying(), Time.d()*15, Time.d()*4);
  113. if(!anim.b_turn_l)anim.t_turn_l=0;else anim.t_turn_l+=Abs(input_turn.x)*Time.d();
  114. if(!anim.b_turn_r)anim.t_turn_r=0;else anim.t_turn_r+=Abs(input_turn.x)*Time.d();
  115. }
  116. // walk <-> run
  117. Bool running=false;
  118. if(input.move.x || input.move.z || (input.move.y && ctrl.flying()))
  119. {
  120. running=!(input.walk || input.crouch || ctrl.crouched());
  121. AdjustValBoolSet(anim.walk_run, running, set, Time.d()*6);
  122. }
  123. // forward <-> back
  124. if(input.move.z)
  125. {
  126. AdjustValBoolSet(anim.forward_back, input.move.z<0, set, Time.d()*4);
  127. }
  128. // strafe
  129. {
  130. AdjustValDir (anim.strafe_yaw , input.move.z*input.move.x*!ctrl.flying(), Time.d()*6);
  131. if(input.move.x )AdjustValBoolSet(anim.left_right , input.move.x==1 , set, Time.d()*6);
  132. if(input.move.x || input.move.z)AdjustValBoolSet(anim.straight_strafe, !input.move.z && input.move.x , set, Time.d()*6);
  133. }
  134. // stand <-> crouch
  135. AdjustValBool(anim.stand_crouch, input.crouch || ctrl.crouched(), Time.d()*2, Time.d()*1.5f);
  136. // stop <-> move
  137. AdjustValBool(anim.stop_move, (input.move.x || input.move.z) && !ctrl.flying(), Time.d()*6);
  138. // lean
  139. {
  140. Flt desired_lean=Mid(input_turn.x, -1.0f, 1.0f)*anim.stop_move*Lerp(0.035f, 0.12f, anim.walk_run)*!ctrl.flying();
  141. AdjustValTime(anim.lean, desired_lean, 0.000001f);
  142. }
  143. // flying
  144. {
  145. AdjustValTime(anim.fly, ctrl.flying(), 0.001f);
  146. if(anim.fly>EPS_ANIM_BLEND)
  147. {
  148. Bool fly_full_body=(input.move.z==1 && running);
  149. Flt desired_strafe=(fly_full_body ? input_move.x*PI_4 : 0),
  150. desired_x =(fly_full_body ? 0 : input_move.x*-0.3f ),
  151. 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"
  152. AdjustValTime(anim.fly_x , desired_x , 0.02f);
  153. AdjustValTime(anim.fly_z , desired_z , 0.02f);
  154. AdjustValTime(anim.fly_strafe , desired_strafe , 0.02f);
  155. AdjustValTime(anim.fly_full_body, fly_full_body , 0.02f);
  156. AdjustValTime(anim.fly_turn , fly_full_body ? input.turn.x*PI_6 : 0, 0.05f);
  157. }else
  158. {
  159. anim.fly_x =0;
  160. anim.fly_z =0;
  161. anim.fly_strafe =0;
  162. anim.fly_turn =0;
  163. anim.fly_full_body=0;
  164. }
  165. }
  166. if(set)anim.time =0 ;
  167. else anim.time+=dt;
  168. }
  169. /******************************************************************************/
  170. static Flt AnimTime(Chr &chr) // get global animation time for the character according to current time and character's 'unique' value
  171. {
  172. return Time.time()+chr.anim.unique*10;
  173. }
  174. void Chr::animate()
  175. {
  176. // animation blend values
  177. Flt b_stand = (1-anim.stand_crouch )*(1-anim.stop_move ),
  178. b_crc_stop= ( anim.stand_crouch )*(1-anim.stop_move ),
  179. b_crc_move= ( anim.stand_crouch )*( anim.stop_move ),
  180. b_turn_l = (1-anim.stand_crouch )*(1-anim.stop_move )*( anim.b_turn_l),
  181. b_turn_r = (1-anim.stand_crouch )*(1-anim.stop_move )*( anim.b_turn_r),
  182. b_walk = (1-anim.stand_crouch )*( anim.stop_move )*(1-anim.walk_run),
  183. b_run = (1-anim.stand_crouch )*( anim.stop_move )*( anim.walk_run),
  184. b_walk_z =b_walk *(1-anim.straight_strafe) ,
  185. b_run_z =b_run *(1-anim.straight_strafe) ,
  186. b_crc_z =b_crc_move*(1-anim.straight_strafe) ,
  187. b_walk_f =b_walk_z *(1-anim.forward_back ) ,
  188. b_walk_b =b_walk_z *( anim.forward_back ) ,
  189. b_run_f =b_run_z *(1-anim.forward_back ) ,
  190. b_run_b =b_run_z *( anim.forward_back ) ,
  191. b_crc_f =b_crc_z *(1-anim.forward_back ) ,
  192. b_crc_b =b_crc_z *( anim.forward_back ) ,
  193. b_crc_l =b_crc_move*( anim.straight_strafe)*(1-anim.left_right),
  194. b_crc_r =b_crc_move*( anim.straight_strafe)*( anim.left_right),
  195. b_walk_l =b_walk *( anim.straight_strafe)*(1-anim.left_right),
  196. b_walk_r =b_walk *( anim.straight_strafe)*( anim.left_right),
  197. b_run_l =b_run *( anim.straight_strafe)*(1-anim.left_right),
  198. b_run_r =b_run *( anim.straight_strafe)*( anim.left_right);
  199. b_turn_l=LerpSmoothPow(0, 1, b_turn_l, 2.5f);
  200. b_turn_r=LerpSmoothPow(0, 1, b_turn_r, 2.5f);
  201. // detect "step" sound (event when character foot landed on the ground while moving)
  202. if(ctrl.onGround() && anim.stop_move>0.25f)
  203. {
  204. Flt blend =0;
  205. SkelAnim *skel_anim=null;
  206. // find most significant movement animation
  207. if(b_crc_z >blend){blend=b_crc_z ; skel_anim=sac.crouch_f ;}
  208. if(b_walk_z>blend){blend=b_walk_z; skel_anim=sac.walk ;}
  209. if(b_run_z >blend){blend=b_run_z ; skel_anim=sac.run ;}
  210. if(b_crc_l >blend){blend=b_crc_l ; skel_anim=sac.crouch_l ;}
  211. if(b_crc_r >blend){blend=b_crc_r ; skel_anim=sac.crouch_r ;}
  212. if(b_walk_l>blend){blend=b_walk_l; skel_anim=sac.strafe_wl;}
  213. if(b_walk_r>blend){blend=b_walk_r; skel_anim=sac.strafe_wr;}
  214. if(b_run_l >blend){blend=b_run_l ; skel_anim=sac.strafe_l ;}
  215. if(b_run_r >blend){blend=b_run_r ; skel_anim=sac.strafe_r ;}
  216. // check if "step" event occurred
  217. if(skel_anim && blend>0.25f)
  218. {
  219. Flt dt=Time.d()*anim.speed;
  220. 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)
  221. }
  222. }
  223. Flt time=AnimTime(T);
  224. // animate the skeleton
  225. skel.clear()
  226. .animate(sac.fist_r , time , 1)
  227. .animate(sac.fist_l , time , 1)
  228. .animate(sac.stand , time , b_stand)
  229. .animate(sac.crouch , time , b_crc_stop)
  230. .animate(sac.turn_l , anim.t_turn_l, b_turn_l, true)
  231. .animate(sac.turn_r , anim.t_turn_r, b_turn_r, true)
  232. .animate(sac.walk , anim.time , b_walk_f)
  233. .animate(sac.walk ,-anim.time , b_walk_b)
  234. .animate(sac.run , anim.time , b_run_f)
  235. .animate(sac.run ,-anim.time , b_run_b)
  236. .animate(sac.crouch_f , anim.time , b_crc_f)
  237. .animate(sac.crouch_f ,-anim.time , b_crc_b)
  238. .animate(sac.crouch_l , anim.time , b_crc_l)
  239. .animate(sac.crouch_r , anim.time , b_crc_r)
  240. .animate(sac.strafe_wl, anim.time , b_walk_l)
  241. .animate(sac.strafe_wr, anim.time , b_walk_r)
  242. .animate(sac.strafe_l , anim.time , b_run_l)
  243. .animate(sac.strafe_r , anim.time , b_run_r)
  244. .animate(sac.floating , time , anim.fly, true);
  245. if(dodging)skel.animate((dodging<0) ? sac.dodge_l : sac.dodge_r, 1-dodge_step, Sqrt(Sin(dodge_step*PI)), true);
  246. }
  247. /******************************************************************************/
  248. void Chr::updateAnimation()
  249. {
  250. updateAnimationAnim();
  251. // 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)
  252. Bool use_foot_offset=false;
  253. Vec foot_offset;
  254. if(anim.fly<1-EPS_ANIM_BLEND // only when not flying
  255. && sac.toe_l>=0 // left foot was detected
  256. && anim.stand_crouch>EPS_ANIM_BLEND) // crouching
  257. {
  258. use_foot_offset=true;
  259. Flt time =AnimTime(T);
  260. Vec pos_foot=skel.skeleton()->bones[sac.toe_l].pos;
  261. skel.clear ();
  262. skel.animate(sac.stand , time, 1 ).updateMatrixParents(MatrixIdentity, sac.toe_l); foot_offset= pos_foot*skel.bones[sac.toe_l].matrix();
  263. 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;
  264. }
  265. // set animations
  266. animate();
  267. // manually adjust body, neck and head bones (according to look angles, movement, ...)
  268. Int body_sign =((sac.body>=0) ? Sign(skel.skeleton()->bones[sac.body].perp.z) : 1);
  269. Flt body_pitch =angle.y*body_sign;
  270. body_pitch *=1-anim.fly_full_body*anim.fly; // when flying with full body, disable body pitch bending, and rotate main matrix instead
  271. 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)
  272. head_neck_pitch=body_pitch_part + anim.fly*anim.fly_z*0.5f*body_sign; // add flying adjustment split into 2 bones
  273. {
  274. Flt body_roll =(-PI_4/4)*anim.strafe_yaw, // body roll is split into 4 bones (body, body_u, neck, head)
  275. head_neck_roll=body_roll;//-angle_head/2
  276. Vec v;
  277. Matrix3 m;
  278. // body
  279. v=skel.root.orn.cross(); if(!v.any())v.x=1; CHS(v.z); // body x-axis
  280. if(sac.body>=0){m.setRotate(v, body_pitch_part*-body_sign).rotateY(body_roll); skel.bones[sac.body].orn*=m;}
  281. // body_u
  282. if(sac.head>=0)
  283. {
  284. v=skel.bones[sac.head].orn.cross(); // lucky guess for upper bones rotation
  285. if(sac.body_u>=0){m.setRotate(v, body_pitch_part).rotateZ(body_roll); skel.bones[sac.body_u].orn*=m;}
  286. // neck + head
  287. m.setRotate(v, head_neck_pitch).rotateZ(head_neck_roll);
  288. if(sac.neck>=0)skel.bones[sac.neck].orn*=m;
  289. skel.bones[sac.head].orn*=m;
  290. skel.bones[sac.head].rot.axis.z-=anim.fly_strafe*anim.fly;
  291. }
  292. }
  293. // main matrix
  294. Matrix m;
  295. {
  296. Flt body_pitch_rest=body_pitch-4*body_pitch_part; // part of the 'body_pitch' which was left to set in the main matrix
  297. // orientation
  298. m.orn().setRotateY( anim.fly*anim.fly_turn + anim.strafe_yaw*PI_4)
  299. . rotateZ( anim.lean*(1-anim.straight_strafe) + anim.fly*(anim.fly_x - anim.fly_strafe ) )
  300. . 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)
  301. . rotateY(-angle.x);
  302. // position
  303. m.pos =ctrl.actor.pos() ; // set initial position from the controller actor
  304. 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
  305. if(use_foot_offset)
  306. {
  307. foot_offset*=m.orn();
  308. m.pos+=foot_offset;
  309. }
  310. // adjust legs flying fake movement
  311. if(anim.fly>EPS_ANIM_BLEND)
  312. {
  313. Vec vec =ctrl.actor.vel(); vec.y=-6;
  314. Flt angle =AbsAngleBetween(vec, Vec(0,-1,0));
  315. angle*=0.2f;
  316. angle =Log2(angle+1);
  317. angle*=(1-anim.fly_full_body)*anim.fly;
  318. if( angle>EPS)
  319. {
  320. MIN(angle, 0.4f);
  321. Vec axis=CrossN(vec, Vec(0,-1,0))/m.orn()*angle;
  322. if(sac.leg_lu>=0)skel.bones[sac.leg_lu].rot.axis+=axis;
  323. if(sac.leg_ru>=0)skel.bones[sac.leg_ru].rot.axis+=axis;
  324. if(axis.x>EPS)
  325. {
  326. if(sac.leg_ld>=0)skel.bones[sac.leg_ld].rot.axis.x+=axis.x;
  327. if(sac.leg_rd>=0)skel.bones[sac.leg_rd].rot.axis.x+=axis.x;
  328. }
  329. }
  330. }
  331. }
  332. // set the skeleton according to the matrix
  333. animateUpdateMatrix(m);
  334. // align feet
  335. AlignFeet(T, animateAlignFeet());
  336. // blend the ragdoll with the skeleton
  337. if(ragdoll_mode==RAGDOLL_PART)
  338. {
  339. Flt length=0.34f;
  340. ragdoll_time+=Time.d();
  341. if(ragdoll_time>=length)
  342. {
  343. ragdoll_mode=RAGDOLL_NONE;
  344. ragdoll.active(false);
  345. }else
  346. {
  347. Flt step =ragdoll_time/length,
  348. blend=1-step*step; if(step<0.1f)blend*=step/0.1f;
  349. ragdoll.toSkelBlend(skel, blend*0.45f);
  350. }
  351. }
  352. }
  353. /******************************************************************************/
  354. }}
  355. /******************************************************************************/