//***************************************************************************** // //! Computes the angle between two quaternions //! //! \param pfQIn1 is a source quaternion in W,X,Y,Z form //! \param pfQIn2 is a source quaternion in W,X,Y,Z form //! //! This function computes the angle between two quaternions. //! //! \return Returns the angle, in radians, between the two quaternions. // //***************************************************************************** float QuaternionAngle(float pfQIn1[4], float pfQIn2[4]) { float pfQInv[4]; float pfQProd[4]; // // Let Q1 and Q2 be two quaternions having components w,x,y,z. The angle // between the orientations represented by Q1 and Q2 can be calculated // with: // // angle = arccos( (Q2 * Q1').w ) * 2.0; // // where Q1' is the inverse of Q1 // // // Calculate the inverse of Q1 // QuaternionInverse(pfQInv, pfQIn1); // // Find the product of Q2 x Q1` // QuaternionMult(pfQProd, pfQIn2, pfQInv); // // calculate the arccos of the w component of the previous product. // return(acosf(pfQProd[Q_W]) * 2.0); }
void C_NPC_Hydra::StandardBlendingRules( Vector pos[], Quaternion q[], float currentTime, int boneMask ) { VPROF( "C_NPC_Hydra::StandardBlendingRules" ); studiohdr_t *hdr = GetModelPtr(); if ( !hdr ) { return; } int i; // check for changing model memory requirements bool bNewlyInited = false; if (m_numHydraBones != hdr->numbones) { m_numHydraBones = hdr->numbones; // build root animation float poseparam[MAXSTUDIOPOSEPARAM]; for (i = 0; i < hdr->numposeparameters; i++) { poseparam[i] = 0; } CalcPose( hdr, NULL, pos, q, 0.0f, 0.0f, poseparam, BONE_USED_BY_ANYTHING ); // allocate arrays if (m_boneLength) { delete[] m_boneLength; } m_boneLength = new float [m_numHydraBones]; if (m_vecPos) { delete[] m_vecPos; } m_vecPos = new Vector [m_numHydraBones]; if (m_iv_vecPos) { delete m_iv_vecPos; } m_iv_vecPos = new CInterpolatedVar< Vector >[m_numHydraBones]; for ( i = 0; i < m_numHydraBones; i++ ) { m_iv_vecPos[ i ].Setup( &m_vecPos[ i ], LATCH_SIMULATION_VAR | EXCLUDE_AUTO_LATCH | EXCLUDE_AUTO_INTERPOLATE ); } // calc models bone lengths m_maxPossibleLength = 0; for (i = 0; i < m_numHydraBones-1; i++) { m_boneLength[i] = (pos[i+1] - pos[i]).Length(); m_maxPossibleLength += m_boneLength[i]; } m_boneLength[i] = 0.0f; bNewlyInited = true; } // calc new bone setup if networked. if (m_bNewChain) { CalcBoneChain( m_vecPos, m_vecChain ); for (i = 0; i < m_numHydraBones; i++) { // debugoverlay->AddLineOverlay( m_vecPos[i], m_vecPos[i<m_numHydraBones-1?i+1:m_numHydraBones-1], 0, 255, 0, false, 0.1 ); m_vecPos[i] = m_vecPos[i] - GetAbsOrigin(); m_iv_vecPos[i].NoteChanged( this, m_fLatchFlags, currentTime ); } m_bNewChain = false; } // if just allocated, initialize bones if (bNewlyInited) { for (i = 0; i < m_numHydraBones; i++) { m_iv_vecPos[i].Reset(); } } for (i = 0; i < m_numHydraBones; i++) { m_iv_vecPos[i].Interpolate( this, currentTime ); pos[ i ] = m_vecPos[ i ]; } // calculate bone angles CalcBoneAngles( pos, q ); // rotate the last bone of the hydra 90 degrees since it's oriented differently than the others Quaternion qTmp; AngleQuaternion( QAngle( 0, -90, 0) , qTmp ); QuaternionMult( q[m_numHydraBones - 1], qTmp, q[m_numHydraBones - 1] ); }