IK.cpp (32654B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #include "../idlib/precompiled.h" 30 #pragma hdrstop 31 32 #include "Game_local.h" 33 34 /* 35 =============================================================================== 36 37 idIK 38 39 =============================================================================== 40 */ 41 42 /* 43 ================ 44 idIK::idIK 45 ================ 46 */ 47 idIK::idIK() { 48 ik_activate = false; 49 initialized = false; 50 self = NULL; 51 animator = NULL; 52 modifiedAnim = 0; 53 modelOffset.Zero(); 54 } 55 56 /* 57 ================ 58 idIK::~idIK 59 ================ 60 */ 61 idIK::~idIK() { 62 } 63 64 /* 65 ================ 66 idIK::Save 67 ================ 68 */ 69 void idIK::Save( idSaveGame *savefile ) const { 70 savefile->WriteBool( initialized ); 71 savefile->WriteBool( ik_activate ); 72 savefile->WriteObject( self ); 73 savefile->WriteString( animator != NULL && animator->GetAnim( modifiedAnim ) ? animator->GetAnim( modifiedAnim )->Name() : "" ); 74 savefile->WriteVec3( modelOffset ); 75 } 76 77 /* 78 ================ 79 idIK::Restore 80 ================ 81 */ 82 void idIK::Restore( idRestoreGame *savefile ) { 83 idStr anim; 84 85 savefile->ReadBool( initialized ); 86 savefile->ReadBool( ik_activate ); 87 savefile->ReadObject( reinterpret_cast<idClass *&>( self ) ); 88 savefile->ReadString( anim ); 89 savefile->ReadVec3( modelOffset ); 90 91 if ( self ) { 92 animator = self->GetAnimator(); 93 if ( animator == NULL || animator->ModelDef() == NULL ) { 94 gameLocal.Warning( "idIK::Restore: IK for entity '%s' at (%s) has no model set.", 95 self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0) ); 96 return; 97 } 98 modifiedAnim = animator->GetAnim( anim ); 99 if ( modifiedAnim == 0 ) { 100 gameLocal.Warning( "idIK::Restore: IK for entity '%s' at (%s) has no modified animation.", 101 self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0) ); 102 } 103 } else { 104 animator = NULL; 105 modifiedAnim = 0; 106 } 107 } 108 109 /* 110 ================ 111 idIK::IsInitialized 112 ================ 113 */ 114 bool idIK::IsInitialized() const { 115 return initialized && ik_enable.GetBool(); 116 } 117 118 /* 119 ================ 120 idIK::Init 121 ================ 122 */ 123 bool idIK::Init( idEntity *self, const char *anim, const idVec3 &modelOffset ) { 124 idRenderModel *model; 125 126 if ( self == NULL ) { 127 return false; 128 } 129 130 this->self = self; 131 132 animator = self->GetAnimator(); 133 if ( animator == NULL || animator->ModelDef() == NULL ) { 134 gameLocal.Warning( "idIK::Init: IK for entity '%s' at (%s) has no model set.", 135 self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0) ); 136 return false; 137 } 138 if ( animator->ModelDef()->ModelHandle() == NULL ) { 139 gameLocal.Warning( "idIK::Init: IK for entity '%s' at (%s) uses default model.", 140 self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0) ); 141 return false; 142 } 143 model = animator->ModelHandle(); 144 if ( model == NULL ) { 145 gameLocal.Warning( "idIK::Init: IK for entity '%s' at (%s) has no model set.", 146 self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0) ); 147 return false; 148 } 149 modifiedAnim = animator->GetAnim( anim ); 150 if ( modifiedAnim == 0 ) { 151 gameLocal.Warning( "idIK::Init: IK for entity '%s' at (%s) has no modified animation.", 152 self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0) ); 153 return false; 154 } 155 156 this->modelOffset = modelOffset; 157 158 return true; 159 } 160 161 /* 162 ================ 163 idIK::Evaluate 164 ================ 165 */ 166 void idIK::Evaluate() { 167 } 168 169 /* 170 ================ 171 idIK::ClearJointMods 172 ================ 173 */ 174 void idIK::ClearJointMods() { 175 ik_activate = false; 176 } 177 178 /* 179 ================ 180 idIK::SolveTwoBones 181 ================ 182 */ 183 bool idIK::SolveTwoBones( const idVec3 &startPos, const idVec3 &endPos, const idVec3 &dir, float len0, float len1, idVec3 &jointPos ) { 184 float length, lengthSqr, lengthInv, x, y; 185 idVec3 vec0, vec1; 186 187 vec0 = endPos - startPos; 188 lengthSqr = vec0.LengthSqr(); 189 lengthInv = idMath::InvSqrt( lengthSqr ); 190 length = lengthInv * lengthSqr; 191 192 // if the start and end position are too far out or too close to each other 193 if ( length > len0 + len1 || length < idMath::Fabs( len0 - len1 ) ) { 194 jointPos = startPos + 0.5f * vec0; 195 return false; 196 } 197 198 vec0 *= lengthInv; 199 vec1 = dir - vec0 * dir * vec0; 200 vec1.Normalize(); 201 202 x = ( length * length + len0 * len0 - len1 * len1 ) * ( 0.5f * lengthInv ); 203 y = idMath::Sqrt( len0 * len0 - x * x ); 204 205 jointPos = startPos + x * vec0 + y * vec1; 206 207 return true; 208 } 209 210 /* 211 ================ 212 idIK::GetBoneAxis 213 ================ 214 */ 215 float idIK::GetBoneAxis( const idVec3 &startPos, const idVec3 &endPos, const idVec3 &dir, idMat3 &axis ) { 216 float length; 217 axis[0] = endPos - startPos; 218 length = axis[0].Normalize(); 219 axis[1] = dir - axis[0] * dir * axis[0]; 220 axis[1].Normalize(); 221 axis[2].Cross( axis[1], axis[0] ); 222 return length; 223 } 224 225 226 /* 227 =============================================================================== 228 229 idIK_Walk 230 231 =============================================================================== 232 */ 233 234 /* 235 ================ 236 idIK_Walk::idIK_Walk 237 ================ 238 */ 239 idIK_Walk::idIK_Walk() { 240 int i; 241 242 initialized = false; 243 footModel = NULL; 244 numLegs = 0; 245 enabledLegs = 0; 246 for ( i = 0; i < MAX_LEGS; i++ ) { 247 footJoints[i] = INVALID_JOINT; 248 ankleJoints[i] = INVALID_JOINT; 249 kneeJoints[i] = INVALID_JOINT; 250 hipJoints[i] = INVALID_JOINT; 251 dirJoints[i] = INVALID_JOINT; 252 hipForward[i].Zero(); 253 kneeForward[i].Zero(); 254 upperLegLength[i] = 0.0f; 255 lowerLegLength[i] = 0.0f; 256 upperLegToHipJoint[i].Identity(); 257 lowerLegToKneeJoint[i].Identity(); 258 oldAnkleHeights[i] = 0.0f; 259 } 260 waistJoint = INVALID_JOINT; 261 262 smoothing = 0.75f; 263 waistSmoothing = 0.5f; 264 footShift = 0.0f; 265 waistShift = 0.0f; 266 minWaistFloorDist = 0.0f; 267 minWaistAnkleDist = 0.0f; 268 footUpTrace = 32.0f; 269 footDownTrace = 32.0f; 270 tiltWaist = false; 271 usePivot = false; 272 273 pivotFoot = -1; 274 pivotYaw = 0.0f; 275 pivotPos.Zero(); 276 277 oldHeightsValid = false; 278 oldWaistHeight = 0.0f; 279 waistOffset.Zero(); 280 } 281 282 /* 283 ================ 284 idIK_Walk::~idIK_Walk 285 ================ 286 */ 287 idIK_Walk::~idIK_Walk() { 288 if ( footModel ) { 289 delete footModel; 290 } 291 } 292 293 /* 294 ================ 295 idIK_Walk::Save 296 ================ 297 */ 298 void idIK_Walk::Save( idSaveGame *savefile ) const { 299 int i; 300 301 idIK::Save( savefile ); 302 303 savefile->WriteClipModel( footModel ); 304 305 savefile->WriteInt( numLegs ); 306 savefile->WriteInt( enabledLegs ); 307 for ( i = 0; i < MAX_LEGS; i++ ) 308 savefile->WriteInt( footJoints[i] ); 309 for ( i = 0; i < MAX_LEGS; i++ ) 310 savefile->WriteInt( ankleJoints[i] ); 311 for ( i = 0; i < MAX_LEGS; i++ ) 312 savefile->WriteInt( kneeJoints[i] ); 313 for ( i = 0; i < MAX_LEGS; i++ ) 314 savefile->WriteInt( hipJoints[i] ); 315 for ( i = 0; i < MAX_LEGS; i++ ) 316 savefile->WriteInt( dirJoints[i] ); 317 savefile->WriteInt( waistJoint ); 318 319 for ( i = 0; i < MAX_LEGS; i++ ) 320 savefile->WriteVec3( hipForward[i] ); 321 for ( i = 0; i < MAX_LEGS; i++ ) 322 savefile->WriteVec3( kneeForward[i] ); 323 324 for ( i = 0; i < MAX_LEGS; i++ ) 325 savefile->WriteFloat( upperLegLength[i] ); 326 for ( i = 0; i < MAX_LEGS; i++ ) 327 savefile->WriteFloat( lowerLegLength[i] ); 328 329 for ( i = 0; i < MAX_LEGS; i++ ) 330 savefile->WriteMat3( upperLegToHipJoint[i] ); 331 for ( i = 0; i < MAX_LEGS; i++ ) 332 savefile->WriteMat3( lowerLegToKneeJoint[i] ); 333 334 savefile->WriteFloat( smoothing ); 335 savefile->WriteFloat( waistSmoothing ); 336 savefile->WriteFloat( footShift ); 337 savefile->WriteFloat( waistShift ); 338 savefile->WriteFloat( minWaistFloorDist ); 339 savefile->WriteFloat( minWaistAnkleDist ); 340 savefile->WriteFloat( footUpTrace ); 341 savefile->WriteFloat( footDownTrace ); 342 savefile->WriteBool( tiltWaist ); 343 savefile->WriteBool( usePivot ); 344 345 savefile->WriteInt( pivotFoot ); 346 savefile->WriteFloat( pivotYaw ); 347 savefile->WriteVec3( pivotPos ); 348 savefile->WriteBool( oldHeightsValid ); 349 savefile->WriteFloat( oldWaistHeight ); 350 for ( i = 0; i < MAX_LEGS; i++ ) { 351 savefile->WriteFloat( oldAnkleHeights[i] ); 352 } 353 savefile->WriteVec3( waistOffset ); 354 } 355 356 /* 357 ================ 358 idIK_Walk::Restore 359 ================ 360 */ 361 void idIK_Walk::Restore( idRestoreGame *savefile ) { 362 int i; 363 364 idIK::Restore( savefile ); 365 366 savefile->ReadClipModel( footModel ); 367 368 savefile->ReadInt( numLegs ); 369 savefile->ReadInt( enabledLegs ); 370 for ( i = 0; i < MAX_LEGS; i++ ) 371 savefile->ReadInt( (int&)footJoints[i] ); 372 for ( i = 0; i < MAX_LEGS; i++ ) 373 savefile->ReadInt( (int&)ankleJoints[i] ); 374 for ( i = 0; i < MAX_LEGS; i++ ) 375 savefile->ReadInt( (int&)kneeJoints[i] ); 376 for ( i = 0; i < MAX_LEGS; i++ ) 377 savefile->ReadInt( (int&)hipJoints[i] ); 378 for ( i = 0; i < MAX_LEGS; i++ ) 379 savefile->ReadInt( (int&)dirJoints[i] ); 380 savefile->ReadInt( (int&)waistJoint ); 381 382 for ( i = 0; i < MAX_LEGS; i++ ) 383 savefile->ReadVec3( hipForward[i] ); 384 for ( i = 0; i < MAX_LEGS; i++ ) 385 savefile->ReadVec3( kneeForward[i] ); 386 387 for ( i = 0; i < MAX_LEGS; i++ ) 388 savefile->ReadFloat( upperLegLength[i] ); 389 for ( i = 0; i < MAX_LEGS; i++ ) 390 savefile->ReadFloat( lowerLegLength[i] ); 391 392 for ( i = 0; i < MAX_LEGS; i++ ) 393 savefile->ReadMat3( upperLegToHipJoint[i] ); 394 for ( i = 0; i < MAX_LEGS; i++ ) 395 savefile->ReadMat3( lowerLegToKneeJoint[i] ); 396 397 savefile->ReadFloat( smoothing ); 398 savefile->ReadFloat( waistSmoothing ); 399 savefile->ReadFloat( footShift ); 400 savefile->ReadFloat( waistShift ); 401 savefile->ReadFloat( minWaistFloorDist ); 402 savefile->ReadFloat( minWaistAnkleDist ); 403 savefile->ReadFloat( footUpTrace ); 404 savefile->ReadFloat( footDownTrace ); 405 savefile->ReadBool( tiltWaist ); 406 savefile->ReadBool( usePivot ); 407 408 savefile->ReadInt( pivotFoot ); 409 savefile->ReadFloat( pivotYaw ); 410 savefile->ReadVec3( pivotPos ); 411 savefile->ReadBool( oldHeightsValid ); 412 savefile->ReadFloat( oldWaistHeight ); 413 for ( i = 0; i < MAX_LEGS; i++ ) { 414 savefile->ReadFloat( oldAnkleHeights[i] ); 415 } 416 savefile->ReadVec3( waistOffset ); 417 } 418 419 /* 420 ================ 421 idIK_Walk::Init 422 ================ 423 */ 424 bool idIK_Walk::Init( idEntity *self, const char *anim, const idVec3 &modelOffset ) { 425 int i; 426 float footSize; 427 idVec3 verts[4]; 428 idTraceModel trm; 429 const char *jointName; 430 idVec3 dir, ankleOrigin, kneeOrigin, hipOrigin, dirOrigin; 431 idMat3 axis, ankleAxis, kneeAxis, hipAxis; 432 433 static idVec3 footWinding[4] = { 434 idVec3( 1.0f, 1.0f, 0.0f ), 435 idVec3( -1.0f, 1.0f, 0.0f ), 436 idVec3( -1.0f, -1.0f, 0.0f ), 437 idVec3( 1.0f, -1.0f, 0.0f ) 438 }; 439 440 if ( !self ) { 441 return false; 442 } 443 444 numLegs = Min( self->spawnArgs.GetInt( "ik_numLegs", "0" ), MAX_LEGS ); 445 if ( numLegs == 0 ) { 446 return true; 447 } 448 449 if ( !idIK::Init( self, anim, modelOffset ) ) { 450 return false; 451 } 452 453 int numJoints = animator->NumJoints(); 454 idJointMat *joints = ( idJointMat * )_alloca16( numJoints * sizeof( joints[0] ) ); 455 456 // create the animation frame used to setup the IK 457 gameEdit->ANIM_CreateAnimFrame( animator->ModelHandle(), animator->GetAnim( modifiedAnim )->MD5Anim( 0 ), numJoints, joints, 1, animator->ModelDef()->GetVisualOffset() + modelOffset, animator->RemoveOrigin() ); 458 459 enabledLegs = 0; 460 461 // get all the joints 462 for ( i = 0; i < numLegs; i++ ) { 463 464 jointName = self->spawnArgs.GetString( va( "ik_foot%d", i+1 ) ); 465 footJoints[i] = animator->GetJointHandle( jointName ); 466 if ( footJoints[i] == INVALID_JOINT ) { 467 gameLocal.Error( "idIK_Walk::Init: invalid foot joint '%s'", jointName ); 468 } 469 470 jointName = self->spawnArgs.GetString( va( "ik_ankle%d", i+1 ) ); 471 ankleJoints[i] = animator->GetJointHandle( jointName ); 472 if ( ankleJoints[i] == INVALID_JOINT ) { 473 gameLocal.Error( "idIK_Walk::Init: invalid ankle joint '%s'", jointName ); 474 } 475 476 jointName = self->spawnArgs.GetString( va( "ik_knee%d", i+1 ) ); 477 kneeJoints[i] = animator->GetJointHandle( jointName ); 478 if ( kneeJoints[i] == INVALID_JOINT ) { 479 gameLocal.Error( "idIK_Walk::Init: invalid knee joint '%s'\n", jointName ); 480 } 481 482 jointName = self->spawnArgs.GetString( va( "ik_hip%d", i+1 ) ); 483 hipJoints[i] = animator->GetJointHandle( jointName ); 484 if ( hipJoints[i] == INVALID_JOINT ) { 485 gameLocal.Error( "idIK_Walk::Init: invalid hip joint '%s'\n", jointName ); 486 } 487 488 jointName = self->spawnArgs.GetString( va( "ik_dir%d", i+1 ) ); 489 dirJoints[i] = animator->GetJointHandle( jointName ); 490 491 enabledLegs |= 1 << i; 492 } 493 494 jointName = self->spawnArgs.GetString( "ik_waist" ); 495 waistJoint = animator->GetJointHandle( jointName ); 496 if ( waistJoint == INVALID_JOINT ) { 497 gameLocal.Error( "idIK_Walk::Init: invalid waist joint '%s'\n", jointName ); 498 } 499 500 // get the leg bone lengths and rotation matrices 501 for ( i = 0; i < numLegs; i++ ) { 502 oldAnkleHeights[i] = 0.0f; 503 504 ankleAxis = joints[ ankleJoints[ i ] ].ToMat3(); 505 ankleOrigin = joints[ ankleJoints[ i ] ].ToVec3(); 506 507 kneeAxis = joints[ kneeJoints[ i ] ].ToMat3(); 508 kneeOrigin = joints[ kneeJoints[ i ] ].ToVec3(); 509 510 hipAxis = joints[ hipJoints[ i ] ].ToMat3(); 511 hipOrigin = joints[ hipJoints[ i ] ].ToVec3(); 512 513 // get the IK direction 514 if ( dirJoints[i] != INVALID_JOINT ) { 515 dirOrigin = joints[ dirJoints[ i ] ].ToVec3(); 516 dir = dirOrigin - kneeOrigin; 517 } else { 518 dir.Set( 1.0f, 0.0f, 0.0f ); 519 } 520 521 hipForward[i] = dir * hipAxis.Transpose(); 522 kneeForward[i] = dir * kneeAxis.Transpose(); 523 524 // conversion from upper leg bone axis to hip joint axis 525 upperLegLength[i] = GetBoneAxis( hipOrigin, kneeOrigin, dir, axis ); 526 upperLegToHipJoint[i] = hipAxis * axis.Transpose(); 527 528 // conversion from lower leg bone axis to knee joint axis 529 lowerLegLength[i] = GetBoneAxis( kneeOrigin, ankleOrigin, dir, axis ); 530 lowerLegToKneeJoint[i] = kneeAxis * axis.Transpose(); 531 } 532 533 smoothing = self->spawnArgs.GetFloat( "ik_smoothing", "0.75" ); 534 waistSmoothing = self->spawnArgs.GetFloat( "ik_waistSmoothing", "0.75" ); 535 footShift = self->spawnArgs.GetFloat( "ik_footShift", "0" ); 536 waistShift = self->spawnArgs.GetFloat( "ik_waistShift", "0" ); 537 minWaistFloorDist = self->spawnArgs.GetFloat( "ik_minWaistFloorDist", "0" ); 538 minWaistAnkleDist = self->spawnArgs.GetFloat( "ik_minWaistAnkleDist", "0" ); 539 footUpTrace = self->spawnArgs.GetFloat( "ik_footUpTrace", "32" ); 540 footDownTrace = self->spawnArgs.GetFloat( "ik_footDownTrace", "32" ); 541 tiltWaist = self->spawnArgs.GetBool( "ik_tiltWaist", "0" ); 542 usePivot = self->spawnArgs.GetBool( "ik_usePivot", "0" ); 543 544 // setup a clip model for the feet 545 footSize = self->spawnArgs.GetFloat( "ik_footSize", "4" ) * 0.5f; 546 if ( footSize > 0.0f ) { 547 for ( i = 0; i < 4; i++ ) { 548 verts[i] = footWinding[i] * footSize; 549 } 550 trm.SetupPolygon( verts, 4 ); 551 footModel = new (TAG_PHYSICS_CLIP) idClipModel( trm ); 552 } 553 554 initialized = true; 555 556 return true; 557 } 558 559 /* 560 ================ 561 idIK_Walk::Evaluate 562 ================ 563 */ 564 void idIK_Walk::Evaluate() { 565 int i, newPivotFoot = -1; 566 float modelHeight, jointHeight, lowestHeight, floorHeights[MAX_LEGS]; 567 float shift, smallestShift, newHeight, step, newPivotYaw, height, largestAnkleHeight; 568 idVec3 modelOrigin, normal, hipDir, kneeDir, start, end, jointOrigins[MAX_LEGS]; 569 idVec3 footOrigin, ankleOrigin, kneeOrigin, hipOrigin, waistOrigin; 570 idMat3 modelAxis, waistAxis, axis; 571 idMat3 hipAxis[MAX_LEGS], kneeAxis[MAX_LEGS], ankleAxis[MAX_LEGS]; 572 trace_t results; 573 574 if ( !self || !gameLocal.isNewFrame ) { 575 return; 576 } 577 578 // if no IK enabled on any legs 579 if ( !enabledLegs ) { 580 return; 581 } 582 583 normal = - self->GetPhysics()->GetGravityNormal(); 584 modelOrigin = self->GetPhysics()->GetOrigin(); 585 modelAxis = self->GetRenderEntity()->axis; 586 modelHeight = modelOrigin * normal; 587 588 modelOrigin += modelOffset * modelAxis; 589 590 // create frame without joint mods 591 animator->CreateFrame( gameLocal.time, false ); 592 593 // get the joint positions for the feet 594 lowestHeight = idMath::INFINITY; 595 for ( i = 0; i < numLegs; i++ ) { 596 animator->GetJointTransform( footJoints[i], gameLocal.time, footOrigin, axis ); 597 jointOrigins[i] = modelOrigin + footOrigin * modelAxis; 598 jointHeight = jointOrigins[i] * normal; 599 if ( jointHeight < lowestHeight ) { 600 lowestHeight = jointHeight; 601 newPivotFoot = i; 602 } 603 } 604 605 if ( usePivot ) { 606 607 newPivotYaw = modelAxis[0].ToYaw(); 608 609 // change pivot foot 610 if ( newPivotFoot != pivotFoot || idMath::Fabs( idMath::AngleNormalize180( newPivotYaw - pivotYaw ) ) > 30.0f ) { 611 pivotFoot = newPivotFoot; 612 pivotYaw = newPivotYaw; 613 animator->GetJointTransform( footJoints[pivotFoot], gameLocal.time, footOrigin, axis ); 614 pivotPos = modelOrigin + footOrigin * modelAxis; 615 } 616 617 // keep pivot foot in place 618 jointOrigins[pivotFoot] = pivotPos; 619 } 620 621 // get the floor heights for the feet 622 for ( i = 0; i < numLegs; i++ ) { 623 624 if ( !( enabledLegs & ( 1 << i ) ) ) { 625 continue; 626 } 627 628 start = jointOrigins[i] + normal * footUpTrace; 629 end = jointOrigins[i] - normal * footDownTrace; 630 gameLocal.clip.Translation( results, start, end, footModel, mat3_identity, CONTENTS_SOLID|CONTENTS_IKCLIP, self ); 631 floorHeights[i] = results.endpos * normal; 632 633 if ( ik_debug.GetBool() && footModel ) { 634 idFixedWinding w; 635 for ( int j = 0; j < footModel->GetTraceModel()->numVerts; j++ ) { 636 w += footModel->GetTraceModel()->verts[j]; 637 } 638 gameRenderWorld->DebugWinding( colorRed, w, results.endpos, results.endAxis ); 639 } 640 } 641 642 const idPhysics *phys = self->GetPhysics(); 643 644 // test whether or not the character standing on the ground 645 bool onGround = phys->HasGroundContacts(); 646 647 // test whether or not the character is standing on a plat 648 bool onPlat = false; 649 for ( i = 0; i < phys->GetNumContacts(); i++ ) { 650 idEntity *ent = gameLocal.entities[ phys->GetContact( i ).entityNum ]; 651 if ( ent != NULL && ent->IsType( idPlat::Type ) ) { 652 onPlat = true; 653 break; 654 } 655 } 656 657 // adjust heights of the ankles 658 smallestShift = idMath::INFINITY; 659 largestAnkleHeight = -idMath::INFINITY; 660 for ( i = 0; i < numLegs; i++ ) { 661 662 if ( onGround && ( enabledLegs & ( 1 << i ) ) ) { 663 shift = floorHeights[i] - modelHeight + footShift; 664 } else { 665 shift = 0.0f; 666 } 667 668 if ( shift < smallestShift ) { 669 smallestShift = shift; 670 } 671 672 animator->GetJointTransform( ankleJoints[i], gameLocal.time, ankleOrigin, ankleAxis[i] ); 673 jointOrigins[i] = modelOrigin + ankleOrigin * modelAxis; 674 675 height = jointOrigins[i] * normal; 676 677 if ( oldHeightsValid && !onPlat ) { 678 step = height + shift - oldAnkleHeights[i]; 679 shift -= smoothing * step; 680 } 681 682 newHeight = height + shift; 683 if ( newHeight > largestAnkleHeight ) { 684 largestAnkleHeight = newHeight; 685 } 686 687 oldAnkleHeights[i] = newHeight; 688 689 jointOrigins[i] += shift * normal; 690 } 691 692 animator->GetJointTransform( waistJoint, gameLocal.time, waistOrigin, waistAxis ); 693 waistOrigin = modelOrigin + waistOrigin * modelAxis; 694 695 // adjust position of the waist 696 waistOffset = ( smallestShift + waistShift ) * normal; 697 698 // if the waist should be at least a certain distance above the floor 699 if ( minWaistFloorDist > 0.0f && waistOffset * normal < 0.0f ) { 700 start = waistOrigin; 701 end = waistOrigin + waistOffset - normal * minWaistFloorDist; 702 gameLocal.clip.Translation( results, start, end, footModel, modelAxis, CONTENTS_SOLID|CONTENTS_IKCLIP, self ); 703 height = ( waistOrigin + waistOffset - results.endpos ) * normal; 704 if ( height < minWaistFloorDist ) { 705 waistOffset += ( minWaistFloorDist - height ) * normal; 706 } 707 } 708 709 // if the waist should be at least a certain distance above the ankles 710 if ( minWaistAnkleDist > 0.0f ) { 711 height = ( waistOrigin + waistOffset ) * normal; 712 if ( height - largestAnkleHeight < minWaistAnkleDist ) { 713 waistOffset += ( minWaistAnkleDist - ( height - largestAnkleHeight ) ) * normal; 714 } 715 } 716 717 if ( oldHeightsValid ) { 718 // smoothly adjust height of waist 719 newHeight = ( waistOrigin + waistOffset ) * normal; 720 step = newHeight - oldWaistHeight; 721 waistOffset -= waistSmoothing * step * normal; 722 } 723 724 // save height of waist for smoothing 725 oldWaistHeight = ( waistOrigin + waistOffset ) * normal; 726 727 if ( !oldHeightsValid ) { 728 oldHeightsValid = true; 729 return; 730 } 731 732 // solve IK 733 for ( i = 0; i < numLegs; i++ ) { 734 735 // get the position of the hip in world space 736 animator->GetJointTransform( hipJoints[i], gameLocal.time, hipOrigin, axis ); 737 hipOrigin = modelOrigin + waistOffset + hipOrigin * modelAxis; 738 hipDir = hipForward[i] * axis * modelAxis; 739 740 // get the IK bend direction 741 animator->GetJointTransform( kneeJoints[i], gameLocal.time, kneeOrigin, axis ); 742 kneeDir = kneeForward[i] * axis * modelAxis; 743 744 // solve IK and calculate knee position 745 SolveTwoBones( hipOrigin, jointOrigins[i], kneeDir, upperLegLength[i], lowerLegLength[i], kneeOrigin ); 746 747 if ( ik_debug.GetBool() ) { 748 gameRenderWorld->DebugLine( colorCyan, hipOrigin, kneeOrigin ); 749 gameRenderWorld->DebugLine( colorRed, kneeOrigin, jointOrigins[i] ); 750 gameRenderWorld->DebugLine( colorYellow, kneeOrigin, kneeOrigin + hipDir ); 751 gameRenderWorld->DebugLine( colorGreen, kneeOrigin, kneeOrigin + kneeDir ); 752 } 753 754 // get the axis for the hip joint 755 GetBoneAxis( hipOrigin, kneeOrigin, hipDir, axis ); 756 hipAxis[i] = upperLegToHipJoint[i] * ( axis * modelAxis.Transpose() ); 757 758 // get the axis for the knee joint 759 GetBoneAxis( kneeOrigin, jointOrigins[i], kneeDir, axis ); 760 kneeAxis[i] = lowerLegToKneeJoint[i] * ( axis * modelAxis.Transpose() ); 761 } 762 763 // set the joint mods 764 animator->SetJointAxis( waistJoint, JOINTMOD_WORLD_OVERRIDE, waistAxis ); 765 animator->SetJointPos( waistJoint, JOINTMOD_WORLD_OVERRIDE, ( waistOrigin + waistOffset - modelOrigin ) * modelAxis.Transpose() ); 766 for ( i = 0; i < numLegs; i++ ) { 767 animator->SetJointAxis( hipJoints[i], JOINTMOD_WORLD_OVERRIDE, hipAxis[i] ); 768 animator->SetJointAxis( kneeJoints[i], JOINTMOD_WORLD_OVERRIDE, kneeAxis[i] ); 769 animator->SetJointAxis( ankleJoints[i], JOINTMOD_WORLD_OVERRIDE, ankleAxis[i] ); 770 } 771 772 ik_activate = true; 773 } 774 775 /* 776 ================ 777 idIK_Walk::ClearJointMods 778 ================ 779 */ 780 void idIK_Walk::ClearJointMods() { 781 int i; 782 783 if ( !self || !ik_activate ) { 784 return; 785 } 786 787 animator->SetJointAxis( waistJoint, JOINTMOD_NONE, mat3_identity ); 788 animator->SetJointPos( waistJoint, JOINTMOD_NONE, vec3_origin ); 789 for ( i = 0; i < numLegs; i++ ) { 790 animator->SetJointAxis( hipJoints[i], JOINTMOD_NONE, mat3_identity ); 791 animator->SetJointAxis( kneeJoints[i], JOINTMOD_NONE, mat3_identity ); 792 animator->SetJointAxis( ankleJoints[i], JOINTMOD_NONE, mat3_identity ); 793 } 794 795 ik_activate = false; 796 } 797 798 /* 799 ================ 800 idIK_Walk::EnableAll 801 ================ 802 */ 803 void idIK_Walk::EnableAll() { 804 enabledLegs = ( 1 << numLegs ) - 1; 805 oldHeightsValid = false; 806 } 807 808 /* 809 ================ 810 idIK_Walk::DisableAll 811 ================ 812 */ 813 void idIK_Walk::DisableAll() { 814 enabledLegs = 0; 815 oldHeightsValid = false; 816 } 817 818 /* 819 ================ 820 idIK_Walk::EnableLeg 821 ================ 822 */ 823 void idIK_Walk::EnableLeg( int num ) { 824 enabledLegs |= 1 << num; 825 } 826 827 /* 828 ================ 829 idIK_Walk::DisableLeg 830 ================ 831 */ 832 void idIK_Walk::DisableLeg( int num ) { 833 enabledLegs &= ~( 1 << num ); 834 } 835 836 837 /* 838 =============================================================================== 839 840 idIK_Reach 841 842 =============================================================================== 843 */ 844 845 /* 846 ================ 847 idIK_Reach::idIK_Reach 848 ================ 849 */ 850 idIK_Reach::idIK_Reach() { 851 int i; 852 853 initialized = false; 854 numArms = 0; 855 enabledArms = 0; 856 for ( i = 0; i < MAX_ARMS; i++ ) { 857 handJoints[i] = INVALID_JOINT; 858 elbowJoints[i] = INVALID_JOINT; 859 shoulderJoints[i] = INVALID_JOINT; 860 dirJoints[i] = INVALID_JOINT; 861 shoulderForward[i].Zero(); 862 elbowForward[i].Zero(); 863 upperArmLength[i] = 0.0f; 864 lowerArmLength[i] = 0.0f; 865 upperArmToShoulderJoint[i].Identity(); 866 lowerArmToElbowJoint[i].Identity(); 867 } 868 } 869 870 /* 871 ================ 872 idIK_Reach::~idIK_Reach 873 ================ 874 */ 875 idIK_Reach::~idIK_Reach() { 876 } 877 878 /* 879 ================ 880 idIK_Reach::Save 881 ================ 882 */ 883 void idIK_Reach::Save( idSaveGame *savefile ) const { 884 int i; 885 idIK::Save( savefile ); 886 887 savefile->WriteInt( numArms ); 888 savefile->WriteInt( enabledArms ); 889 for ( i = 0; i < MAX_ARMS; i++ ) 890 savefile->WriteInt( handJoints[i] ); 891 for ( i = 0; i < MAX_ARMS; i++ ) 892 savefile->WriteInt( elbowJoints[i] ); 893 for ( i = 0; i < MAX_ARMS; i++ ) 894 savefile->WriteInt( shoulderJoints[i] ); 895 for ( i = 0; i < MAX_ARMS; i++ ) 896 savefile->WriteInt( dirJoints[i] ); 897 898 for ( i = 0; i < MAX_ARMS; i++ ) 899 savefile->WriteVec3( shoulderForward[i] ); 900 for ( i = 0; i < MAX_ARMS; i++ ) 901 savefile->WriteVec3( elbowForward[i] ); 902 903 for ( i = 0; i < MAX_ARMS; i++ ) 904 savefile->WriteFloat( upperArmLength[i] ); 905 for ( i = 0; i < MAX_ARMS; i++ ) 906 savefile->WriteFloat( lowerArmLength[i] ); 907 908 for ( i = 0; i < MAX_ARMS; i++ ) 909 savefile->WriteMat3( upperArmToShoulderJoint[i] ); 910 for ( i = 0; i < MAX_ARMS; i++ ) 911 savefile->WriteMat3( lowerArmToElbowJoint[i] ); 912 } 913 914 /* 915 ================ 916 idIK_Reach::Restore 917 ================ 918 */ 919 void idIK_Reach::Restore( idRestoreGame *savefile ) { 920 int i; 921 idIK::Restore( savefile ); 922 923 savefile->ReadInt( numArms ); 924 savefile->ReadInt( enabledArms ); 925 for ( i = 0; i < MAX_ARMS; i++ ) 926 savefile->ReadInt( (int&)handJoints[i] ); 927 for ( i = 0; i < MAX_ARMS; i++ ) 928 savefile->ReadInt( (int&)elbowJoints[i] ); 929 for ( i = 0; i < MAX_ARMS; i++ ) 930 savefile->ReadInt( (int&)shoulderJoints[i] ); 931 for ( i = 0; i < MAX_ARMS; i++ ) 932 savefile->ReadInt( (int&)dirJoints[i] ); 933 934 for ( i = 0; i < MAX_ARMS; i++ ) 935 savefile->ReadVec3( shoulderForward[i] ); 936 for ( i = 0; i < MAX_ARMS; i++ ) 937 savefile->ReadVec3( elbowForward[i] ); 938 939 for ( i = 0; i < MAX_ARMS; i++ ) 940 savefile->ReadFloat( upperArmLength[i] ); 941 for ( i = 0; i < MAX_ARMS; i++ ) 942 savefile->ReadFloat( lowerArmLength[i] ); 943 944 for ( i = 0; i < MAX_ARMS; i++ ) 945 savefile->ReadMat3( upperArmToShoulderJoint[i] ); 946 for ( i = 0; i < MAX_ARMS; i++ ) 947 savefile->ReadMat3( lowerArmToElbowJoint[i] ); 948 } 949 950 /* 951 ================ 952 idIK_Reach::Init 953 ================ 954 */ 955 bool idIK_Reach::Init( idEntity *self, const char *anim, const idVec3 &modelOffset ) { 956 int i; 957 const char *jointName; 958 idTraceModel trm; 959 idVec3 dir, handOrigin, elbowOrigin, shoulderOrigin, dirOrigin; 960 idMat3 axis, handAxis, elbowAxis, shoulderAxis; 961 962 if ( !self ) { 963 return false; 964 } 965 966 numArms = Min( self->spawnArgs.GetInt( "ik_numArms", "0" ), MAX_ARMS ); 967 if ( numArms == 0 ) { 968 return true; 969 } 970 971 if ( !idIK::Init( self, anim, modelOffset ) ) { 972 return false; 973 } 974 975 int numJoints = animator->NumJoints(); 976 idJointMat *joints = ( idJointMat * )_alloca16( numJoints * sizeof( joints[0] ) ); 977 978 // create the animation frame used to setup the IK 979 gameEdit->ANIM_CreateAnimFrame( animator->ModelHandle(), animator->GetAnim( modifiedAnim )->MD5Anim( 0 ), numJoints, joints, 1, animator->ModelDef()->GetVisualOffset() + modelOffset, animator->RemoveOrigin() ); 980 981 enabledArms = 0; 982 983 // get all the joints 984 for ( i = 0; i < numArms; i++ ) { 985 986 jointName = self->spawnArgs.GetString( va( "ik_hand%d", i+1 ) ); 987 handJoints[i] = animator->GetJointHandle( jointName ); 988 if ( handJoints[i] == INVALID_JOINT ) { 989 gameLocal.Error( "idIK_Reach::Init: invalid hand joint '%s'", jointName ); 990 } 991 992 jointName = self->spawnArgs.GetString( va( "ik_elbow%d", i+1 ) ); 993 elbowJoints[i] = animator->GetJointHandle( jointName ); 994 if ( elbowJoints[i] == INVALID_JOINT ) { 995 gameLocal.Error( "idIK_Reach::Init: invalid elbow joint '%s'\n", jointName ); 996 } 997 998 jointName = self->spawnArgs.GetString( va( "ik_shoulder%d", i+1 ) ); 999 shoulderJoints[i] = animator->GetJointHandle( jointName ); 1000 if ( shoulderJoints[i] == INVALID_JOINT ) { 1001 gameLocal.Error( "idIK_Reach::Init: invalid shoulder joint '%s'\n", jointName ); 1002 } 1003 1004 jointName = self->spawnArgs.GetString( va( "ik_elbowDir%d", i+1 ) ); 1005 dirJoints[i] = animator->GetJointHandle( jointName ); 1006 1007 enabledArms |= 1 << i; 1008 } 1009 1010 // get the arm bone lengths and rotation matrices 1011 for ( i = 0; i < numArms; i++ ) { 1012 1013 handAxis = joints[ handJoints[ i ] ].ToMat3(); 1014 handOrigin = joints[ handJoints[ i ] ].ToVec3(); 1015 1016 elbowAxis = joints[ elbowJoints[ i ] ].ToMat3(); 1017 elbowOrigin = joints[ elbowJoints[ i ] ].ToVec3(); 1018 1019 shoulderAxis = joints[ shoulderJoints[ i ] ].ToMat3(); 1020 shoulderOrigin = joints[ shoulderJoints[ i ] ].ToVec3(); 1021 1022 // get the IK direction 1023 if ( dirJoints[i] != INVALID_JOINT ) { 1024 dirOrigin = joints[ dirJoints[ i ] ].ToVec3(); 1025 dir = dirOrigin - elbowOrigin; 1026 } else { 1027 dir.Set( -1.0f, 0.0f, 0.0f ); 1028 } 1029 1030 shoulderForward[i] = dir * shoulderAxis.Transpose(); 1031 elbowForward[i] = dir * elbowAxis.Transpose(); 1032 1033 // conversion from upper arm bone axis to should joint axis 1034 upperArmLength[i] = GetBoneAxis( shoulderOrigin, elbowOrigin, dir, axis ); 1035 upperArmToShoulderJoint[i] = shoulderAxis * axis.Transpose(); 1036 1037 // conversion from lower arm bone axis to elbow joint axis 1038 lowerArmLength[i] = GetBoneAxis( elbowOrigin, handOrigin, dir, axis ); 1039 lowerArmToElbowJoint[i] = elbowAxis * axis.Transpose(); 1040 } 1041 1042 initialized = true; 1043 1044 return true; 1045 } 1046 1047 /* 1048 ================ 1049 idIK_Reach::Evaluate 1050 ================ 1051 */ 1052 void idIK_Reach::Evaluate() { 1053 int i; 1054 idVec3 modelOrigin, shoulderOrigin, elbowOrigin, handOrigin, shoulderDir, elbowDir; 1055 idMat3 modelAxis, axis; 1056 idMat3 shoulderAxis[MAX_ARMS], elbowAxis[MAX_ARMS]; 1057 trace_t trace; 1058 1059 modelOrigin = self->GetRenderEntity()->origin; 1060 modelAxis = self->GetRenderEntity()->axis; 1061 1062 // solve IK 1063 for ( i = 0; i < numArms; i++ ) { 1064 1065 // get the position of the shoulder in world space 1066 animator->GetJointTransform( shoulderJoints[i], gameLocal.time, shoulderOrigin, axis ); 1067 shoulderOrigin = modelOrigin + shoulderOrigin * modelAxis; 1068 shoulderDir = shoulderForward[i] * axis * modelAxis; 1069 1070 // get the position of the hand in world space 1071 animator->GetJointTransform( handJoints[i], gameLocal.time, handOrigin, axis ); 1072 handOrigin = modelOrigin + handOrigin * modelAxis; 1073 1074 // get first collision going from shoulder to hand 1075 gameLocal.clip.TracePoint( trace, shoulderOrigin, handOrigin, CONTENTS_SOLID, self ); 1076 handOrigin = trace.endpos; 1077 1078 // get the IK bend direction 1079 animator->GetJointTransform( elbowJoints[i], gameLocal.time, elbowOrigin, axis ); 1080 elbowDir = elbowForward[i] * axis * modelAxis; 1081 1082 // solve IK and calculate elbow position 1083 SolveTwoBones( shoulderOrigin, handOrigin, elbowDir, upperArmLength[i], lowerArmLength[i], elbowOrigin ); 1084 1085 if ( ik_debug.GetBool() ) { 1086 gameRenderWorld->DebugLine( colorCyan, shoulderOrigin, elbowOrigin ); 1087 gameRenderWorld->DebugLine( colorRed, elbowOrigin, handOrigin ); 1088 gameRenderWorld->DebugLine( colorYellow, elbowOrigin, elbowOrigin + elbowDir ); 1089 gameRenderWorld->DebugLine( colorGreen, elbowOrigin, elbowOrigin + shoulderDir ); 1090 } 1091 1092 // get the axis for the shoulder joint 1093 GetBoneAxis( shoulderOrigin, elbowOrigin, shoulderDir, axis ); 1094 shoulderAxis[i] = upperArmToShoulderJoint[i] * ( axis * modelAxis.Transpose() ); 1095 1096 // get the axis for the elbow joint 1097 GetBoneAxis( elbowOrigin, handOrigin, elbowDir, axis ); 1098 elbowAxis[i] = lowerArmToElbowJoint[i] * ( axis * modelAxis.Transpose() ); 1099 } 1100 1101 for ( i = 0; i < numArms; i++ ) { 1102 animator->SetJointAxis( shoulderJoints[i], JOINTMOD_WORLD_OVERRIDE, shoulderAxis[i] ); 1103 animator->SetJointAxis( elbowJoints[i], JOINTMOD_WORLD_OVERRIDE, elbowAxis[i] ); 1104 } 1105 1106 ik_activate = true; 1107 } 1108 1109 /* 1110 ================ 1111 idIK_Reach::ClearJointMods 1112 ================ 1113 */ 1114 void idIK_Reach::ClearJointMods() { 1115 int i; 1116 1117 if ( !self || !ik_activate ) { 1118 return; 1119 } 1120 1121 for ( i = 0; i < numArms; i++ ) { 1122 animator->SetJointAxis( shoulderJoints[i], JOINTMOD_NONE, mat3_identity ); 1123 animator->SetJointAxis( elbowJoints[i], JOINTMOD_NONE, mat3_identity ); 1124 animator->SetJointAxis( handJoints[i], JOINTMOD_NONE, mat3_identity ); 1125 } 1126 1127 ik_activate = false; 1128 }