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.

2310 lines
78 KiB

  1. //====== Copyright � 1996-2008, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: Implementation of the constraint operator classes. The constraint
  4. // operators control the position and / or orientation of a specified slave dag
  5. // node based on the position and orientation of a set of weighted target dag
  6. // nodes. The relationship between the target dag node and the slave is
  7. // determined by the type of the constraint. The Operate() function of each
  8. // constraint class is responsible for enforcing its specific relationship.
  9. //
  10. //=============================================================================
  11. #include "movieobjects/dmerigconstraintoperators.h"
  12. #include "movieobjects/dmechannel.h"
  13. #include "movieobjects/dmeanimationset.h"
  14. #include "movieobjects/dmerig.h"
  15. #include "datamodel/dmelementfactoryhelper.h"
  16. #include "tier1/fmtstr.h"
  17. #include "bone_constraints.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. //-------------------------------------------------------------------------------------------------
  21. //
  22. // CDmeConstraintTarget
  23. //
  24. //-------------------------------------------------------------------------------------------------
  25. //-----------------------------------------------------------------------------
  26. // Expose the CDmeConstraintTarget class to the scene database
  27. //-----------------------------------------------------------------------------
  28. IMPLEMENT_ELEMENT_FACTORY( DmeConstraintTarget, CDmeConstraintTarget );
  29. //-----------------------------------------------------------------------------
  30. // Purpose: Perform construction tasks, initializes attributes
  31. //-----------------------------------------------------------------------------
  32. void CDmeConstraintTarget::OnConstruction()
  33. {
  34. m_Handle.Init( this, "target" );
  35. m_flWeight.Init( this, "targetWeight" );
  36. m_vecOffset.InitAndSet( this, "vecOffset", vec3_origin );
  37. m_qOffset.InitAndSet( this, "oOffset", quat_identity );
  38. }
  39. //-----------------------------------------------------------------------------
  40. // Purpose: Perform destruction tasks
  41. //-----------------------------------------------------------------------------
  42. void CDmeConstraintTarget::OnDestruction()
  43. {
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Purpose: Reset the position and orientation offset values
  47. //-----------------------------------------------------------------------------
  48. void CDmeConstraintTarget::ClearOffset()
  49. {
  50. m_vecOffset = vec3_origin;
  51. m_qOffset = quat_identity;
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Purpose: Find the channel driving the weight value of the constraint
  55. //-----------------------------------------------------------------------------
  56. CDmeChannel *CDmeConstraintTarget::FindWeightChannel() const
  57. {
  58. for ( DmAttributeReferenceIterator_t it = g_pDataModel->FirstAttributeReferencingElement( GetHandle() );
  59. it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID;
  60. it = g_pDataModel->NextAttributeReferencingElement( it ) )
  61. {
  62. CDmAttribute *pAttr = g_pDataModel->GetAttribute( it );
  63. CDmElement *pElement = pAttr->GetOwner();
  64. if ( pElement == NULL )
  65. continue;
  66. CDmeChannel *pChannel = CastElement< CDmeChannel >( pElement );
  67. if ( pChannel )
  68. {
  69. if ( pChannel->GetToAttribute() == m_flWeight.GetAttribute() )
  70. return pChannel;
  71. }
  72. }
  73. return NULL;
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose: Get the constraint that target belongs to.
  77. //-----------------------------------------------------------------------------
  78. CDmeRigBaseConstraintOperator *CDmeConstraintTarget::GetConstraint()
  79. {
  80. return FindAncestorReferencingElement< CDmeRigBaseConstraintOperator >( this );
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Get the control attached to constraint
  84. //-----------------------------------------------------------------------------
  85. CDmElement *CDmeConstraintTarget::FindWeightControl() const
  86. {
  87. CDmElement *pWeightChannel = FindWeightChannel();
  88. CDmElement *pControl = FindReferringElement< CDmElement >( pWeightChannel, "channel" );
  89. return pControl;
  90. }
  91. //-------------------------------------------------------------------------------------------------
  92. //
  93. // CDmeConstraintSlave
  94. //
  95. //-------------------------------------------------------------------------------------------------
  96. //-----------------------------------------------------------------------------
  97. // Expose the CDmeConstraintSlave class to the scene database
  98. //-----------------------------------------------------------------------------
  99. IMPLEMENT_ELEMENT_FACTORY( DmeConstraintSlave, CDmeConstraintSlave );
  100. //-----------------------------------------------------------------------------
  101. // Purpose: Perform construction tasks, initializes attributes
  102. //-----------------------------------------------------------------------------
  103. void CDmeConstraintSlave::OnConstruction()
  104. {
  105. m_Dag.Init( this, "target" );
  106. m_BasePosition.Init( this, TRANSFORM_POSITION );
  107. m_BaseOrientation.Init( this, TRANSFORM_ORIENTATION );
  108. }
  109. //-----------------------------------------------------------------------------
  110. // Purpose: Perform destruction tasks
  111. //-----------------------------------------------------------------------------
  112. void CDmeConstraintSlave::OnDestruction()
  113. {
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Get the constraint to which the slave belongs.
  117. //-----------------------------------------------------------------------------
  118. CDmeRigBaseConstraintOperator *CDmeConstraintSlave::GetConstraint() const
  119. {
  120. CDmeRigBaseConstraintOperator *pConstraint = FindAncestorReferencingElement< CDmeRigBaseConstraintOperator >( this );
  121. return pConstraint;
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose: Compute the base world space matrix
  125. //-----------------------------------------------------------------------------
  126. void CDmeConstraintSlave::GetBaseWorldTransform( matrix3x4_t &worldMatrix ) const
  127. {
  128. Vector lsBasePosition = m_BasePosition;
  129. Quaternion lsBaseOrientation = m_BaseOrientation;
  130. CDmeDag *pDag = m_Dag;
  131. if ( pDag )
  132. {
  133. matrix3x4_t parentToWorld, localMatrix;
  134. pDag->GetParentWorldMatrix( parentToWorld );
  135. QuaternionMatrix( lsBaseOrientation, lsBasePosition, localMatrix );
  136. ConcatTransforms( parentToWorld, localMatrix, worldMatrix );
  137. }
  138. else
  139. {
  140. SetIdentityMatrix( worldMatrix );
  141. }
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose: Compute the base position and orientation in world space
  145. //-----------------------------------------------------------------------------
  146. void CDmeConstraintSlave::ComputeBaseWorldValues( Vector &wsPosition, Quaternion &wsOrientation ) const
  147. {
  148. matrix3x4_t worldMatrix;
  149. GetBaseWorldTransform( worldMatrix );
  150. MatrixAngles( worldMatrix, wsOrientation, wsPosition );
  151. }
  152. //-------------------------------------------------------------------------------------------------
  153. //
  154. // CDmeRigBaseConstraintOperator
  155. //
  156. //-------------------------------------------------------------------------------------------------
  157. //-----------------------------------------------------------------------------
  158. // Expose this class to the scene database
  159. //-----------------------------------------------------------------------------
  160. IMPLEMENT_ELEMENT_FACTORY( DmeRigBaseConstraintOperator, CDmeRigBaseConstraintOperator );
  161. //-----------------------------------------------------------------------------
  162. // Purpose: Constructor, initializes attributes, create the embedded target
  163. //-----------------------------------------------------------------------------
  164. void CDmeRigBaseConstraintOperator::OnConstruction()
  165. {
  166. m_Targets.Init( this, "targets" );
  167. m_Slave.InitAndCreate( this, "slave" );
  168. m_mode.InitAndSet( this, "mode", (int)RM_FORWARD );
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Purpose: Perform destruction tasks, destroy the internal elements of the
  172. // constraint.
  173. //-----------------------------------------------------------------------------
  174. void CDmeRigBaseConstraintOperator::OnDestruction()
  175. {
  176. g_pDataModel->DestroyElement( m_Slave.GetHandle() );
  177. for ( int i = 0 ;i < m_Targets.Count(); ++i )
  178. {
  179. if ( m_Targets[ i ] )
  180. {
  181. g_pDataModel->DestroyElement( m_Targets[ i ]->GetHandle() );
  182. }
  183. }
  184. m_Targets.RemoveAll();
  185. }
  186. //-----------------------------------------------------------------------------
  187. // Purpose: Determine if the the constraint has slave with the specified name
  188. //-----------------------------------------------------------------------------
  189. bool CDmeRigBaseConstraintOperator::IsSlaveObject( char const *pchName ) const
  190. {
  191. if ( !m_Slave->m_Dag )
  192. return false;
  193. return !Q_stricmp( m_Slave->m_Dag->GetName(), pchName );
  194. }
  195. //-----------------------------------------------------------------------------
  196. // Purpose: Get the attributes that the constraint reads data from, Inputs are
  197. // CDmeDags (handles usually)
  198. //-----------------------------------------------------------------------------
  199. void CDmeRigBaseConstraintOperator::GetInputAttributes( CUtlVector< CDmAttribute * > &attrs )
  200. {
  201. for ( int i = 0; i < m_Targets.Count(); ++i )
  202. {
  203. if ( !m_Targets[ i ])
  204. continue;
  205. CDmeDag* pDagNode = m_Targets[ i ]->m_Handle;
  206. if ( pDagNode == NULL )
  207. continue;
  208. AddAttribute( attrs, GetInputAttributeType(), pDagNode->GetTransform() );
  209. AddAncestorAttributes( attrs, pDagNode );
  210. CDmAttribute *pWeightAttr = m_Targets[ i ]->GetWeightAttribute();
  211. if ( pWeightAttr )
  212. {
  213. attrs.AddToTail( pWeightAttr );
  214. }
  215. }
  216. // If the slave dag node is the child of another node the operation of the constraint
  217. // is dependent upon the evaluation of the parent because result of the constraint
  218. // operation must be converted into the space of the parent of the slave.
  219. AddAncestorAttributes( attrs, m_Slave->m_Dag );
  220. CDmAttribute *pSlavePosAttr = m_Slave->m_BasePosition.GetAttribute();
  221. if ( pSlavePosAttr )
  222. {
  223. attrs.AddToTail( pSlavePosAttr );
  224. }
  225. CDmAttribute *pSlaveRotAttr = m_Slave->m_BaseOrientation.GetAttribute();
  226. if ( pSlaveRotAttr )
  227. {
  228. attrs.AddToTail( pSlaveRotAttr );
  229. }
  230. }
  231. //-----------------------------------------------------------------------------
  232. // Purpose: Get the attributes to which the attribute writes, Outputs are
  233. // CDmeDags (bones or other CDmeRigHandles usually)
  234. //-----------------------------------------------------------------------------
  235. void CDmeRigBaseConstraintOperator::GetOutputAttributes( CUtlVector< CDmAttribute * > &attrs )
  236. {
  237. if ( !m_Slave->m_Dag )
  238. return;
  239. AddAttribute( attrs, GetOutputAttributeType(), m_Slave->m_Dag->GetTransform() );
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Purpose: Add the specified type of attributes from the provided transform
  243. //-----------------------------------------------------------------------------
  244. void CDmeRigBaseConstraintOperator::AddAttribute( CUtlVector< CDmAttribute * > &attrs, enum EAddType type, CDmeTransform *pTxForm )
  245. {
  246. if ( !pTxForm )
  247. return;
  248. // Get the transform attribute
  249. if ( type & AA_TYPE_POSITION )
  250. {
  251. CDmAttribute *pAttrib = pTxForm->GetPositionAttribute();
  252. if ( pAttrib )
  253. attrs.AddToTail( pAttrib );
  254. }
  255. if ( type & AA_TYPE_ORIENTATION )
  256. {
  257. CDmAttribute *pAttrib = pTxForm->GetOrientationAttribute();
  258. if ( pAttrib )
  259. attrs.AddToTail( pAttrib );
  260. }
  261. }
  262. //-----------------------------------------------------------------------------
  263. // Purpose: Add the position and orientation attributes the entire ancestry of
  264. // the dag node.
  265. //-----------------------------------------------------------------------------
  266. void CDmeRigBaseConstraintOperator::AddAncestorAttributes( CUtlVector< CDmAttribute * > &attrs, CDmeDag *pDagNode )
  267. {
  268. if ( pDagNode == NULL )
  269. return;
  270. CDmeDag* pParent = pDagNode->GetParent();
  271. while ( pParent )
  272. {
  273. AddAttribute( attrs, (EAddType)( AA_TYPE_POSITION | AA_TYPE_ORIENTATION ), pParent->GetTransform() );
  274. pParent = pParent->GetParent();
  275. }
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Purpose: Add target handles to the the constraint with the specified
  279. // weights. Returns the index of the first target added.
  280. //-----------------------------------------------------------------------------
  281. void CDmeRigBaseConstraintOperator::AddHandles( int nCount, CDmeDag *const pTargetDags[], const float *pflWeights, bool bPreserveOffset, CUtlVector< CDmeConstraintTarget* > *pTargetList )
  282. {
  283. // If a target list is provided, allocate the space to hold all
  284. // of the constraint targets for the list of input dag nodes.
  285. if ( pTargetList )
  286. {
  287. pTargetList->EnsureCapacity( pTargetList->Count() + nCount );
  288. }
  289. for ( int i = 0; i < nCount; ++i )
  290. {
  291. Assert( pTargetDags[ i ] );
  292. if ( !pTargetDags[ i ] )
  293. continue;
  294. // Check to see if the constraint already has a target with the specified dag node
  295. CDmeConstraintTarget *pTarget = FindConstraintTargetForDag( pTargetDags[ i ] );
  296. if ( pTarget == NULL )
  297. {
  298. pTarget = CreateElement< CDmeConstraintTarget >( CFmtStr( "%s", pTargetDags[ i ]->GetName() ), GetFileId() );
  299. m_Targets.AddToTail( pTarget );
  300. }
  301. if ( pTarget != NULL )
  302. {
  303. pTarget->m_Handle = pTargetDags[ i ];
  304. pTarget->m_flWeight = ( pflWeights != NULL ) ? pflWeights[ i ] : 1.0f;
  305. Vector vOffset = vec3_origin;
  306. Quaternion qOffset = quat_identity;
  307. ComputeOffset( vOffset, qOffset, pTarget, bPreserveOffset );
  308. pTarget->m_vecOffset = vOffset;
  309. pTarget->m_qOffset = qOffset;
  310. if ( pTargetList )
  311. {
  312. pTargetList->AddToTail( pTarget );
  313. }
  314. }
  315. }
  316. PostHandlesAdded( bPreserveOffset );
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose: Remove all target handles from the constraint
  320. //-----------------------------------------------------------------------------
  321. void CDmeRigBaseConstraintOperator::ClearHandles()
  322. {
  323. m_Targets.RemoveAll();
  324. }
  325. //-----------------------------------------------------------------------------
  326. // Purpose: Set the dag node which the constraint is controlling
  327. //-----------------------------------------------------------------------------
  328. void CDmeRigBaseConstraintOperator::SetSlave( CDmeDag *pSlave )
  329. {
  330. m_Slave->m_Dag = pSlave;
  331. CDmeTransform *pTransform = pSlave->GetTransform();
  332. if ( pTransform )
  333. {
  334. m_Slave->SetBasePosition( pTransform->GetPosition() );
  335. m_Slave->SetBaseOrientation( pTransform->GetOrientation() );
  336. }
  337. }
  338. //-----------------------------------------------------------------------------
  339. // Purpose: Get a pointer to the dag node the constraint is controlling
  340. //-----------------------------------------------------------------------------
  341. const CDmeDag *CDmeRigBaseConstraintOperator::GetSlave() const
  342. {
  343. return m_Slave->m_Dag;
  344. }
  345. //-----------------------------------------------------------------------------
  346. // Purpose: Set the operating mode of the constraint
  347. //-----------------------------------------------------------------------------
  348. void CDmeRigBaseConstraintOperator::SetMode( RigOperatorMode_t mode )
  349. {
  350. m_mode = mode;
  351. }
  352. //-----------------------------------------------------------------------------
  353. // Purpose: Compute the position and orientation offset of the specified target
  354. // based on the relative transforms of the target and the slave.
  355. //-----------------------------------------------------------------------------
  356. void CDmeRigBaseConstraintOperator::ComputeOffset( Vector &vOffset, Quaternion &qOffset, CDmeConstraintTarget *pTarget, bool bPreserveOffset )
  357. {
  358. vOffset = vec3_origin;
  359. qOffset = quat_identity;
  360. Assert( m_Slave->m_Dag );
  361. if ( !bPreserveOffset || !m_Slave->m_Dag || !pTarget->m_Handle )
  362. return;
  363. matrix3x4_t mSlave, mTarget;
  364. m_Slave->m_Dag->GetAbsTransform( mSlave );
  365. pTarget->m_Handle->GetAbsTransform( mTarget );
  366. Vector slavePosition, targetPosition;
  367. Quaternion slaveOrientation, targetOrientation;
  368. MatrixAngles( mSlave, slaveOrientation, slavePosition );
  369. MatrixAngles( mTarget, targetOrientation, targetPosition );
  370. vOffset = slavePosition - targetPosition;
  371. Quaternion invTargetOrientation;
  372. QuaternionInvert( targetOrientation, invTargetOrientation );
  373. QuaternionMult( invTargetOrientation, slaveOrientation, qOffset );
  374. }
  375. //-----------------------------------------------------------------------------
  376. // Compute the aggregate target position from the weighted target list and
  377. // return the total weight
  378. //-----------------------------------------------------------------------------
  379. float CDmeRigBaseConstraintOperator::ComputeTargetPosition( Vector &wsTargetPosition )
  380. {
  381. wsTargetPosition = vec3_origin;
  382. float flWeightSum = 0.0f;
  383. int nTargets = m_Targets.Count();
  384. for ( int i = 0; i < nTargets; ++i )
  385. {
  386. CDmeConstraintTarget *pTarget = m_Targets[ i ];
  387. Assert( pTarget );
  388. CDmeDag *pTargetDag = pTarget->m_Handle;
  389. if ( pTargetDag )
  390. {
  391. Vector targetPos;
  392. pTargetDag->GetAbsPosition( targetPos );
  393. wsTargetPosition += ( pTarget->m_flWeight * ( targetPos + pTarget->m_vecOffset ) );
  394. flWeightSum += pTarget->m_flWeight;
  395. }
  396. }
  397. if ( flWeightSum > 0.0f )
  398. {
  399. wsTargetPosition *= 1.0f / flWeightSum;
  400. }
  401. return MIN( 1.0f, flWeightSum );
  402. }
  403. static const int MAX_RIG_TARGETS = 4;
  404. //-----------------------------------------------------------------------------
  405. // Compute the aggregate target orientation from the weighted target list and
  406. // return the total weight
  407. //-----------------------------------------------------------------------------
  408. float CDmeRigBaseConstraintOperator::ComputeTargetOrientation( Quaternion &wsTargetOrientation )
  409. {
  410. int nTargets = m_Targets.Count();
  411. // If there is only one target, for efficiency don't bother with the weighting
  412. if ( nTargets == 1 )
  413. {
  414. CDmeConstraintTarget *pTarget = m_Targets[ 0 ];
  415. CDmeDag *pTargetDag = pTarget->m_Handle;
  416. if ( !pTargetDag )
  417. return 0;
  418. Quaternion targetOrientation;
  419. Quaternion offsetOrientation;
  420. pTargetDag->GetAbsOrientation( targetOrientation );
  421. QuaternionMult( targetOrientation, pTarget->m_qOffset, wsTargetOrientation );
  422. return MIN( 1.0f, pTarget->m_flWeight.Get() );
  423. }
  424. int nAllocCount = MAX( nTargets, 1 );
  425. Quaternion *pQuats = ( Quaternion* )stackalloc( nAllocCount * sizeof( Quaternion ) );
  426. float *flQuatWeights = ( float* )stackalloc( nAllocCount * sizeof( float ) );
  427. wsTargetOrientation = quat_identity;
  428. float flWeightSum = 0.0f;
  429. int nQuatCount = 0;
  430. for ( int i = 0; i < nTargets; ++i )
  431. {
  432. CDmeConstraintTarget *pTarget = m_Targets[ i ];
  433. Assert( pTarget );
  434. CDmeDag *pTargetDag = pTarget->m_Handle;
  435. if ( !pTargetDag )
  436. continue;
  437. Quaternion targetOrientation;
  438. Quaternion offsetOrientation;
  439. pTargetDag->GetAbsOrientation( targetOrientation );
  440. QuaternionMult( targetOrientation, pTarget->m_qOffset, offsetOrientation );
  441. pQuats[ nQuatCount ] = offsetOrientation;
  442. flQuatWeights[ nQuatCount ] = pTarget->m_flWeight;
  443. flWeightSum += pTarget->m_flWeight;
  444. ++nQuatCount;
  445. }
  446. QuaternionAverageExponential( wsTargetOrientation, nQuatCount, pQuats, flQuatWeights );
  447. return MIN( 1.0f, flWeightSum );
  448. }
  449. //-----------------------------------------------------------------------------
  450. // Purpose: Get a list of all of the operators that the operation of the
  451. // constraint depends on.
  452. //-----------------------------------------------------------------------------
  453. void CDmeRigBaseConstraintOperator::GatherInputOperators( CUtlVector< CDmeOperator * > &operatorList )
  454. {
  455. // Iterate through the targets and add the operator
  456. // dependencies for the associated dag nodes.
  457. int nTargets = m_Targets.Count();
  458. for ( int i = 0; i < nTargets; ++i )
  459. {
  460. CDmeConstraintTarget *pTarget = m_Targets[ i ];
  461. Assert( pTarget );
  462. CDmeDag *pHandle = pTarget->m_Handle;
  463. if ( !pHandle )
  464. continue;
  465. pHandle->FindRelevantOperators( operatorList );
  466. }
  467. BaseClass::GatherInputOperators( operatorList );
  468. }
  469. //-----------------------------------------------------------------------------
  470. // Purpose: Disconnect the channels driving the slave dag nodes from the dag
  471. // transforms and connect them to the constraint
  472. //-----------------------------------------------------------------------------
  473. void CDmeRigBaseConstraintOperator::DisconnectTransformChannels()
  474. {
  475. DisconnectSlaveChannels( m_Slave.GetElement(), GetOutputAttributeType() );
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Purpose: Reconnect the base channels of each slave directly to the dag
  479. //-----------------------------------------------------------------------------
  480. void CDmeRigBaseConstraintOperator::ReconnectTransformChannels()
  481. {
  482. ReconnectSlaveChannels( m_Slave.GetElement(), GetOutputAttributeType() );
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose: Disconnect the channels driving the specified slave from the dag
  486. // and connect them to the constraint
  487. //-----------------------------------------------------------------------------
  488. void CDmeRigBaseConstraintOperator::DisconnectSlaveChannels( CDmeConstraintSlave *pSlave, int attributeTypeFlags )
  489. {
  490. // Verify that the specified slave is valid and has a dag node connected.
  491. if ( pSlave == NULL )
  492. return;
  493. if ( pSlave->m_Dag.GetElement() == NULL )
  494. return;
  495. CDmeTransform *pTransform = pSlave->m_Dag->GetTransform();
  496. if ( pTransform == NULL )
  497. return;
  498. // Make the base position and orientation match the
  499. // current position and orientation of the transform.
  500. pSlave->SetBasePosition( pTransform->GetPosition() );
  501. pSlave->SetBaseOrientation( pTransform->GetOrientation() );
  502. // Find the channel targeting the position attribute of the transform and
  503. // re-connect it to the position attribute of the slave within the constraint.
  504. if ( attributeTypeFlags & AA_TYPE_POSITION )
  505. {
  506. CDmeChannel *pPosChannel = FindChannelTargetingElement( pTransform, TRANSFORM_POSITION );
  507. if ( pPosChannel )
  508. {
  509. pPosChannel->SetOutput( pSlave, TRANSFORM_POSITION );
  510. }
  511. }
  512. // Find the channel targeting the orientation attribute of the transform and
  513. // re-connect it to the orientation attribute of the slave within the constraint.
  514. if ( attributeTypeFlags & AA_TYPE_ORIENTATION )
  515. {
  516. CDmeChannel *pRotChannel = FindChannelTargetingElement( pTransform, TRANSFORM_ORIENTATION );
  517. if ( pRotChannel )
  518. {
  519. pRotChannel->SetOutput( pSlave, TRANSFORM_ORIENTATION );
  520. }
  521. }
  522. }
  523. //-----------------------------------------------------------------------------
  524. // Purpose: Reconnect the transform channels associated with the specified
  525. // slave directly to the dag
  526. //-----------------------------------------------------------------------------
  527. void CDmeRigBaseConstraintOperator::ReconnectSlaveChannels( CDmeConstraintSlave *pSlave, int attributeTypeFlags )
  528. {
  529. // Verify that the specified slave is valid and has a dag node connected.
  530. if ( pSlave == NULL )
  531. return;
  532. if ( pSlave->m_Dag.GetElement() == NULL )
  533. return;
  534. CDmeTransform *pTransform = pSlave->m_Dag->GetTransform();
  535. if ( pTransform == NULL )
  536. return;
  537. // Find the channel targeting the position attribute of the slave and
  538. // re-connect it to the position attribute of the transform.
  539. if ( attributeTypeFlags & AA_TYPE_POSITION )
  540. {
  541. CDmeChannel *pPosChannel = FindChannelTargetingElement( pSlave, TRANSFORM_POSITION );
  542. if ( pPosChannel )
  543. {
  544. pPosChannel->SetOutput( pTransform, TRANSFORM_POSITION );
  545. // If the channel is in pass through mode, update the control value with the
  546. // transform value so that the result of the constraint will be maintained.
  547. if ( pPosChannel->GetMode() == CM_PASS )
  548. {
  549. CDmElement *pControl = pPosChannel->GetFromElement();
  550. CDmeTransformControl *pTranformControl = CastElement< CDmeTransformControl >( pControl );
  551. if ( pTranformControl )
  552. {
  553. pTranformControl->SetPosition( pTransform->GetPosition() );
  554. }
  555. }
  556. }
  557. }
  558. // Find the channel targeting the orientation attribute of the slave and
  559. // re-connect it to the orientation attribute of the transform.
  560. if ( attributeTypeFlags & AA_TYPE_ORIENTATION )
  561. {
  562. CDmeChannel *pRotChannel = FindChannelTargetingElement( pSlave, TRANSFORM_ORIENTATION );
  563. if ( pRotChannel )
  564. {
  565. pRotChannel->SetOutput( pTransform, TRANSFORM_ORIENTATION );
  566. // If the channel is in pass through mode, update the control value with the
  567. // transform value so that the result of the constraint will be maintained.
  568. if ( pRotChannel->GetMode() == CM_PASS )
  569. {
  570. CDmElement *pControl = pRotChannel->GetFromElement();
  571. CDmeTransformControl *pTranformControl = CastElement< CDmeTransformControl >( pControl );
  572. if ( pTranformControl )
  573. {
  574. pTranformControl->SetOrientation( pTransform->GetOrientation() );
  575. }
  576. }
  577. }
  578. }
  579. }
  580. //-----------------------------------------------------------------------------
  581. // Purpose: Find the constraint target for the specified dag node
  582. //-----------------------------------------------------------------------------
  583. CDmeConstraintTarget *CDmeRigBaseConstraintOperator::FindConstraintTargetForDag( CDmeDag* pDagNode ) const
  584. {
  585. if ( pDagNode == NULL )
  586. return NULL;
  587. int nTargets = m_Targets.Count();
  588. for ( int iTarget = 0; iTarget < nTargets; ++iTarget )
  589. {
  590. CDmeConstraintTarget *pTarget = m_Targets[ iTarget ];
  591. if ( pTarget )
  592. {
  593. if ( pTarget->GetDag() == pDagNode )
  594. {
  595. return pTarget;
  596. }
  597. }
  598. }
  599. return NULL;
  600. }
  601. //-----------------------------------------------------------------------------
  602. // Purpose: Find all of the constraints that target the specified dag node
  603. //-----------------------------------------------------------------------------
  604. void CDmeRigBaseConstraintOperator::FindDagConstraints( const CDmeDag *pDagNode, CUtlVector< CDmeRigBaseConstraintOperator* > &constraintList )
  605. {
  606. if ( pDagNode == NULL )
  607. return;
  608. // Find the slave instances targeting the specified node
  609. CUtlVector< CDmeConstraintSlave* > slaveList;
  610. FindAncestorsReferencingElement( pDagNode, slaveList );
  611. // Find the constraints for each slave instance
  612. for ( int i = 0; i < slaveList.Count(); ++i )
  613. {
  614. FindAncestorsReferencingElement( slaveList[ i ], constraintList );
  615. }
  616. }
  617. //-----------------------------------------------------------------------------
  618. // Purpose: Find the constraint on the dag of the specified type
  619. //-----------------------------------------------------------------------------
  620. CDmeRigBaseConstraintOperator *CDmeRigBaseConstraintOperator::FindDagConstraint( CDmeDag *pDag, EConstraintType constraintType )
  621. {
  622. CUtlVector< CDmeRigBaseConstraintOperator* > constraintList;
  623. FindDagConstraints( pDag, constraintList );
  624. int nConstraints = constraintList.Count();
  625. for ( int iConstraint = 0; iConstraint < nConstraints; ++iConstraint )
  626. {
  627. CDmeRigBaseConstraintOperator *pConstraint = constraintList[ iConstraint ];
  628. if ( pConstraint )
  629. {
  630. if ( pConstraint->GetConstraintType() == constraintType )
  631. {
  632. return pConstraint;
  633. }
  634. }
  635. }
  636. return NULL;
  637. }
  638. //-------------------------------------------------------------------------------------------------
  639. // Purpose: Remove all of the constraints from the specified dag node.
  640. //-------------------------------------------------------------------------------------------------
  641. void CDmeRigBaseConstraintOperator::RemoveConstraintsFromDag( CDmeDag *pDag )
  642. {
  643. if ( pDag == NULL )
  644. return;
  645. // Find the constraints associated with the specified dag node.
  646. CUtlVector< CDmeConstraintSlave* > constraintSlaves;
  647. FindAncestorsReferencingElement( pDag, constraintSlaves );
  648. int nSlaves = constraintSlaves.Count();
  649. for ( int i = 0; i < nSlaves; ++i )
  650. {
  651. CDmeConstraintSlave *pSlave = constraintSlaves[ i ];
  652. if ( pSlave == NULL )
  653. continue;
  654. CDmeRigBaseConstraintOperator *pConstraint = pSlave->GetConstraint();
  655. if ( pConstraint )
  656. {
  657. DestroyConstraint( pConstraint );
  658. }
  659. }
  660. }
  661. //-------------------------------------------------------------------------------------------------
  662. // Purpose: Destroy the specified constraint and remove it from the animation set.
  663. //-------------------------------------------------------------------------------------------------
  664. void CDmeRigBaseConstraintOperator::DestroyConstraint( CDmeRigBaseConstraintOperator *pConstraint )
  665. {
  666. if ( pConstraint == NULL )
  667. return;
  668. CDmeAnimationSet *pAnimSet = FindAncestorReferencingElement< CDmeAnimationSet >( pConstraint );
  669. // Find the weight channels associated with the constraint targets.
  670. const CDmaElementArray< CDmeConstraintTarget > &targetList = pConstraint->GetTargets();
  671. int nTargets = targetList.Count();
  672. for ( int iTarget = 0; iTarget < nTargets; ++iTarget )
  673. {
  674. CDmeConstraintTarget *pTarget = targetList[ iTarget ];
  675. if ( pTarget == NULL )
  676. continue;
  677. CDmeChannel *pWeightChannel = pTarget->FindWeightChannel();
  678. if ( pWeightChannel == NULL )
  679. continue;
  680. // Destroy the control associated with the channel
  681. CDmElement* pControl = pWeightChannel->GetFromElement();
  682. if ( pControl )
  683. {
  684. if ( pAnimSet )
  685. {
  686. pAnimSet->RemoveControl( pControl );
  687. }
  688. CDmeRig::RemoveElementFromRig( pControl );
  689. DestroyElement( pControl );
  690. }
  691. // Remove the channel from the channels clip it belongs to
  692. CDmeChannelsClip *pChannelsClip = FindAncestorReferencingElement< CDmeChannelsClip >( pWeightChannel );
  693. if ( pChannelsClip )
  694. {
  695. pChannelsClip->RemoveChannel( pWeightChannel );
  696. }
  697. // Remove the channel from the rig.
  698. CDmeRig::RemoveElementFromRig( pWeightChannel );
  699. // Destroy the channel
  700. DestroyElement( pWeightChannel );
  701. }
  702. // Reconnect the original channels of the constrained dag back to the transform.
  703. pConstraint->ReconnectTransformChannels();
  704. // Remove the constraint from the animation set's list of operators or
  705. // from the shot if the constraint did not belong to an animation set.
  706. if ( pAnimSet )
  707. {
  708. pAnimSet->RemoveOperator( pConstraint );
  709. }
  710. CDmeFilmClip *pClip = FindAncestorReferencingElement< CDmeFilmClip >( pConstraint );
  711. if ( pClip )
  712. {
  713. pClip->RemoveOperator( pConstraint );
  714. }
  715. // Remove the constraint from the rig it belongs to, if any
  716. CDmeRig::RemoveElementFromRig( pConstraint );
  717. // Destroy the constraint element
  718. DestroyElement( pConstraint );
  719. }
  720. //-------------------------------------------------------------------------------------------------
  721. // Purpose: Get the string name associated with the specified constraint type.
  722. //-------------------------------------------------------------------------------------------------
  723. char const *CDmeRigBaseConstraintOperator::ConstraintTypeName( EConstraintType eType )
  724. {
  725. switch ( eType )
  726. {
  727. case CT_POINT:
  728. return( "pointConstraint" );
  729. case CT_ORIENT:
  730. return( "orientConstraint" );
  731. case CT_AIM:
  732. return( "aimConstraint" );
  733. case CT_IK:
  734. return( "ikConstraint" );
  735. case CT_PARENT:
  736. return( "parentConstraint" );
  737. case CT_ROTATION:
  738. return( "rotationConstraint" );
  739. default:
  740. break;
  741. }
  742. Assert( 0 );
  743. return "unknown";
  744. }
  745. //-------------------------------------------------------------------------------------------------
  746. //
  747. // CDmeRigPointConstraintOperator
  748. //
  749. //-------------------------------------------------------------------------------------------------
  750. //-----------------------------------------------------------------------------
  751. // Point Constraint
  752. //-----------------------------------------------------------------------------
  753. IMPLEMENT_ELEMENT_FACTORY( DmeRigPointConstraintOperator, CDmeRigPointConstraintOperator );
  754. void CDmeRigPointConstraintOperator::OnConstruction()
  755. {
  756. }
  757. void CDmeRigPointConstraintOperator::OnDestruction()
  758. {
  759. }
  760. void CDmeRigPointConstraintOperator::Operate()
  761. {
  762. VPROF_BUDGET( "CDmeRigPointConstraintOperator::Operate", "SFM" );
  763. CDmeDag *pSlaveDag = m_Slave->GetDag();
  764. if ( !pSlaveDag )
  765. return;
  766. // Calculate the current target position and the total weight
  767. // of the the targets contributing to the target position.
  768. Vector targetPos;
  769. float weight = ComputeTargetPosition( targetPos );
  770. // Blend between the target position and the base position using the target weight
  771. Vector finalPos = targetPos;
  772. if ( weight < 1.0f )
  773. {
  774. Vector basePosition;
  775. Quaternion baseOrientation;
  776. m_Slave->ComputeBaseWorldValues( basePosition, baseOrientation );
  777. finalPos = ( targetPos * weight ) + ( basePosition * ( 1.0f - weight ) );
  778. }
  779. // Update the transform of the dag with the new position.
  780. pSlaveDag->SetAbsPosition( finalPos );
  781. }
  782. //-------------------------------------------------------------------------------------------------
  783. //
  784. // CDmeRigOrientConstraintOperator
  785. //
  786. //-------------------------------------------------------------------------------------------------
  787. IMPLEMENT_ELEMENT_FACTORY( DmeRigOrientConstraintOperator, CDmeRigOrientConstraintOperator );
  788. void CDmeRigOrientConstraintOperator::OnConstruction()
  789. {
  790. }
  791. void CDmeRigOrientConstraintOperator::OnDestruction()
  792. {
  793. }
  794. void CDmeRigOrientConstraintOperator::Operate()
  795. {
  796. VPROF_BUDGET( "CDmeRigOrientConstraintOperator::Operate", "SFM" );
  797. CDmeDag *pSlaveDag = m_Slave->GetDag();
  798. if ( !pSlaveDag )
  799. return;
  800. // Compute the target orientation and weight
  801. Quaternion qTarget;
  802. float weight = ComputeTargetOrientation( qTarget );
  803. // Blend between the target orientation and the base orientation using the target weight
  804. Quaternion qFinalWorld = qTarget;
  805. if ( weight < 1.0f )
  806. {
  807. Vector basePosition;
  808. Quaternion baseOrientation;
  809. m_Slave->ComputeBaseWorldValues( basePosition, baseOrientation );
  810. QuaternionSlerp( baseOrientation, qTarget, weight, qFinalWorld );
  811. }
  812. matrix3x4_t parentToWorld;
  813. pSlaveDag->GetParentWorldMatrix( parentToWorld );
  814. Quaternion qParentToWorld;
  815. MatrixQuaternion( parentToWorld, qParentToWorld );
  816. Quaternion qParentToWorldInv;
  817. QuaternionInvert( qParentToWorld, qParentToWorldInv );
  818. Quaternion qFinalLocal;
  819. QuaternionMult( qParentToWorldInv, qFinalWorld, qFinalLocal );
  820. pSlaveDag->GetTransform()->SetOrientation( qFinalLocal );
  821. /*
  822. CDmeDag *pSlaveDag = m_Slave->GetDag();
  823. if ( !pSlaveDag )
  824. return;
  825. // Compute the target orientation and weight
  826. Quaternion qTarget;
  827. float weight = ComputeTargetOrientation( qTarget );
  828. // Blend between the target orientation and the base orientation using the target weight
  829. Vector basePosition;
  830. Quaternion baseOrientation;
  831. m_Slave->ComputeBaseWorldValues( basePosition, baseOrientation );
  832. Quaternion qFinal;
  833. QuaternionSlerp( baseOrientation, qTarget, weight, qFinal );
  834. // Update the orientation of the slave, but maintain the position.
  835. matrix3x4_t absTxForm;
  836. pSlaveDag->GetAbsTransform( absTxForm );
  837. Vector worldPos;
  838. MatrixGetColumn( absTxForm, 3, worldPos );
  839. AngleMatrix( qFinal, worldPos, absTxForm );
  840. pSlaveDag->SetAbsTransform( absTxForm );
  841. */
  842. }
  843. //-------------------------------------------------------------------------------------------------
  844. //
  845. // CDmeRigAimConstraintOperator
  846. //
  847. //-------------------------------------------------------------------------------------------------
  848. IMPLEMENT_ELEMENT_FACTORY( DmeRigAimConstraintOperator, CDmeRigAimConstraintOperator );
  849. void CDmeRigAimConstraintOperator::OnConstruction()
  850. {
  851. m_AimOffset.InitAndSet( this, "aimOffset", quat_identity );
  852. m_UpVector.InitAndSet( this, "upVector", Vector( 0, 0, 1 ) );
  853. m_UpSpaceTarget.Init( this, "upSpaceTarget" );
  854. m_UpType.InitAndSet( this, "upType", CConstraintBones::AC_UP_TYPE_OBJECT_ROTATION );
  855. }
  856. void CDmeRigAimConstraintOperator::OnDestruction()
  857. {
  858. }
  859. //-----------------------------------------------------------------------------
  860. // Purpose: Perform an update after targets are added to the constraint. Offset
  861. // means something slightly different for aim constraint, it's the rotation
  862. // needed to orient the aimVector back at the original slave object. So all
  863. // target offsets are simply cleared out.
  864. //-----------------------------------------------------------------------------
  865. void CDmeRigAimConstraintOperator::PostHandlesAdded( bool bPreserveOffset )
  866. {
  867. for ( int i = 0; i < m_Targets.Count(); ++i )
  868. {
  869. m_Targets[ i ]->ClearOffset();
  870. }
  871. }
  872. //-----------------------------------------------------------------------------
  873. // Purpose: Set the up vector to be used when calculating the orientation from
  874. // the target position. The up vector may be in world space or in the space of
  875. // a specified dag node.
  876. //-----------------------------------------------------------------------------
  877. void CDmeRigAimConstraintOperator::SetUpVector( const Vector &upVector, bool bPreserveOffset, const CDmeDag *pUpSpaceTarget )
  878. {
  879. CDmeDag *pDag = m_Slave->GetDag();
  880. if ( pDag == NULL )
  881. return;
  882. m_UpVector = upVector.Normalized();
  883. m_UpSpaceTarget = pUpSpaceTarget;
  884. UpdateOffset( bPreserveOffset );
  885. }
  886. //-----------------------------------------------------------------------------
  887. // Purpose: Set the up vector to be used when calculating the orientation from
  888. // the target position. The up vector may be in world space or in the space of
  889. // a specified dag node.
  890. //-----------------------------------------------------------------------------
  891. void CDmeRigAimConstraintOperator::SetUpType( int nUpType )
  892. {
  893. if ( nUpType < CConstraintBones::AC_UP_TYPE_FIRST || nUpType > CConstraintBones::AC_UP_TYPE_LAST )
  894. {
  895. nUpType = CConstraintBones::AC_UP_TYPE_OBJECT_ROTATION;
  896. }
  897. m_UpType = CConstraintBones::AC_UP_TYPE_OBJECT_ROTATION;
  898. }
  899. //-----------------------------------------------------------------------------
  900. // Purpose: Calculate the orientation needed to make a transform where the y
  901. // vector of the transform matches the forward vector and the z vector matches
  902. // the up reference vector as closely as possible. The x vector will be in the
  903. // plane defined by using the forward vector as the normal.
  904. //-----------------------------------------------------------------------------
  905. void CDmeRigAimConstraintOperator::AimAt( const Vector &vecForward, const Vector &referenceUp, Quaternion &q )
  906. {
  907. Vector forward = vecForward;
  908. forward.NormalizeInPlace();
  909. float ratio = DotProduct( forward, referenceUp );
  910. Vector up = referenceUp - ( forward * ratio );
  911. up.NormalizeInPlace();
  912. Vector right = forward.Cross( up );
  913. right.NormalizeInPlace();
  914. const Vector &x = right;
  915. const Vector &y = forward;
  916. const Vector &z = up;
  917. float tr = x.x + y.y + z.z;
  918. q.Init( y.z - z.y , z.x - x.z, x.y - y.x, tr + 1.0f );
  919. float radius = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
  920. if ( radius > FLT_EPSILON )
  921. {
  922. QuaternionNormalize( q );
  923. }
  924. else
  925. {
  926. matrix3x4_t rotMat;
  927. MatrixSetColumn( x, 0, rotMat );
  928. MatrixSetColumn( y, 1, rotMat );
  929. MatrixSetColumn( z, 2, rotMat );
  930. MatrixQuaternion( rotMat, q );
  931. }
  932. }
  933. //-----------------------------------------------------------------------------
  934. // Purpose: Calculate the target orientation of the aim constraint based on the
  935. // current slave position and the target position, using the up vector as a
  936. // reference to try and maintain.
  937. //-----------------------------------------------------------------------------
  938. float CDmeRigAimConstraintOperator::CalculateOrientation( Quaternion &targetOrientation )
  939. {
  940. CDmeDag *pDag = m_Slave->GetDag();
  941. if ( pDag == NULL )
  942. return 0.0f;
  943. CDmeTransform *pTransform = pDag->GetTransform();
  944. if ( pTransform == NULL )
  945. return 0.0f;
  946. // Compute the world space position of the target
  947. Vector wsTargetPos;
  948. float weight = ComputeTargetPosition( wsTargetPos );
  949. // Construct the matrix to convert from world space to the parent space of the slave
  950. matrix3x4_t parentToWorld;
  951. matrix3x4_t worldToParent;
  952. pDag->GetParentWorldMatrix( parentToWorld );
  953. MatrixInvert( parentToWorld, worldToParent );
  954. // If the up vector is in world space, convert it into local space
  955. Vector worldUp;
  956. Vector localUp;
  957. const CDmeDag *pUpSpaceDag = m_UpSpaceTarget;
  958. switch ( m_UpType )
  959. {
  960. case CConstraintBones::AC_UP_TYPE_VECTOR:
  961. VectorCopy( m_UpVector, worldUp );
  962. break;
  963. case CConstraintBones::AC_UP_TYPE_OBJECT:
  964. if ( pUpSpaceDag )
  965. {
  966. matrix3x4_t localToWorld;
  967. pUpSpaceDag->GetAbsTransform( localToWorld );
  968. Vector vUpObjectWorldPos;
  969. MatrixPosition( localToWorld, vUpObjectWorldPos );
  970. Vector vSlaveWorldPos;
  971. VectorTransform( pTransform->GetPosition(), parentToWorld, vSlaveWorldPos );
  972. VectorSubtract( vUpObjectWorldPos, vSlaveWorldPos, worldUp );
  973. VectorNormalize( worldUp );
  974. }
  975. else
  976. {
  977. VectorCopy( m_UpVector, worldUp );
  978. }
  979. break;
  980. case CConstraintBones::AC_UP_TYPE_PARENT_ROTATION:
  981. VectorRotate( m_UpVector, parentToWorld, worldUp );
  982. break;
  983. default:
  984. case CConstraintBones::AC_UP_TYPE_OBJECT_ROTATION:
  985. if ( pUpSpaceDag )
  986. {
  987. matrix3x4_t localToWorld;
  988. pUpSpaceDag->GetAbsTransform( localToWorld );
  989. VectorRotate( m_UpVector, localToWorld, worldUp );
  990. }
  991. else
  992. {
  993. VectorCopy( m_UpVector, worldUp );
  994. }
  995. break;
  996. }
  997. VectorRotate( worldUp, worldToParent, localUp );
  998. // Convert the target's world space position into the local space of the slave.
  999. Vector lsTargetPos;
  1000. VectorTransform( wsTargetPos, worldToParent, lsTargetPos );
  1001. // Compute the local space forward vector
  1002. Vector slavePos = pTransform->GetPosition();
  1003. Vector forward = lsTargetPos - slavePos;
  1004. forward.NormalizeInPlace();
  1005. // Compute the orientation
  1006. AimAt( forward, localUp, targetOrientation );
  1007. {
  1008. Quaternion qAim;
  1009. matrix3x4_t mUpToWorld;
  1010. if ( pUpSpaceDag )
  1011. {
  1012. pUpSpaceDag->GetAbsTransform( mUpToWorld );
  1013. }
  1014. else
  1015. {
  1016. SetIdentityMatrix( mUpToWorld );
  1017. }
  1018. CConstraintBones::ComputeAimConstraint( qAim, wsTargetPos, parentToWorld, m_UpVector.Get(), slavePos, &mUpToWorld, static_cast< CConstraintBones::AimConstraintUpType_t >( m_UpType.Get() ) );
  1019. Assert( QuaternionsAreEqual( qAim, targetOrientation, 1.0e-5 ) );
  1020. }
  1021. return weight;
  1022. }
  1023. //-----------------------------------------------------------------------------
  1024. // Purpose: Calculate the rotational offset which will be applied after aiming
  1025. // the transform at the target location. The rotational offset essentially
  1026. // allows the selection of which direction within the slave's space will be
  1027. // considered the forward direction and will point towards the target.
  1028. //-----------------------------------------------------------------------------
  1029. void CDmeRigAimConstraintOperator::UpdateOffset( bool bPreserveOffset )
  1030. {
  1031. if ( !bPreserveOffset )
  1032. {
  1033. m_AimOffset = quat_identity;
  1034. return;
  1035. }
  1036. CDmeDag *pDag = m_Slave->GetDag();
  1037. if ( pDag == NULL )
  1038. return;
  1039. CDmeTransform *pTransform = pDag->GetTransform();
  1040. if ( pTransform == NULL )
  1041. return;
  1042. // Calculate the desired orientation based the target position
  1043. Quaternion targetOrientation;
  1044. CalculateOrientation( targetOrientation );
  1045. // Compute the difference between the slave's current orientation and the target orientation
  1046. Quaternion slaveOrientation = pTransform->GetOrientation();
  1047. Quaternion qInv, aimOffset;
  1048. QuaternionInvert( targetOrientation, qInv );
  1049. QuaternionMult( qInv, slaveOrientation, aimOffset );
  1050. m_AimOffset = aimOffset;
  1051. }
  1052. //-----------------------------------------------------------------------------
  1053. // Purpose: Operate the aim constraint, modifying the orientation of the slave
  1054. // so that it looks at the target position.
  1055. //-----------------------------------------------------------------------------
  1056. void CDmeRigAimConstraintOperator::Operate()
  1057. {
  1058. VPROF_BUDGET( "CDmeRigAimConstraintOperator::Operate", "SFM" );
  1059. CDmeDag *pDag = m_Slave->GetDag();
  1060. if ( pDag == NULL )
  1061. return;
  1062. CDmeTransform *pTransform = pDag->GetTransform();
  1063. if ( pTransform == NULL )
  1064. return;
  1065. // Calculate the desired orientation based the target position
  1066. Quaternion targetOrientation;
  1067. float targetWeight = CalculateOrientation( targetOrientation );
  1068. // Add in initial offset
  1069. Quaternion offsetOrientation;
  1070. QuaternionMult( targetOrientation, m_AimOffset, offsetOrientation );
  1071. // Blend between the target orientation and the base orientation using the target weight
  1072. Quaternion finalOrientation;
  1073. Quaternion baseOrientation = m_Slave->GetBaseOrientation();
  1074. QuaternionSlerp( baseOrientation, offsetOrientation, targetWeight, finalOrientation );
  1075. // Update the orientation of the slave
  1076. pTransform->SetOrientation( finalOrientation );
  1077. }
  1078. //-----------------------------------------------------------------------------
  1079. // Purpose: Get the attributes that the constraint reads data from, Inputs are
  1080. // CDmeDags (handles usually)
  1081. //-----------------------------------------------------------------------------
  1082. void CDmeRigAimConstraintOperator::GetInputAttributes( CUtlVector< CDmAttribute * > &attrs )
  1083. {
  1084. CDmeRigBaseConstraintOperator::GetInputAttributes( attrs );
  1085. // The position of the slave must be evaluated be
  1086. CDmeDag *pSlaveDag = m_Slave->GetDag();
  1087. if ( pSlaveDag )
  1088. {
  1089. AddAttribute( attrs, AA_TYPE_POSITION, pSlaveDag->GetTransform() );
  1090. }
  1091. }
  1092. //-------------------------------------------------------------------------------------------------
  1093. //
  1094. // CDmeRigRotationConstraintOperator
  1095. //
  1096. //-------------------------------------------------------------------------------------------------
  1097. IMPLEMENT_ELEMENT_FACTORY( DmeRigRotationConstraintOperator, CDmeRigRotationConstraintOperator );
  1098. //-----------------------------------------------------------------------------
  1099. // Purpose: Perform post construction operations, including initializing member
  1100. // attributes.
  1101. //-----------------------------------------------------------------------------
  1102. void CDmeRigRotationConstraintOperator::OnConstruction()
  1103. {
  1104. m_Rotations.Init( this, "rotations" );
  1105. m_Axies.Init( this, "axies" );
  1106. }
  1107. //-----------------------------------------------------------------------------
  1108. // Purpose: Perform shutdown and cleanup operations.
  1109. //-----------------------------------------------------------------------------
  1110. void CDmeRigRotationConstraintOperator::OnDestruction()
  1111. {
  1112. }
  1113. //-----------------------------------------------------------------------------
  1114. // Purpose: Run the operator, this calculates the resulting quaternion
  1115. // orientation and stores it in result.
  1116. //-----------------------------------------------------------------------------
  1117. void CDmeRigRotationConstraintOperator::Operate()
  1118. {
  1119. VPROF_BUDGET( "CDmeRigRotationConstraintOperator::Operate", "SFM" );
  1120. CDmeDag *pDag = m_Slave->GetDag();
  1121. if ( pDag == NULL )
  1122. return;
  1123. CDmeTransform *pTransform = pDag->GetTransform();
  1124. if ( pTransform == NULL )
  1125. return;
  1126. Quaternion finalOrientation = quat_identity;
  1127. int nAxies = MIN( m_Axies.Count(), m_Rotations.Count() );
  1128. for ( int iAxis = 0; iAxis < nAxies; ++iAxis )
  1129. {
  1130. Vector axis = m_Axies[ iAxis ];
  1131. float rotation = m_Rotations[ iAxis ];
  1132. Quaternion orientation;
  1133. AxisAngleQuaternion( axis, rotation, orientation );
  1134. QuaternionNormalize( orientation );
  1135. QuaternionMult( orientation, finalOrientation, finalOrientation );
  1136. QuaternionNormalize( finalOrientation );
  1137. }
  1138. // Update the orientation of the slave
  1139. pTransform->SetOrientation( finalOrientation );
  1140. }
  1141. //-----------------------------------------------------------------------------
  1142. // Purpose: Add the input attribute used by the operator to the provided list
  1143. // of attributes, This is generally used by the evaluation process to find the
  1144. // attributes an operator is dependent on.
  1145. //-----------------------------------------------------------------------------
  1146. void CDmeRigRotationConstraintOperator::GetInputAttributes( CUtlVector< CDmAttribute * > &attrs )
  1147. {
  1148. attrs.AddToTail( m_Axies.GetAttribute() );
  1149. attrs.AddToTail( m_Rotations.GetAttribute() );
  1150. }
  1151. //-----------------------------------------------------------------------------
  1152. // Purpose: Add a rotation axis
  1153. //-----------------------------------------------------------------------------
  1154. int CDmeRigRotationConstraintOperator::AddAxis( const Vector &axis )
  1155. {
  1156. int index = m_Axies.AddToTail( axis );
  1157. m_Rotations.AddToTail( 0.0f );
  1158. Assert( m_Rotations.Count() == m_Axies.Count() );
  1159. return index;
  1160. }
  1161. //-----------------------------------------------------------------------------
  1162. // Purpose: Set the axis around which the rotation is to occur
  1163. //-----------------------------------------------------------------------------
  1164. void CDmeRigRotationConstraintOperator::SetAxis( const Vector &axis, int index )
  1165. {
  1166. if ( index < m_Axies.Count() )
  1167. {
  1168. m_Axies.Set( index, axis );
  1169. }
  1170. }
  1171. //-----------------------------------------------------------------------------
  1172. // Purpose: Set current rotation value
  1173. //-----------------------------------------------------------------------------
  1174. void CDmeRigRotationConstraintOperator::SetRotation( float rotation, int index )
  1175. {
  1176. if ( index < m_Rotations.Count() )
  1177. {
  1178. m_Rotations.Set( index, rotation );
  1179. }
  1180. }
  1181. //-------------------------------------------------------------------------------------------------
  1182. //
  1183. // Parent Constraint
  1184. //
  1185. //-------------------------------------------------------------------------------------------------
  1186. IMPLEMENT_ELEMENT_FACTORY( DmeRigParentConstraintOperator, CDmeRigParentConstraintOperator );
  1187. void CDmeRigParentConstraintOperator::OnConstruction()
  1188. {
  1189. }
  1190. void CDmeRigParentConstraintOperator::OnDestruction()
  1191. {
  1192. }
  1193. //-------------------------------------------------------------------------------------------------
  1194. // Compute the offsets of the specified target based on the relative transforms of the target to
  1195. // the slave
  1196. //-------------------------------------------------------------------------------------------------
  1197. void CDmeRigParentConstraintOperator::ComputeOffset( Vector &vOffset, Quaternion &qOffset, CDmeConstraintTarget *pTarget, bool bPreserveOffset )
  1198. {
  1199. CDmeDag *pSlaveDag = m_Slave->GetDag();
  1200. CDmeDag *pTargetDag = pTarget->GetDag();
  1201. Assert( pSlaveDag );
  1202. if ( !bPreserveOffset || !pSlaveDag|| !pTargetDag )
  1203. {
  1204. vOffset = vec3_origin;
  1205. qOffset = quat_identity;
  1206. return;
  1207. }
  1208. // Get slave abs info
  1209. matrix3x4_t mS;
  1210. m_Slave->GetBaseWorldTransform( mS );
  1211. matrix3x4_t mT;
  1212. pTargetDag->GetAbsTransform( mT );
  1213. matrix3x4_t invT;
  1214. MatrixInvert( mT, invT );
  1215. // Compute slave offset local to target transform
  1216. matrix3x4_t offset;
  1217. ConcatTransforms( invT, mS, offset );
  1218. MatrixAngles( offset, qOffset, vOffset );
  1219. }
  1220. //-------------------------------------------------------------------------------------------------
  1221. // Compute the aggregate target position and orientation from the weighted target list and return
  1222. // the resulting position and orientation in addition to updating the target dag.
  1223. //-------------------------------------------------------------------------------------------------
  1224. float CDmeRigParentConstraintOperator::ComputeTargetPositionOrientation( Vector &wsTargetPos, Quaternion &wsTargetOrientation )
  1225. {
  1226. static Quaternion s_Quats[ MAX_RIG_TARGETS ];
  1227. static float s_flQuatWeights[ MAX_RIG_TARGETS ];
  1228. Quaternion *pQuats = s_Quats;
  1229. float *flQuatWeights = s_flQuatWeights;
  1230. int nTargets = m_Targets.Count();
  1231. if ( nTargets > MAX_RIG_TARGETS )
  1232. {
  1233. pQuats = (Quaternion *)stackalloc( nTargets * sizeof( Quaternion ) );
  1234. flQuatWeights = (float *)stackalloc( nTargets * sizeof( float ) );
  1235. }
  1236. float weightSum = 0.0f;
  1237. wsTargetPos = vec3_origin;
  1238. wsTargetOrientation = quat_identity;
  1239. int nQuatCount = 0;
  1240. for ( int i = 0; i < nTargets; ++i )
  1241. {
  1242. CDmeConstraintTarget *pTarget = m_Targets[ i ];
  1243. Assert( pTarget );
  1244. CDmeDag *pTargetDag = pTarget->GetDag();
  1245. if ( !pTargetDag )
  1246. continue;
  1247. float flWeight = pTarget->GetWeight();
  1248. matrix3x4_t handleM;
  1249. pTargetDag->GetAbsTransform( handleM );
  1250. matrix3x4_t offset;
  1251. Vector vOffset = pTarget->GetPositionOfffset();
  1252. Quaternion qOffset = pTarget->GetOrientationOffset();
  1253. AngleMatrix( RadianEuler( qOffset ), vOffset, offset );
  1254. matrix3x4_t absTxForm;
  1255. ConcatTransforms( handleM, offset, absTxForm );
  1256. Vector pos;
  1257. Quaternion q;
  1258. MatrixAngles( absTxForm, q, pos );
  1259. wsTargetPos += ( flWeight * pos );
  1260. pQuats[ nQuatCount ] = q;
  1261. flQuatWeights[ nQuatCount ] = flWeight;
  1262. ++nQuatCount;
  1263. // For normalization
  1264. weightSum += flWeight;
  1265. }
  1266. if ( weightSum > 0.0f )
  1267. {
  1268. wsTargetPos *= 1.0f / weightSum;
  1269. }
  1270. QuaternionAverageExponential( wsTargetOrientation, nQuatCount, pQuats, flQuatWeights );
  1271. return MIN( 1.0f, weightSum );
  1272. }
  1273. void CDmeRigParentConstraintOperator::Operate()
  1274. {
  1275. VPROF_BUDGET( "CDmeRigParentConstraintOperator::Operate", "SFM" );
  1276. CDmeDag *pSlaveDag = m_Slave->GetDag();
  1277. if ( !pSlaveDag )
  1278. return;
  1279. // Compute the target orientation and weight
  1280. Vector targetPosition;
  1281. Quaternion targetOrientation;
  1282. float weight = ComputeTargetPositionOrientation( targetPosition, targetOrientation );
  1283. Vector finalPosition = targetPosition;
  1284. Quaternion finalOrientation = targetOrientation;
  1285. // Blend between the target orientation and the base orientation using the target weight
  1286. if ( weight < 1.0f )
  1287. {
  1288. Vector basePosition;
  1289. Quaternion baseOrientation;
  1290. m_Slave->ComputeBaseWorldValues( basePosition, baseOrientation );
  1291. VectorLerp( basePosition, targetPosition, weight, finalPosition );
  1292. QuaternionSlerp( baseOrientation, targetOrientation, weight, finalOrientation );
  1293. }
  1294. matrix3x4_t finalTransform;
  1295. AngleMatrix( RadianEuler( finalOrientation ), finalPosition, finalTransform );
  1296. pSlaveDag->SetAbsTransform( finalTransform );
  1297. }
  1298. //-----------------------------------------------------------------------------
  1299. // 3 joint (2 bone) IK Constraint
  1300. //-----------------------------------------------------------------------------
  1301. IMPLEMENT_ELEMENT_FACTORY( DmeRigIKConstraintOperator, CDmeRigIKConstraintOperator );
  1302. //-----------------------------------------------------------------------------
  1303. // Purpose: Perform initialization operations.
  1304. //-----------------------------------------------------------------------------
  1305. void CDmeRigIKConstraintOperator::OnConstruction()
  1306. {
  1307. m_StartOffsetRotation.InitAndSet( this, "startOffset", quat_identity );
  1308. m_MidOffsetRotation.InitAndSet( this, "midOffset", quat_identity );
  1309. m_PoleVector.InitAndSet( this, "poleVector", Vector( 0, 0, 1 ) );
  1310. m_PoleVectorTarget.Init( this, "pvTarget" );
  1311. m_StartJoint.InitAndCreate( this, "startJoint" );
  1312. m_MidJoint.InitAndCreate( this, "midJoint" );
  1313. m_EndJoint.InitAndCreate( this, "endJoint" );
  1314. }
  1315. //-----------------------------------------------------------------------------
  1316. // Purpose: Perform shutdown operations
  1317. //-----------------------------------------------------------------------------
  1318. void CDmeRigIKConstraintOperator::OnDestruction()
  1319. {
  1320. g_pDataModel->DestroyElement( m_StartJoint );
  1321. g_pDataModel->DestroyElement( m_MidJoint );
  1322. g_pDataModel->DestroyElement( m_EndJoint );
  1323. }
  1324. //-----------------------------------------------------------------------------
  1325. // Purpose: Validate that the start and end effector are set up and that there
  1326. // is only one intermediate bone between them forming a 2 bone ik chain. If
  1327. // specified calculate the offset of the current position of the bones from the
  1328. // target position calculated by the ik solution and store as an offset to be
  1329. // applied upon operation.
  1330. //-----------------------------------------------------------------------------
  1331. bool CDmeRigIKConstraintOperator::Setup( bool bPreserveOffset )
  1332. {
  1333. CDmeDag *pStartJoint = m_StartJoint->GetDag();
  1334. CDmeDag *pMidJoint = m_MidJoint->GetDag();
  1335. CDmeDag *pEndJoint = m_EndJoint->GetDag();
  1336. CDmeTransform *pStartTransform = pStartJoint->GetTransform();
  1337. CDmeTransform *pMidTransform = pMidJoint->GetTransform();
  1338. // Make sure all the joints have been specified.
  1339. if ( !pStartJoint || !pMidJoint || !pEndJoint )
  1340. return false;
  1341. // Verify the chain
  1342. if ( ( pEndJoint->GetParent() != pMidJoint ) || ( pMidJoint->GetParent() != pStartJoint ) )
  1343. return false;
  1344. // Make sure there is one and only one target and that it is valid
  1345. if ( m_Targets.Count() != 1 )
  1346. return false;
  1347. CDmeDag *pTargetDag = m_Targets[ 0 ]->GetDag();
  1348. if ( pTargetDag == NULL )
  1349. return false;
  1350. // Calculate the orientation that the start and end joints would be set to if the ik were run,
  1351. // the calculate the difference between the result and the current orientation.
  1352. if ( bPreserveOffset )
  1353. {
  1354. Quaternion qStartIK = quat_identity;
  1355. Quaternion qMidIK = quat_identity;
  1356. CalculateOrientations( qStartIK, qMidIK, quat_identity, quat_identity );
  1357. // Calculate the offset of the start joint
  1358. Quaternion qStartCurrent = pStartTransform->GetOrientation();
  1359. Quaternion qStartInv, qStartOffset;
  1360. QuaternionInvert( qStartIK, qStartInv );
  1361. QuaternionMult( qStartInv, qStartCurrent, qStartOffset );
  1362. m_StartOffsetRotation = qStartOffset;
  1363. // Calculate the offset of the mid joint, note the ik solve has to be re-run
  1364. // with the offset of the start joint to get the proper offset for the mid joint.
  1365. CalculateOrientations( qStartIK, qMidIK, m_StartOffsetRotation, quat_identity );
  1366. Quaternion qMidCurrent = pMidTransform->GetOrientation();
  1367. Quaternion qMidInv, qMidOffset;
  1368. QuaternionInvert( qMidIK, qMidInv );
  1369. QuaternionMult( qMidInv, qMidCurrent, qMidOffset );
  1370. m_MidOffsetRotation = qMidOffset;
  1371. }
  1372. return true;
  1373. }
  1374. //-----------------------------------------------------------------------------
  1375. // Purpose: Calculate the orientation needed to make a transform where the x
  1376. // vector of the transform matches the forward vector and the z vector matches
  1377. // the up reference vector as closely as possible. The y vector will be in the
  1378. // plane defined by using the forward vector as the normal.
  1379. //-----------------------------------------------------------------------------
  1380. void CDmeRigIKConstraintOperator::AimAt( const Vector &vecForward, const Vector &referenceUp, Quaternion &q )
  1381. {
  1382. Vector forward = vecForward;
  1383. forward.NormalizeInPlace();
  1384. float ratio = DotProduct( forward, referenceUp );
  1385. Vector up = referenceUp - ( forward * ratio );
  1386. up.NormalizeInPlace();
  1387. Vector left = up.Cross( forward );
  1388. left.NormalizeInPlace();
  1389. const Vector &x = forward;
  1390. const Vector &y = left;
  1391. const Vector &z = up;
  1392. float tr = x.x + y.y + z.z;
  1393. q.Init( y.z - z.y, z.x - x.z, x.y - y.x, tr + 1.0f );
  1394. float radius = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
  1395. if ( radius > FLT_EPSILON )
  1396. {
  1397. QuaternionNormalize( q );
  1398. }
  1399. else
  1400. {
  1401. matrix3x4_t rotMat;
  1402. MatrixSetColumn( x, 0, rotMat );
  1403. MatrixSetColumn( y, 1, rotMat );
  1404. MatrixSetColumn( z, 2, rotMat );
  1405. MatrixQuaternion( rotMat, q );
  1406. }
  1407. }
  1408. //-----------------------------------------------------------------------------
  1409. // Purpose: Perform the 2 bone ik solve to get target orientation for the
  1410. // start and mid bones and apply the specified offset rotations to get the
  1411. // final target orientation for each bone.
  1412. //-----------------------------------------------------------------------------
  1413. float CDmeRigIKConstraintOperator::CalculateOrientations( Quaternion &startBoneOrientation, Quaternion &midBoneOrientation, const Quaternion &startOffset, const Quaternion &midOffset )
  1414. {
  1415. // Get the pointers to the dag nodes and transforms that participate in the calculations.
  1416. CDmeDag *pStartJoint = m_StartJoint->GetDag();
  1417. CDmeDag *pMidJoint = m_MidJoint->GetDag();
  1418. CDmeDag *pEndJoint = m_EndJoint->GetDag();
  1419. CDmeTransform *pStartTransform = pStartJoint->GetTransform();
  1420. CDmeTransform *pMidTransform = pMidJoint->GetTransform();
  1421. CDmeTransform *pEndTransform = pEndJoint->GetTransform();
  1422. // Get the transform matrix of the parent of the start joint, this transform defines the
  1423. // local space of the start joint, which is the space in which the calculations will be done.
  1424. matrix3x4_t mLocalToWorld;
  1425. matrix3x4_t mWorldToLocal;
  1426. pStartJoint->GetParentWorldMatrix( mLocalToWorld );
  1427. MatrixInvert( mLocalToWorld, mWorldToLocal );
  1428. // Update the target position and get the result in world space
  1429. Vector wsTargetPos;
  1430. float weight = ComputeTargetPosition( wsTargetPos );
  1431. // Convert the world space target position into the local space
  1432. Vector lsTargetPos;
  1433. VectorTransform( wsTargetPos, mWorldToLocal, lsTargetPos );
  1434. // Find the axis, which is the vector from the start joint to the end joint and then calculate
  1435. // the distance of the axis and each of the bones. Additionally calculate vDir, the unit vector
  1436. // along the direction of the axis.
  1437. Vector startPos = pStartTransform->GetPosition();
  1438. Vector vAxis = lsTargetPos - startPos;
  1439. Vector vDir = vAxis;
  1440. float axisLen = VectorNormalize( vDir );
  1441. float boneLenA = pMidTransform->GetPosition().Length();
  1442. float boneLenB = pEndTransform->GetPosition().Length();
  1443. axisLen = MIN( axisLen, boneLenA + boneLenB );
  1444. lsTargetPos = startPos + ( vDir * axisLen );
  1445. // Find the up vector, this is the vector in plane perpendicular to the axis along which the
  1446. // mid point will move as a function of the length of the axis.
  1447. Vector vPole;
  1448. CDmeDag *pPoleVectorTarget = m_PoleVectorTarget;
  1449. if ( pPoleVectorTarget )
  1450. {
  1451. Vector wsPVTargetPos;
  1452. pPoleVectorTarget->GetAbsPosition( wsPVTargetPos );
  1453. Vector lsPVTargetPos;
  1454. VectorTransform( wsPVTargetPos, mWorldToLocal, lsPVTargetPos );
  1455. vPole = lsPVTargetPos - startPos;
  1456. }
  1457. else
  1458. {
  1459. VectorRotate( m_PoleVector, mWorldToLocal, vPole );
  1460. }
  1461. Vector vUp = vPole - ( vDir * DotProduct( vDir, vPole ) );
  1462. VectorNormalize( vUp );
  1463. // Calculate the distance from the start point to the axis mid point. The axis mid point is the
  1464. // location on the axis that is the projection of the final mid point position onto the axis.
  1465. float midAxisLen = ( ( boneLenA * boneLenA ) - ( boneLenB * boneLenB ) + ( axisLen * axisLen ) ) / ( 2.0f * axisLen );
  1466. // Calculate the distance of the mid point from the axis
  1467. float midDist = sqrt( MAX( 0, ( boneLenA * boneLenA ) - ( midAxisLen * midAxisLen ) ) );
  1468. // Calculate the vector to the new mid point position, and then calculate the new mid point position.
  1469. Vector vMid = ( vDir * midAxisLen ) + ( vUp * midDist );
  1470. Vector newMidPos = startPos + vMid;
  1471. // Calculate the orientation of the first bone
  1472. Quaternion qStartTarget;
  1473. AimAt( vMid, vUp, qStartTarget );
  1474. QuaternionMult( qStartTarget, startOffset, startBoneOrientation );
  1475. // Calculate the orientation of the second bone
  1476. Vector vEnd = lsTargetPos - newMidPos;
  1477. Quaternion qParentBoneOrientB;
  1478. Quaternion qInvBoneOrientA;
  1479. Quaternion qMidTarget;
  1480. AimAt( vEnd, vUp, qParentBoneOrientB );
  1481. QuaternionInvert( startBoneOrientation, qInvBoneOrientA );
  1482. QuaternionMult( qInvBoneOrientA, qParentBoneOrientB, qMidTarget );
  1483. QuaternionMult( qMidTarget, midOffset, midBoneOrientation );
  1484. return weight;
  1485. }
  1486. //-----------------------------------------------------------------------------
  1487. // Purpose: Run the ik solve and apply the results to the constrained bones.
  1488. //-----------------------------------------------------------------------------
  1489. void CDmeRigIKConstraintOperator::Operate()
  1490. {
  1491. VPROF_BUDGET( "CDmeRigIKConstraintOperator::Operate", "SFM" );
  1492. CDmeDag *pStartJoint = m_StartJoint->GetDag();
  1493. CDmeDag *pMidJoint = m_MidJoint->GetDag();
  1494. CDmeDag *pEndJoint = m_EndJoint->GetDag();
  1495. // Make sure all the joints have been specified.
  1496. if ( !pStartJoint || !pMidJoint || !pEndJoint )
  1497. return;
  1498. // Calculate the new orientation of the start and mid joints
  1499. Quaternion qStartTarget = quat_identity;
  1500. Quaternion qMidTarget = quat_identity;
  1501. float targetWeight = CalculateOrientations( qStartTarget, qMidTarget, m_StartOffsetRotation, m_MidOffsetRotation );
  1502. // Update the orientations of the start and mid point joints
  1503. CDmeTransform *pStartTransform = m_StartJoint->GetDag()->GetTransform();
  1504. CDmeTransform *pMidTransform = m_MidJoint->GetDag()->GetTransform();
  1505. Quaternion qStartBase = m_StartJoint->GetBaseOrientation();
  1506. Quaternion qMidBase = m_MidJoint->GetBaseOrientation();
  1507. Quaternion qStartFinal, qMidFinal;
  1508. QuaternionSlerp( qStartBase, qStartTarget, targetWeight, qStartFinal );
  1509. QuaternionSlerp( qMidBase, qMidTarget, targetWeight, qMidFinal );
  1510. pStartTransform->SetOrientation( qStartFinal );
  1511. pMidTransform->SetOrientation( qMidFinal );
  1512. }
  1513. //-----------------------------------------------------------------------------
  1514. // Purpose: Assign the dag nodes that to be controlled by the ik constraint.
  1515. //-----------------------------------------------------------------------------
  1516. void CDmeRigIKConstraintOperator::SetJoints( CDmeDag *pStartJoint, CDmeDag *pMidJoint, CDmeDag *pEndJoint )
  1517. {
  1518. m_StartJoint->SetDag( pStartJoint );
  1519. m_MidJoint->SetDag( pMidJoint );
  1520. m_EndJoint->SetDag( pEndJoint );
  1521. }
  1522. //-----------------------------------------------------------------------------
  1523. // Purpose: Set the world space pole vector for the ik constraint
  1524. //-----------------------------------------------------------------------------
  1525. void CDmeRigIKConstraintOperator::SetPoleVector( const Vector &poleVector )
  1526. {
  1527. m_PoleVector = poleVector;
  1528. }
  1529. //-----------------------------------------------------------------------------
  1530. // Purpose: Set the pole vector target, a dag node toward which the pole vector
  1531. // will point, overrides the standard pole vector.
  1532. //-----------------------------------------------------------------------------
  1533. void CDmeRigIKConstraintOperator::SetPoleVectorTarget( CDmeDag *pPoleVectorTarget )
  1534. {
  1535. m_PoleVectorTarget = pPoleVectorTarget;
  1536. }
  1537. //-----------------------------------------------------------------------------
  1538. // Purpose: Get the attributes which are written to by the constraint.
  1539. //-----------------------------------------------------------------------------
  1540. void CDmeRigIKConstraintOperator::GetOutputAttributes( CUtlVector< CDmAttribute * > &attrs )
  1541. {
  1542. AddAttribute( attrs, AA_TYPE_ORIENTATION, m_StartJoint->GetTransform() );
  1543. AddAttribute( attrs, AA_TYPE_ORIENTATION, m_MidJoint->GetTransform() );
  1544. }
  1545. //-----------------------------------------------------------------------------
  1546. // Purpose: Get the attributes upon which the constraint is dependent.
  1547. //-----------------------------------------------------------------------------
  1548. void CDmeRigIKConstraintOperator::GetInputAttributes( CUtlVector< CDmAttribute * > &attrs )
  1549. {
  1550. BaseClass::GetInputAttributes( attrs );
  1551. AddAncestorAttributes( attrs, m_StartJoint->GetDag() );
  1552. AddAttribute( attrs, AA_TYPE_POSITION, m_StartJoint->GetTransform() );
  1553. AddAttribute( attrs, AA_TYPE_POSITION, m_MidJoint->GetTransform() );
  1554. AddAttribute( attrs, AA_TYPE_POSITION, m_EndJoint->GetTransform() );
  1555. }
  1556. //-----------------------------------------------------------------------------
  1557. // Purpose: Find all of the channels relevant to all of the target handles
  1558. //-----------------------------------------------------------------------------
  1559. void CDmeRigIKConstraintOperator::GatherInputOperators( CUtlVector< CDmeOperator * > &operatorList )
  1560. {
  1561. if ( m_PoleVectorTarget.GetElement() )
  1562. {
  1563. m_PoleVectorTarget->FindRelevantOperators( operatorList );
  1564. }
  1565. BaseClass::GatherInputOperators( operatorList );
  1566. }
  1567. //-----------------------------------------------------------------------------
  1568. // Purpose: Compute the offset for the specified target. The ik constraint does
  1569. // not use target offsets, so this function simply clears the offset for the
  1570. // specified target.
  1571. //-----------------------------------------------------------------------------
  1572. void CDmeRigIKConstraintOperator::ComputeOffset( Vector &vOffset, Quaternion &qOffset, CDmeConstraintTarget *pTarget, bool bPreserveOffset )
  1573. {
  1574. // No target offset allowed
  1575. vOffset = vec3_origin;
  1576. qOffset = quat_identity;
  1577. }
  1578. //-----------------------------------------------------------------------------
  1579. // Purpose: Disconnect the channels driving the slave dag nodes from the dag
  1580. // transforms and connect them to the constraint
  1581. //-----------------------------------------------------------------------------
  1582. void CDmeRigIKConstraintOperator::DisconnectTransformChannels()
  1583. {
  1584. DisconnectSlaveChannels( m_StartJoint.GetElement(), AA_TYPE_ORIENTATION );
  1585. DisconnectSlaveChannels( m_MidJoint.GetElement(), AA_TYPE_ORIENTATION );
  1586. }
  1587. //-----------------------------------------------------------------------------
  1588. // Purpose: Reconnect the base channels of each slave directly to the dag
  1589. //-----------------------------------------------------------------------------
  1590. void CDmeRigIKConstraintOperator::ReconnectTransformChannels()
  1591. {
  1592. ReconnectSlaveChannels( m_StartJoint.GetElement(), AA_TYPE_ORIENTATION );
  1593. ReconnectSlaveChannels( m_MidJoint.GetElement(), AA_TYPE_ORIENTATION );
  1594. }
  1595. //-----------------------------------------------------------------------------
  1596. // Purpose: Get a pointer to the dag node the constraint is controlling. For
  1597. // the ik constraint this is the start joint, but both the start and the mid
  1598. // joint are actually 'slaves' of the constraint.
  1599. //-----------------------------------------------------------------------------
  1600. const CDmeDag *CDmeRigIKConstraintOperator::GetSlave() const
  1601. {
  1602. return m_StartJoint->GetDag();
  1603. }
  1604. //-----------------------------------------------------------------------------
  1605. // Purpose: Determine if the the constraint has slave with the specified name,
  1606. // for the ik constraint this is always false.
  1607. //-----------------------------------------------------------------------------
  1608. bool CDmeRigIKConstraintOperator::IsSlaveObject( char const *pchName ) const
  1609. {
  1610. // IK Handle doesn't have targets that can be added
  1611. return false;
  1612. }
  1613. //-------------------------------------------------------------------------------------------------
  1614. //
  1615. // CDmeRigTwistSlave
  1616. //
  1617. //-------------------------------------------------------------------------------------------------
  1618. //-----------------------------------------------------------------------------
  1619. // Expose the CDmeConstraintTarget class to the scene database
  1620. //-----------------------------------------------------------------------------
  1621. IMPLEMENT_ELEMENT_FACTORY( DmeRigTwistSlave, CDmeRigTwistSlave );
  1622. //-----------------------------------------------------------------------------
  1623. // Purpose: Perform initialization operations.
  1624. //-----------------------------------------------------------------------------
  1625. void CDmeRigTwistSlave::OnConstruction()
  1626. {
  1627. m_flWeight.Init( this, "weight" );
  1628. }
  1629. //-----------------------------------------------------------------------------
  1630. // Purpose: Perform shutdown operations
  1631. //-----------------------------------------------------------------------------
  1632. void CDmeRigTwistSlave::OnDestruction()
  1633. {
  1634. }
  1635. //-------------------------------------------------------------------------------------------------
  1636. //
  1637. // CDmeRigTwistConstraintOperator
  1638. //
  1639. //-------------------------------------------------------------------------------------------------
  1640. //-----------------------------------------------------------------------------
  1641. // Expose the CDmeConstraintTarget class to the scene database
  1642. //-----------------------------------------------------------------------------
  1643. IMPLEMENT_ELEMENT_FACTORY( DmeRigTwistConstraintOperator, CDmeRigTwistConstraintOperator );
  1644. //-----------------------------------------------------------------------------
  1645. // Purpose: Perform initialization operations.
  1646. //-----------------------------------------------------------------------------
  1647. void CDmeRigTwistConstraintOperator::OnConstruction()
  1648. {
  1649. m_bInverse.Init( this, "inverse" );
  1650. m_vUpAxis.InitAndSet( this, "upVector", Vector( 0.0f, 1.0f, 0.0f ) );
  1651. m_flWeights.Init( this, "weights" );
  1652. m_eSlaves.Init( this, "twistJoints" );
  1653. m_qParentBindRotation.InitAndSet( this, "parentBindRotation", quat_identity );
  1654. m_qChildBindRotation.InitAndSet( this, "childBindRotation", quat_identity );
  1655. }
  1656. //-----------------------------------------------------------------------------
  1657. // Purpose: Perform shutdown operations
  1658. //-----------------------------------------------------------------------------
  1659. void CDmeRigTwistConstraintOperator::OnDestruction()
  1660. {
  1661. ClearSlaves();
  1662. }
  1663. //-----------------------------------------------------------------------------
  1664. //
  1665. //-----------------------------------------------------------------------------
  1666. bool CDmeRigTwistConstraintOperator::SetTargets( CDmeDag *pDmeDagParent, CDmeDag *pDmeDagChild )
  1667. {
  1668. ClearHandles();
  1669. if ( !pDmeDagParent || !pDmeDagChild )
  1670. return false;
  1671. CDmeDag *dmeDags[] = { pDmeDagParent, pDmeDagChild };
  1672. float flWeights[] = { 1.0f, 1.0f };
  1673. AddHandles( 2, dmeDags, flWeights, false, NULL );
  1674. return true;
  1675. }
  1676. //-----------------------------------------------------------------------------
  1677. // Purpose: Return the DmeDag parent target or NULL
  1678. // m_Targets[0] is the parent target
  1679. //-----------------------------------------------------------------------------
  1680. CDmeDag *CDmeRigTwistConstraintOperator::GetParentTarget() const
  1681. {
  1682. return m_Targets.Count() >= 1 ? m_Targets[0]->GetDag() : NULL;
  1683. }
  1684. //-----------------------------------------------------------------------------
  1685. // Purpose: Return the DmeDag child target or NULL
  1686. // m_Targets[0] is the parent target
  1687. //-----------------------------------------------------------------------------
  1688. CDmeDag *CDmeRigTwistConstraintOperator::GetChildTarget() const
  1689. {
  1690. return m_Targets.Count() >= 2 ? m_Targets[1]->GetDag() : NULL;
  1691. }
  1692. //-----------------------------------------------------------------------------
  1693. // Purpose: Remove all slaves
  1694. //-----------------------------------------------------------------------------
  1695. void CDmeRigTwistConstraintOperator::ClearSlaves()
  1696. {
  1697. for ( int i = 0; i < m_eSlaves.Count(); ++i )
  1698. {
  1699. CDmeConstraintSlave *pDmeConstraintSlave = m_eSlaves[i];
  1700. if ( !pDmeConstraintSlave )
  1701. continue;
  1702. DestroyElement( pDmeConstraintSlave );
  1703. }
  1704. }
  1705. //-----------------------------------------------------------------------------
  1706. // Purpose: Add the specified DmeDag as a slave with the specified weight
  1707. // Returns: The index of the slave, -1 on failure
  1708. //-----------------------------------------------------------------------------
  1709. int CDmeRigTwistConstraintOperator::AddSlave( CDmeDag *pDmeDagSlave, float flWeight )
  1710. {
  1711. CDmeRigTwistSlave *pDmeRigTwistSlave = CreateElement< CDmeRigTwistSlave >( pDmeDagSlave->GetName(), GetFileId() );
  1712. if ( !pDmeRigTwistSlave )
  1713. return -1;
  1714. // This assume the current rotation of the specified dag is the base/bind rotation
  1715. matrix3x4_t mBind;
  1716. pDmeDagSlave->GetLocalMatrix( mBind );
  1717. Quaternion qBind;
  1718. MatrixQuaternion( mBind, qBind );
  1719. pDmeRigTwistSlave->SetDag( pDmeDagSlave );
  1720. pDmeRigTwistSlave->SetWeight( flWeight );
  1721. pDmeRigTwistSlave->SetBaseOrientation( qBind );
  1722. return m_eSlaves.AddToTail( pDmeRigTwistSlave );
  1723. }
  1724. //-----------------------------------------------------------------------------
  1725. // Purpose: Return the DmeDag of the slave at the specified index
  1726. //-----------------------------------------------------------------------------
  1727. CDmeDag *CDmeRigTwistConstraintOperator::GetSlaveDag( int i ) const
  1728. {
  1729. return m_eSlaves.Count() > i ? m_eSlaves[i]->GetDag() : NULL;
  1730. }
  1731. //-----------------------------------------------------------------------------
  1732. // Purpose: Return the weight of the slave at the specified index
  1733. //-----------------------------------------------------------------------------
  1734. float CDmeRigTwistConstraintOperator::GetSlaveWeight( int i ) const
  1735. {
  1736. return m_eSlaves.Count() > i ? m_eSlaves[i]->GetWeight() : 0.0f;
  1737. }
  1738. //-----------------------------------------------------------------------------
  1739. // Purpose: Set the bind orientation of the parent
  1740. //-----------------------------------------------------------------------------
  1741. void CDmeRigTwistConstraintOperator::SetParentBindRotation( const Quaternion &qBindRotation )
  1742. {
  1743. m_qParentBindRotation = qBindRotation;
  1744. }
  1745. //-----------------------------------------------------------------------------
  1746. // Purpose: Set the bind orientation of the child
  1747. //-----------------------------------------------------------------------------
  1748. void CDmeRigTwistConstraintOperator::SetChildBindRotation( const Quaternion &qBindRotation )
  1749. {
  1750. m_qChildBindRotation = qBindRotation;
  1751. }
  1752. //-----------------------------------------------------------------------------
  1753. // Purpose: Return the bind orientation of the slave at the specified index
  1754. //-----------------------------------------------------------------------------
  1755. const Quaternion &CDmeRigTwistConstraintOperator::GetSlaveBindOrientation( int i ) const
  1756. {
  1757. if ( m_eSlaves.Count() > i )
  1758. {
  1759. return m_eSlaves[i]->GetBaseOrientation();
  1760. }
  1761. else
  1762. {
  1763. return quat_identity;
  1764. }
  1765. }
  1766. //-----------------------------------------------------------------------------
  1767. // Purpose: Set the bind orientation of the slave at the specified index
  1768. //-----------------------------------------------------------------------------
  1769. void CDmeRigTwistConstraintOperator::SetSlaveBindOrientation( const Quaternion &qBindRotation, int i )
  1770. {
  1771. if ( m_eSlaves.Count() > i )
  1772. {
  1773. m_eSlaves[i]->SetBaseOrientation( qBindRotation );
  1774. }
  1775. }
  1776. //-----------------------------------------------------------------------------
  1777. // Purpose: Compute the twist
  1778. //-----------------------------------------------------------------------------
  1779. void CDmeRigTwistConstraintOperator::Operate()
  1780. {
  1781. VPROF_BUDGET( "CDmeRigTwistConstraintOperator::Operate", "SFM" );
  1782. /*
  1783. * TODO: Call the Twist constraint code
  1784. * But it needs to be moved into bonesetup first
  1785. * Right now this is just a data container
  1786. */
  1787. }
  1788. //-----------------------------------------------------------------------------
  1789. // Purpose: Get the attributes which are written to by the constraint.
  1790. //-----------------------------------------------------------------------------
  1791. void CDmeRigTwistConstraintOperator::GetOutputAttributes( CUtlVector< CDmAttribute * > &attrs )
  1792. {
  1793. for ( int i = 0; i < m_eSlaves.Count(); ++i )
  1794. {
  1795. CDmeConstraintSlave *pDmeConstraintSlave = m_eSlaves[i];
  1796. if ( !pDmeConstraintSlave )
  1797. continue;
  1798. AddAttribute( attrs, AA_TYPE_ORIENTATION, pDmeConstraintSlave->GetTransform() );
  1799. }
  1800. }
  1801. //-----------------------------------------------------------------------------
  1802. // Purpose: Compute the offset for the specified target. The twist constraint
  1803. // does not use target offsets, so this function simply clears the offset for the
  1804. // specified target.
  1805. //-----------------------------------------------------------------------------
  1806. void CDmeRigTwistConstraintOperator::ComputeOffset( Vector &vOffset, Quaternion &qOffset, CDmeConstraintTarget *pTarget, bool bPreserveOffset )
  1807. {
  1808. // No target offset allowed
  1809. vOffset = vec3_origin;
  1810. qOffset = quat_identity;
  1811. }
  1812. //-----------------------------------------------------------------------------
  1813. // Purpose: Disconnect the channels driving the slave dag nodes from the dag
  1814. // transforms and connect them to the constraint
  1815. //-----------------------------------------------------------------------------
  1816. void CDmeRigTwistConstraintOperator::DisconnectTransformChannels()
  1817. {
  1818. for ( int i = 0; i < m_eSlaves.Count(); ++i )
  1819. {
  1820. CDmeConstraintSlave *pDmeConstraintSlave = m_eSlaves[i];
  1821. if ( !pDmeConstraintSlave )
  1822. continue;
  1823. DisconnectSlaveChannels( pDmeConstraintSlave, AA_TYPE_ORIENTATION );
  1824. }
  1825. }
  1826. //-----------------------------------------------------------------------------
  1827. // Purpose: Reconnect the base channels of each slave directly to the dag
  1828. //-----------------------------------------------------------------------------
  1829. void CDmeRigTwistConstraintOperator::ReconnectTransformChannels()
  1830. {
  1831. for ( int i = 0; i < m_eSlaves.Count(); ++i )
  1832. {
  1833. CDmeConstraintSlave *pDmeConstraintSlave = m_eSlaves[i];
  1834. if ( !pDmeConstraintSlave )
  1835. continue;
  1836. ReconnectSlaveChannels( pDmeConstraintSlave, AA_TYPE_ORIENTATION );
  1837. }
  1838. }
  1839. //-----------------------------------------------------------------------------
  1840. // Purpose: Get a pointer to the dag node the constraint is controlling.
  1841. // Return the first
  1842. //-----------------------------------------------------------------------------
  1843. const CDmeDag *CDmeRigTwistConstraintOperator::GetSlave() const
  1844. {
  1845. return m_eSlaves.Count() ? m_eSlaves[0]->GetDag() : NULL;
  1846. }
  1847. //-----------------------------------------------------------------------------
  1848. // Purpose: Determine if the the constraint has slave with the specified name
  1849. //-----------------------------------------------------------------------------
  1850. bool CDmeRigTwistConstraintOperator::IsSlaveObject( char const *pchName ) const
  1851. {
  1852. for ( int i = 0; i < m_eSlaves.Count(); ++i )
  1853. {
  1854. CDmeConstraintSlave *pDmeConstraintSlave = m_eSlaves[i];
  1855. if ( !pDmeConstraintSlave )
  1856. continue;
  1857. if ( !V_stricmp( pchName, pDmeConstraintSlave->GetName() ) )
  1858. return true;
  1859. }
  1860. return false;
  1861. }