Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

897 lines
28 KiB

  1. //============ Copyright (c) Valve Corporation, All rights reserved. ============
  2. //
  3. // Routines used for various prodcedural bones but meant to be called from
  4. // datamodel or maya as well
  5. //
  6. // In a separate source file so linking bonesetup.lib doesn't get more than
  7. // needed
  8. //
  9. //===============================================================================
  10. // Valve includes
  11. #include "mathlib/mathlib.h"
  12. #include "mathlib/vector.h"
  13. #include "tier1/strtools.h"
  14. #include "bone_setup.h"
  15. #include "bone_constraints.h"
  16. #include "bone_accessor.h"
  17. #include "studio.h"
  18. #include "tier0/tslist.h"
  19. #include "tier0/miniprofiler.h"
  20. #include "bone_utils.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. //=============================================================================
  24. //=============================================================================
  25. //
  26. // CConstraintBones
  27. //
  28. //=============================================================================
  29. //=============================================================================
  30. //-----------------------------------------------------------------------------
  31. // Compute the aggregate target position and orientation from the weighted target list and return
  32. // the resulting position and orientation in addition to updating the target dag.
  33. // All passed arrays must be nTargetCount in length
  34. //-----------------------------------------------------------------------------
  35. float CConstraintBones::ComputeTargetPosition(
  36. Vector &vTargetPosition,
  37. int nTargetCount,
  38. float *flTargetWeights,
  39. Vector *vTargetPositions,
  40. Vector *vTargetOffsets )
  41. {
  42. vTargetPosition = vec3_origin;
  43. float flWeightSum = 0.0;
  44. for ( int i = 0; i < nTargetCount; ++i )
  45. {
  46. vTargetPosition += ( flTargetWeights[i] * ( vTargetPositions[i] + vTargetOffsets[i] ) );
  47. flWeightSum += flTargetWeights[i];
  48. }
  49. if ( flWeightSum > 0.0f )
  50. {
  51. vTargetPosition *= 1.0f / flWeightSum;
  52. }
  53. return MIN( 1.0f, flWeightSum );
  54. }
  55. //-----------------------------------------------------------------------------
  56. // Compute the aggregate target orientation from the weighted target list and
  57. // return the total weight
  58. // All passed arrays must be nTargetCount in length
  59. //-----------------------------------------------------------------------------
  60. float CConstraintBones::ComputeTargetOrientation(
  61. Quaternion &qTargetOrientation,
  62. int nTargetCount,
  63. float *pflTargetWeights,
  64. Quaternion *pqTargetOrientations,
  65. Quaternion *pqTargetOffsets )
  66. {
  67. // If there is only one target, for efficiency don't bother with the weighting
  68. if ( nTargetCount == 1 )
  69. {
  70. QuaternionMult( pqTargetOrientations[0], pqTargetOffsets[0], qTargetOrientation );
  71. return MIN( 1.0f, pflTargetWeights[0] );
  72. }
  73. qTargetOrientation = quat_identity;
  74. // If no targets, return identity quaternion and weight of 0
  75. if ( nTargetCount <= 0 )
  76. return 0.0f;
  77. Quaternion *pQuats = reinterpret_cast< Quaternion * >( stackalloc( nTargetCount * sizeof( Quaternion ) ) );
  78. float flWeightSum = 0.0f;
  79. for ( int i = 0; i < nTargetCount; ++i )
  80. {
  81. QuaternionMult( pqTargetOrientations[i], pqTargetOffsets[i], pQuats[i] );
  82. flWeightSum += pflTargetWeights[i];
  83. }
  84. QuaternionAverageExponential( qTargetOrientation, nTargetCount, pQuats, pflTargetWeights );
  85. return MIN( 1.0f, flWeightSum );
  86. }
  87. //-----------------------------------------------------------------------------
  88. // Compute the aggregate target position and orientation from the weighted
  89. // target list and return the total weight
  90. // All passed arrays must be nTargetCount in length
  91. //-----------------------------------------------------------------------------
  92. float CConstraintBones::ComputeTargetPositionOrientation(
  93. Vector &vTargetPosition,
  94. Quaternion &qTargetOrientation,
  95. int nTargetCount,
  96. float *pflTargetWeights,
  97. Vector *pvTargetPositions,
  98. Vector *pvTargetOffsets,
  99. Quaternion *pqTargetOrientations,
  100. Quaternion *pqTargetOffsets )
  101. {
  102. Quaternion *pQuats = reinterpret_cast< Quaternion *>( stackalloc( nTargetCount * sizeof( Quaternion ) ) );
  103. float flWeightSum = 0.0f;
  104. vTargetPosition = vec3_origin;
  105. qTargetOrientation = quat_identity;
  106. for ( int i = 0; i < nTargetCount; ++i )
  107. {
  108. float flWeight = pflTargetWeights[i];
  109. matrix3x4a_t mTarget;
  110. AngleMatrix( RadianEuler(pqTargetOrientations[i]), pvTargetPositions[i], mTarget );
  111. matrix3x4a_t mOffset;
  112. AngleMatrix( RadianEuler(pqTargetOffsets[i]), pvTargetOffsets[i], mOffset );
  113. matrix3x4a_t mAbs;
  114. ConcatTransforms( mTarget, mOffset, mAbs );
  115. Vector vPos;
  116. MatrixAngles( mAbs, pQuats[i], vPos );
  117. vTargetPosition += ( flWeight * vPos );
  118. // For normalization
  119. flWeightSum += flWeight;
  120. }
  121. if ( flWeightSum > 0.0f )
  122. {
  123. vTargetPosition *= 1.0f / flWeightSum;
  124. }
  125. QuaternionAverageExponential( qTargetOrientation, nTargetCount, pQuats, pflTargetWeights );
  126. return MIN( 1.0f, flWeightSum );
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Compute the aggregate target position and orientation from the weighted
  130. // target list and return the total weight
  131. // All passed arrays must be nTargetCount in length
  132. //-----------------------------------------------------------------------------
  133. float CConstraintBones::ComputeTargetPositionOrientation(
  134. Vector &vTargetPosition,
  135. Quaternion &qTargetOrientation,
  136. int nTargetCount,
  137. float *pflTargetWeights,
  138. matrix3x4a_t *pmTargets,
  139. matrix3x4a_t *pmOffsets )
  140. {
  141. Quaternion *pQuats = reinterpret_cast< Quaternion *>( stackalloc( nTargetCount * sizeof( Quaternion ) ) );
  142. float flWeightSum = 0.0f;
  143. vTargetPosition = vec3_origin;
  144. qTargetOrientation = quat_identity;
  145. matrix3x4a_t mAbs;
  146. Vector vPos;
  147. for ( int i = 0; i < nTargetCount; ++i )
  148. {
  149. float flWeight = pflTargetWeights[i];
  150. ConcatTransforms( pmTargets[i], pmOffsets[i], mAbs );
  151. MatrixAngles( mAbs, pQuats[i], vPos );
  152. vTargetPosition += ( flWeight * vPos );
  153. // For normalization
  154. flWeightSum += flWeight;
  155. }
  156. if ( flWeightSum > 0.0f )
  157. {
  158. vTargetPosition *= 1.0f / flWeightSum;
  159. }
  160. QuaternionAverageExponential( qTargetOrientation, nTargetCount, pQuats, pflTargetWeights );
  161. return MIN( 1.0f, flWeightSum );
  162. }
  163. //-----------------------------------------------------------------------------
  164. //
  165. //-----------------------------------------------------------------------------
  166. void CConstraintBones::ComputeAimConstraintOffset(
  167. Quaternion &qAimOffset,
  168. bool bPreserveOffset,
  169. const Vector &vTargetWorldPos,
  170. const matrix3x4_t &mSlaveParentToWorld,
  171. const Vector &vUp,
  172. const Vector &vSlaveLocalPos,
  173. const Quaternion &qSlaveLocal,
  174. matrix3x4_t *pmUpToWorld,
  175. AimConstraintUpType_t eUpType )
  176. {
  177. if ( !bPreserveOffset )
  178. {
  179. qAimOffset = quat_identity;
  180. return;
  181. }
  182. // Calculate the desired orientation based the target position
  183. Quaternion qAim;
  184. ComputeAimConstraint( qAim, vTargetWorldPos, mSlaveParentToWorld, vUp, vSlaveLocalPos, pmUpToWorld, eUpType );
  185. // Compute the difference between the slave's current orientation and the target orientation
  186. Quaternion qAimInv;
  187. QuaternionInvert( qAim, qAimInv );
  188. QuaternionMult( qAimInv, qSlaveLocal, qAimOffset );
  189. RadianEuler eAim(qAim);
  190. RadianEuler eSlaveLocal(qSlaveLocal);
  191. RadianEuler eAimOffset(qAimOffset);
  192. }
  193. //-----------------------------------------------------------------------------
  194. // Calculate the orientation needed to make a transform where the y
  195. // vector of the transform matches the forward vector and the z vector matches
  196. // the up reference vector as closely as possible. The x vector will be in the
  197. // plane defined by using the forward vector as the normal.
  198. //-----------------------------------------------------------------------------
  199. void CConstraintBones::ComputeAimConstraintAimAt(
  200. Quaternion &qAim,
  201. const Vector &vForward,
  202. const Vector &vReferenceUp )
  203. {
  204. Vector vFwd = vForward;
  205. vFwd.NormalizeInPlace();
  206. const float flRatio = DotProduct( vFwd, vReferenceUp );
  207. Vector vUp = vReferenceUp - ( vFwd * flRatio );
  208. vUp.NormalizeInPlace();
  209. Vector vRight = vFwd.Cross( vUp );
  210. vRight.NormalizeInPlace();
  211. const Vector &vX = vRight;
  212. const Vector &vY = vFwd;
  213. const Vector &vZ = vUp;
  214. const float flTr = vX.x + vY.y + vZ.z;
  215. qAim.Init( vY.z - vZ.y , vZ.x - vX.z, vX.y - vY.x, flTr + 1.0f );
  216. const float flRadius = qAim[0] * qAim[0] + qAim[1] * qAim[1] + qAim[2] * qAim[2] + qAim[3] * qAim[3];
  217. if ( flRadius > FLT_EPSILON )
  218. {
  219. QuaternionNormalize( qAim );
  220. }
  221. else
  222. {
  223. matrix3x4_t mRot;
  224. MatrixSetColumn( vX, 0, mRot );
  225. MatrixSetColumn( vY, 1, mRot );
  226. MatrixSetColumn( vZ, 2, mRot );
  227. MatrixQuaternion( mRot, qAim );
  228. }
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Given the various parameters, computes the local vForward & vReferenceUp
  232. // and calls ComputeAimConstraintAimAt
  233. //-----------------------------------------------------------------------------
  234. void CConstraintBones::ComputeAimConstraint(
  235. Quaternion &qAim,
  236. const Vector &vTargetWorldPos,
  237. const matrix3x4_t &mParentToWorld,
  238. const Vector &vUp,
  239. const Vector &vSlaveLocalPos,
  240. const matrix3x4_t *pmUpToWorld,
  241. AimConstraintUpType_t eUpType )
  242. {
  243. matrix3x4_t mWorldToParent;
  244. MatrixInvert( mParentToWorld, mWorldToParent );
  245. // If the up vector is in world space, convert it into local space
  246. Vector vWorldUp;
  247. ComputeWorldUpVector( &vWorldUp, mParentToWorld, vUp, vSlaveLocalPos, pmUpToWorld, eUpType );
  248. Vector vLocalUp;
  249. VectorRotate( vWorldUp, mWorldToParent, vLocalUp );
  250. // Convert the target's world space position into the local space of the slave.
  251. Vector vTargetLocalPos;
  252. VectorTransform( vTargetWorldPos, mWorldToParent, vTargetLocalPos );
  253. // Compute the local space forward vector
  254. Vector vLocalForward = vTargetLocalPos - vSlaveLocalPos;
  255. vLocalForward.NormalizeInPlace();
  256. // Compute the orientation
  257. CConstraintBones::ComputeAimConstraintAimAt( qAim, vLocalForward, vLocalUp );
  258. RadianEuler e(qAim);
  259. }
  260. //-----------------------------------------------------------------------------
  261. //
  262. //-----------------------------------------------------------------------------
  263. void CConstraintBones::ComputeWorldUpVector(
  264. Vector *pvWorldUp,
  265. const matrix3x4_t & mParentToWorld,
  266. const Vector &vUp,
  267. const Vector &vSlaveLocalPos,
  268. const matrix3x4_t *pmUpToWorld,
  269. AimConstraintUpType_t eUpType )
  270. {
  271. switch ( eUpType )
  272. {
  273. case AC_UP_TYPE_VECTOR:
  274. VectorCopy( vUp, *pvWorldUp );
  275. break;
  276. case AC_UP_TYPE_OBJECT:
  277. if ( pmUpToWorld )
  278. {
  279. Vector vUpObjectWorldPos;
  280. MatrixPosition( *pmUpToWorld, vUpObjectWorldPos );
  281. Vector vSlaveWorldPos;
  282. VectorTransform( vSlaveLocalPos, mParentToWorld, vSlaveWorldPos );
  283. VectorSubtract( vUpObjectWorldPos, vSlaveWorldPos, *pvWorldUp );
  284. VectorNormalize( *pvWorldUp );
  285. }
  286. else
  287. {
  288. VectorCopy( vUp, *pvWorldUp );
  289. }
  290. break;
  291. case AC_UP_TYPE_PARENT_ROTATION:
  292. VectorRotate( vUp, mParentToWorld, *pvWorldUp );
  293. break;
  294. default:
  295. case AC_UP_TYPE_OBJECT_ROTATION:
  296. if ( pmUpToWorld )
  297. {
  298. VectorRotate( vUp, *pmUpToWorld, *pvWorldUp );
  299. }
  300. else
  301. {
  302. VectorCopy( vUp, *pvWorldUp );
  303. }
  304. break;
  305. }
  306. }
  307. //=============================================================================
  308. //=============================================================================
  309. //
  310. // CStudioConstraintBones
  311. //
  312. //=============================================================================
  313. //=============================================================================
  314. //-----------------------------------------------------------------------------
  315. //
  316. //-----------------------------------------------------------------------------
  317. float CStudioConstraintBones::ComputeTargetPosition(
  318. Vector &vTargetPosition,
  319. mstudioconstrainttarget_t *pTargets,
  320. int nTargetCount,
  321. CBoneAccessor &boneToWorld )
  322. {
  323. float *pflTargetWeights = reinterpret_cast< float * >( stackalloc( nTargetCount * sizeof( float ) ) );
  324. Vector *pvTargetPositions = reinterpret_cast< Vector * >( stackalloc( nTargetCount * sizeof( Vector ) ) );
  325. Vector *pvTargetOffsets = reinterpret_cast< Vector * >( stackalloc( nTargetCount * sizeof( Vector ) ) );
  326. mstudioconstrainttarget_t *pTarget;
  327. for ( int i = 0; i < nTargetCount; ++i )
  328. {
  329. pTarget = pTargets + i;
  330. pflTargetWeights[i] = pTarget->m_flWeight;
  331. pvTargetOffsets[i] = pTarget->m_vOffset;
  332. MatrixPosition( boneToWorld.GetBone( pTarget->m_nBone ), pvTargetPositions[i] );
  333. }
  334. return CConstraintBones::ComputeTargetPosition( vTargetPosition, nTargetCount, pflTargetWeights, pvTargetPositions, pvTargetOffsets );
  335. }
  336. //=============================================================================
  337. // CStudioConstraintBones : Studio Interface Functions
  338. //=============================================================================
  339. //-----------------------------------------------------------------------------
  340. // studio interface
  341. //-----------------------------------------------------------------------------
  342. float CStudioConstraintBones::ComputeTargetOrientation(
  343. Quaternion &qTargetOrientation,
  344. mstudioconstrainttarget_t *pTargets,
  345. int nTargetCount,
  346. CBoneAccessor &boneToWorld )
  347. {
  348. float *pflTargetWeights = reinterpret_cast< float * >( stackalloc( nTargetCount * sizeof( float ) ) );
  349. Quaternion *pqTargetOrientations = reinterpret_cast< Quaternion * >( stackalloc( nTargetCount * sizeof( Quaternion ) ) );
  350. Quaternion *pqTargetOffsets = reinterpret_cast< Quaternion * >( stackalloc( nTargetCount * sizeof( Quaternion ) ) );
  351. mstudioconstrainttarget_t *pTarget;
  352. for ( int i = 0; i < nTargetCount; ++i )
  353. {
  354. pTarget = pTargets + i;
  355. pflTargetWeights[i] = pTarget->m_flWeight;
  356. pqTargetOffsets[i] = pTarget->m_qOffset;
  357. MatrixQuaternion( boneToWorld.GetBone( pTarget->m_nBone ), pqTargetOrientations[i] );
  358. }
  359. return CConstraintBones::ComputeTargetOrientation( qTargetOrientation, nTargetCount, pflTargetWeights, pqTargetOrientations, pqTargetOffsets );
  360. }
  361. //-----------------------------------------------------------------------------
  362. // studio interface
  363. //-----------------------------------------------------------------------------
  364. float CStudioConstraintBones::ComputeTargetPositionOrientation(
  365. Vector &vTargetPosition,
  366. Quaternion &qTargetOrientation,
  367. mstudioconstrainttarget_t *pTargets,
  368. int nTargetCount,
  369. CBoneAccessor &boneToWorld )
  370. {
  371. float *pflTargetWeights = reinterpret_cast< float * >( stackalloc( nTargetCount * sizeof( float ) ) );
  372. matrix3x4a_t *pmTargets = reinterpret_cast< matrix3x4a_t * >( stackalloc( nTargetCount * sizeof( matrix3x4a_t ) ) );
  373. matrix3x4a_t *pmOffsets = reinterpret_cast< matrix3x4a_t * >( stackalloc( nTargetCount * sizeof( matrix3x4a_t ) ) );
  374. mstudioconstrainttarget_t *pTarget = pTargets;
  375. for ( int i = 0; i < nTargetCount; ++i, ++pTarget )
  376. {
  377. pflTargetWeights[i] = pTarget->m_flWeight;
  378. QuaternionMatrix( pTarget->m_qOffset, pTarget->m_vOffset, pmOffsets[i] );
  379. pmTargets[i] = boneToWorld.GetBone( pTarget->m_nBone );
  380. }
  381. return CConstraintBones::ComputeTargetPositionOrientation( vTargetPosition, qTargetOrientation, nTargetCount, pflTargetWeights, pmTargets, pmOffsets );
  382. }
  383. //-----------------------------------------------------------------------------
  384. // studio interface
  385. //-----------------------------------------------------------------------------
  386. void CStudioConstraintBones::ComputeBaseWorldMatrix(
  387. matrix3x4a_t &mBaseWorldMatrix,
  388. mstudioconstraintslave_t *pSlave,
  389. CBoneAccessor &boneToWorld,
  390. const CStudioHdr *pStudioHdr,
  391. const matrix3x4_t *pmViewTransform /* = NULL */ )
  392. {
  393. // studiomdl shouldn't create mstudioconstraintslave_t's with invalid bone indices
  394. Assert( pSlave->m_nBone >= 0 && pSlave->m_nBone < MAXSTUDIOBONES );
  395. const int nBoneParent = pStudioHdr->boneParent( pSlave->m_nBone );
  396. if ( nBoneParent < 0 )
  397. {
  398. if ( pmViewTransform )
  399. {
  400. matrix3x4a_t mTmp;
  401. QuaternionMatrix( pSlave->m_qBaseOrientation, pSlave->m_vBasePosition, mTmp );
  402. ConcatTransforms( *pmViewTransform, mTmp, mBaseWorldMatrix );
  403. }
  404. else
  405. {
  406. QuaternionMatrix( pSlave->m_qBaseOrientation, pSlave->m_vBasePosition, mBaseWorldMatrix );
  407. }
  408. }
  409. else
  410. {
  411. matrix3x4a_t mTmp;
  412. QuaternionMatrix( pSlave->m_qBaseOrientation, pSlave->m_vBasePosition, mTmp );
  413. ConcatTransforms( boneToWorld.GetBone( nBoneParent ), mTmp, mBaseWorldMatrix );
  414. }
  415. }
  416. //-----------------------------------------------------------------------------
  417. // studio interface
  418. //-----------------------------------------------------------------------------
  419. void CStudioConstraintBones::ComputePointConstraint(
  420. const mstudiobone_t *pBones,
  421. int nBone,
  422. CBoneAccessor &boneToWorld,
  423. const CStudioHdr *pStudioHdr )
  424. {
  425. BONE_PROFILE_FUNC();
  426. mstudiopointconstraint_t *pProc = ( mstudiopointconstraint_t * )pBones[nBone].pProcedure();
  427. // Calculate the current target position and the total weight
  428. // of the the targets contributing to the target position.
  429. Vector vTargetPosition;
  430. const float flWeight = CStudioConstraintBones::ComputeTargetPosition( vTargetPosition, pProc->pTarget( 0 ), pProc->m_nTargetCount, boneToWorld );
  431. Vector vFinalPosition;
  432. matrix3x4a_t &mBaseWorldMatrix = boneToWorld.GetBoneForWrite( nBone );
  433. CStudioConstraintBones::ComputeBaseWorldMatrix( mBaseWorldMatrix, &( pProc->m_slave ), boneToWorld, pStudioHdr );
  434. // Blend between the target position and the base position using the target weight
  435. if ( flWeight < 1.0f )
  436. {
  437. Vector vBasePosition;
  438. MatrixPosition( mBaseWorldMatrix, vBasePosition );
  439. vFinalPosition = Lerp( flWeight, vBasePosition, vTargetPosition );
  440. }
  441. else
  442. {
  443. vFinalPosition = vTargetPosition;
  444. }
  445. // Update the bone the new position.
  446. PositionMatrix( vFinalPosition, mBaseWorldMatrix );
  447. }
  448. //-----------------------------------------------------------------------------
  449. // studio interface
  450. //-----------------------------------------------------------------------------
  451. void CStudioConstraintBones::ComputeOrientConstraint(
  452. const mstudiobone_t *pBones,
  453. int nBone,
  454. CBoneAccessor &boneToWorld,
  455. const CStudioHdr *pStudioHdr,
  456. const matrix3x4_t *pmViewTransform )
  457. {
  458. BONE_PROFILE_FUNC();
  459. mstudioorientconstraint_t *pProc = ( mstudioorientconstraint_t * )pBones[nBone].pProcedure();
  460. // Calculate the current target position and the total weight
  461. // of the the targets contributing to the target position.
  462. Quaternion qTargetOrientation;
  463. const float flWeight = CStudioConstraintBones::ComputeTargetOrientation( qTargetOrientation, pProc->pTarget( 0 ), pProc->m_nTargetCount, boneToWorld );
  464. // Blend between the target orientation and the base orientation using the target weight
  465. Quaternion qFinalOrientation;
  466. matrix3x4a_t &mBaseWorldMatrix = boneToWorld.GetBoneForWrite( nBone );
  467. CStudioConstraintBones::ComputeBaseWorldMatrix( mBaseWorldMatrix, &( pProc->m_slave ), boneToWorld, pStudioHdr, pmViewTransform );
  468. if ( flWeight < 1.0f )
  469. {
  470. Quaternion qBaseOrientation;
  471. MatrixQuaternion( mBaseWorldMatrix, qBaseOrientation );
  472. QuaternionSlerp( qBaseOrientation, qTargetOrientation, flWeight, qFinalOrientation );
  473. }
  474. else
  475. {
  476. qFinalOrientation = qTargetOrientation;
  477. }
  478. // Quaternion matrix wipes out the translate component
  479. Vector vTmpPosition;
  480. MatrixPosition( mBaseWorldMatrix, vTmpPosition );
  481. QuaternionMatrix( qFinalOrientation, vTmpPosition, mBaseWorldMatrix );
  482. }
  483. //-----------------------------------------------------------------------------
  484. // studio interface
  485. //
  486. // pmViewTransform is for hlmv which modifies the actual parentless bones
  487. // to position things in the viewer
  488. //
  489. // TODO: Split into hlmv and "normal" versions, i.e. hlmv needs ViewTransform
  490. //-----------------------------------------------------------------------------
  491. void CStudioConstraintBones::ComputeAimConstraint(
  492. const mstudiobone_t *pBones,
  493. int nBone,
  494. CBoneAccessor &boneToWorld,
  495. const CStudioHdr *pStudioHdr,
  496. const matrix3x4_t *pmViewTransform,
  497. AimConstraintUpType_t eType )
  498. {
  499. BONE_PROFILE_FUNC();
  500. mstudioaimconstraint_t *pProc = ( mstudioaimconstraint_t * )pBones[nBone].pProcedure();
  501. // Calculate the current target position and the total weight
  502. // of the the targets contributing to the target position.
  503. Vector vTargetPos;
  504. const float flWeight = CStudioConstraintBones::ComputeTargetPosition( vTargetPos, pProc->pTarget( 0 ), pProc->m_nTargetCount, boneToWorld );
  505. Vector vTargetWorldPos;
  506. matrix3x4a_t mSlaveParentToWorld;
  507. const int nParentBone = pBones[nBone].parent;
  508. if ( pmViewTransform )
  509. {
  510. matrix3x4_t mInv;
  511. MatrixInvert( *pmViewTransform, mInv );
  512. VectorTransform( vTargetPos, mInv, vTargetWorldPos );
  513. if ( nParentBone >= 0 )
  514. {
  515. ConcatTransforms( mInv, boneToWorld[nParentBone], mSlaveParentToWorld );
  516. }
  517. else
  518. {
  519. SetIdentityMatrix( mSlaveParentToWorld );
  520. }
  521. }
  522. else
  523. {
  524. VectorCopy( vTargetPos, vTargetWorldPos );
  525. if ( nParentBone >= 0 )
  526. {
  527. MatrixCopy( boneToWorld[nParentBone], mSlaveParentToWorld );
  528. }
  529. else
  530. {
  531. SetIdentityMatrix( mSlaveParentToWorld );
  532. }
  533. }
  534. Quaternion qTargetOrientation;
  535. CConstraintBones::ComputeAimConstraint(
  536. qTargetOrientation,
  537. vTargetWorldPos,
  538. mSlaveParentToWorld,
  539. pProc->m_vUp,
  540. pProc->m_slave.m_vBasePosition,
  541. pProc->m_nUpSpaceTarget >= 0 ? &boneToWorld[ pProc->m_nUpSpaceTarget ] : NULL,
  542. eType );
  543. // Add in initial offset
  544. Quaternion qOffsetOrientation;
  545. QuaternionMult( qTargetOrientation, pProc->m_qAimOffset, qOffsetOrientation );
  546. // Add in parent matrix
  547. Quaternion qParentToWorld;
  548. MatrixQuaternion( mSlaveParentToWorld, qParentToWorld );
  549. Quaternion qTmp;
  550. QuaternionMult( qParentToWorld, qOffsetOrientation, qTmp );
  551. qOffsetOrientation = qTmp;
  552. // Blend between the target orientation and the base orientation using the target weight
  553. Quaternion qFinalOrientation;
  554. matrix3x4a_t &mBaseWorldMatrix = boneToWorld.GetBoneForWrite( nBone );
  555. CStudioConstraintBones::ComputeBaseWorldMatrix( mBaseWorldMatrix, &( pProc->m_slave ), boneToWorld, pStudioHdr, pmViewTransform );
  556. if ( flWeight < 1.0f )
  557. {
  558. Quaternion qBaseOrientation;
  559. MatrixQuaternion( mBaseWorldMatrix, qBaseOrientation );
  560. QuaternionSlerp( qBaseOrientation, qOffsetOrientation, flWeight, qFinalOrientation );
  561. }
  562. else
  563. {
  564. qFinalOrientation = qOffsetOrientation;
  565. }
  566. if ( pmViewTransform )
  567. {
  568. Quaternion qTmp0;
  569. Quaternion qTmp1;
  570. MatrixQuaternion( *pmViewTransform, qTmp0 );
  571. QuaternionMult( qTmp0, qFinalOrientation, qTmp1 );
  572. qFinalOrientation = qTmp1;
  573. }
  574. // Quaternion matrix wipes out the translate component
  575. Vector vTmpPosition;
  576. MatrixPosition( mBaseWorldMatrix, vTmpPosition );
  577. QuaternionMatrix( qFinalOrientation, vTmpPosition, mBaseWorldMatrix );
  578. }
  579. //-----------------------------------------------------------------------------
  580. // studio interface
  581. //-----------------------------------------------------------------------------
  582. void CStudioConstraintBones::ComputeParentConstraint(
  583. const mstudiobone_t *pBones,
  584. int nBone,
  585. CBoneAccessor &boneToWorld,
  586. const CStudioHdr *pStudioHdr )
  587. {
  588. BONE_PROFILE_FUNC();
  589. mstudioorientconstraint_t *pProc = ( mstudioorientconstraint_t * )pBones[nBone].pProcedure();
  590. // Calculate the current target position and the total weight
  591. // of the the targets contributing to the target position.
  592. Vector vTargetPosition;
  593. Quaternion qTargetOrientation;
  594. const float flWeight = CStudioConstraintBones::ComputeTargetPositionOrientation( vTargetPosition, qTargetOrientation, pProc->pTarget( 0 ), pProc->m_nTargetCount, boneToWorld );
  595. // Blend between the target orientation and the base orientation using the target weight
  596. Quaternion qFinalOrientation;
  597. Vector vFinalPosition;
  598. matrix3x4a_t &mBaseWorldMatrix = boneToWorld.GetBoneForWrite( nBone );
  599. CStudioConstraintBones::ComputeBaseWorldMatrix( mBaseWorldMatrix, &( pProc->m_slave ), boneToWorld, pStudioHdr );
  600. if ( flWeight < 1.0f )
  601. {
  602. Vector vBasePosition;
  603. Quaternion qBaseOrientation;
  604. MatrixAngles( mBaseWorldMatrix, qBaseOrientation, vBasePosition );
  605. QuaternionSlerp( qBaseOrientation, qTargetOrientation, flWeight, qFinalOrientation );
  606. VectorLerp( vBasePosition, vTargetPosition, flWeight, vFinalPosition );
  607. }
  608. else
  609. {
  610. qFinalOrientation = qTargetOrientation;
  611. vFinalPosition = vTargetPosition;
  612. }
  613. QuaternionMatrix( qFinalOrientation, vFinalPosition, mBaseWorldMatrix );
  614. }
  615. //-----------------------------------------------------------------------------
  616. //
  617. // Twist bones are bones which take a portion of the rotation around a specified
  618. // axis.
  619. //
  620. // The axis is defined as the vector between a parent and child bone
  621. // The twist bones must also be children of the parent
  622. //
  623. // + parent
  624. // |
  625. // +--+ twist 0.25
  626. // |
  627. // +--+ twist 0.5
  628. // |
  629. // +--+ twist 0.75
  630. // |
  631. // +--+ child
  632. //
  633. // If inverse is false each twist takes a portion of the child rotation around
  634. // the specified axis
  635. //
  636. // If inverse is true each twist takes a portion of the parent rotation around
  637. // the specified axis from a specified reference orientation
  638. //
  639. // All specified matrices & Quaternions are local to the bone, they are not
  640. // worldToBone transformations
  641. //
  642. // pqTwists, pflWeights, pqTwistBinds are all pointers to arrays which must be
  643. // at least nCount in size
  644. //
  645. // This code is called directly from:
  646. // maya, datamodel & CalcProceduralBone/DoTwistBones
  647. //-----------------------------------------------------------------------------
  648. void ComputeTwistBones(
  649. Quaternion *pqTwists,
  650. int nCount,
  651. bool bInverse,
  652. const Vector &vUp,
  653. const Quaternion &qParent,
  654. const matrix3x4_t &mChild,
  655. const Quaternion &qBaseInv,
  656. const float *pflWeights,
  657. const Quaternion *pqTwistBinds )
  658. {
  659. const float flEps = FLT_EPSILON * 10.0f;
  660. const float flEpsSq = flEps * flEps;
  661. Vector vUpRotate;
  662. Vector vLocalTranslation;
  663. Vector vRotatedTranslation;
  664. Quaternion qTmp0;
  665. Quaternion qTmp1;
  666. {
  667. Quaternion qChild;
  668. MatrixAngles( mChild, qChild, vLocalTranslation );
  669. // Check for 0 length translation - perhaps use Vector::IsZero?
  670. if ( vLocalTranslation.LengthSqr() < flEpsSq )
  671. {
  672. // No translation, can't compute rotation axis, do nothing
  673. V_memcpy( pqTwists, pqTwistBinds, nCount * sizeof( Quaternion ) );
  674. return;
  675. }
  676. VectorNormalize( vLocalTranslation );
  677. if ( bInverse )
  678. {
  679. QuaternionMult( qBaseInv, qParent, qTmp0 );
  680. VectorRotate( vUp, qTmp0, vUpRotate );
  681. VectorRotate( vLocalTranslation, qTmp0, vRotatedTranslation );
  682. }
  683. else
  684. {
  685. QuaternionMult( qBaseInv, qChild, qTmp0 );
  686. VectorRotate( vUp, qTmp0, vUpRotate );
  687. VectorRotate( vLocalTranslation, qBaseInv, vRotatedTranslation );
  688. }
  689. }
  690. // If the specified up axis and the rotated translation vector are parallel then quit
  691. if ( 1.0f - FloatMakePositive( DotProduct( vRotatedTranslation, vUp ) ) < flEps )
  692. {
  693. V_memcpy( pqTwists, pqTwistBinds, nCount * sizeof( Quaternion ) );
  694. return;
  695. }
  696. // If the rotated up axis and the rotated translation vector are parallel then quit
  697. if ( 1.0f - FloatMakePositive( DotProduct( vRotatedTranslation, vUpRotate ) ) < flEps )
  698. {
  699. V_memcpy( pqTwists, pqTwistBinds, nCount * sizeof( Quaternion ) );
  700. return;
  701. }
  702. // Project Up (V) & Rotated Up (V) into the plane defined by the
  703. // rotated up vector (N)
  704. //
  705. // U = V - ( V dot N ) N;
  706. //
  707. // U is V projected into plane with normal N
  708. Vector vTmp0;
  709. vTmp0 = vRotatedTranslation;
  710. Vector vUpProject;
  711. vTmp0 *= DotProduct( vUp, vRotatedTranslation );
  712. VectorSubtract( vUp, vTmp0, vUpProject );
  713. VectorNormalize( vUpProject );
  714. vTmp0 = vRotatedTranslation;
  715. Vector vUpRotateProject;
  716. vTmp0 *= DotProduct( vUpRotate, vRotatedTranslation );
  717. VectorSubtract( vUpRotate, vTmp0, vUpRotateProject );
  718. VectorNormalize( vUpRotateProject );
  719. if ( VectorsAreEqual( vUpProject, vUpRotateProject, 0.001 ) )
  720. {
  721. V_memcpy( pqTwists, pqTwistBinds, nCount * sizeof( Quaternion ) );
  722. }
  723. else
  724. {
  725. CrossProduct( vUpProject, vUpRotateProject, vTmp0 );
  726. VectorNormalize( vTmp0 );
  727. const float flDot = DotProduct( vUpProject, vUpRotateProject );
  728. const float flAngle = DotProduct( vTmp0, vRotatedTranslation ) < 0.0f ? -acos( flDot ) : acos( flDot );
  729. AxisAngleQuaternion( vLocalTranslation, RAD2DEG( flAngle ), qTmp0 );
  730. if ( bInverse )
  731. {
  732. for ( int i = 0; i < nCount; ++i )
  733. {
  734. QuaternionScale( qTmp0, pflWeights[i] - 1.0f, qTmp1 );
  735. QuaternionMult( qTmp1, pqTwistBinds[i], pqTwists[i] );
  736. }
  737. }
  738. else
  739. {
  740. for ( int i = 0; i < nCount; ++i )
  741. {
  742. QuaternionScale( qTmp0, pflWeights[i], qTmp1 );
  743. QuaternionMult( qTmp1, pqTwistBinds[i], pqTwists[i] );
  744. }
  745. }
  746. }
  747. }