//---------------------- // カーソルの動きを計算 //---------------------- void cMMDChar::calcCursorVec( float fInvElapsedFrame, const Vector3 *pvec3CursorPos ) { Vector3 vec3Diff; Vector3Sub( &vec3Diff, pvec3CursorPos, &m_vec3PrevCurPos ); m_vec3CurVec.x = (m_vec3CurVec.x + vec3Diff.x * fInvElapsedFrame) * 0.5f; m_vec3CurVec.y = (m_vec3CurVec.y + vec3Diff.y * fInvElapsedFrame) * 0.5f; m_vec3CurVec.z = (m_vec3CurVec.z + vec3Diff.z * fInvElapsedFrame) * 0.5f; m_fCurVecLength = (m_fCurVecLength + sqrtf( Vector3DotProduct( &vec3Diff, &vec3Diff ) ) * fInvElapsedFrame) * 0.5f; m_vec3PrevCurPos = *pvec3CursorPos; }
//======== // 初期化 //======== void cPMDBone::initialize( const PMD_Bone *pPMDBoneData, const cPMDBone pBoneArray[] ) { // ボーン名のコピー strncpy( m_szName, pPMDBoneData->szName, 20 ); m_szName[20] = '\0'; // 位置のコピー m_vec3OrgPosition = pPMDBoneData->vec3Position; // 親ボーンの設定 if( pPMDBoneData->nParentNo != -1 ) { m_pParentBone = &(pBoneArray[pPMDBoneData->nParentNo]); Vector3Sub( &m_vec3Offset, &m_vec3OrgPosition, &m_pParentBone->m_vec3OrgPosition ); } else { // 親なし m_vec3Offset = m_vec3OrgPosition; } // 子ボーンの設定 if( pPMDBoneData->nChildNo != -1 ) { m_pChildBone = (cPMDBone *)&(pBoneArray[pPMDBoneData->nChildNo]); } MatrixIdentity( m_matInvTransform ); m_matInvTransform[3][0] = -m_vec3OrgPosition.x; m_matInvTransform[3][1] = -m_vec3OrgPosition.y; m_matInvTransform[3][2] = -m_vec3OrgPosition.z; m_bIKLimitAngle = false; // 2009/08/07 Ru--en m_cbKind = pPMDBoneData->cbKind; // ボーン種類を記憶 m_cbRigidType = 0; // このボーンに関連付いた剛体タイプ // 各変数の初期値を設定 reset(); }
//============================================================================ // 親のボーン番号のほうが大きい場合におかしくなるので初期化終了後に再計算する //============================================================================ void cPMDBone::recalcOffset( void ) { if( m_pParentBone ) Vector3Sub( &m_vec3Offset, &m_vec3OrgPosition, &m_pParentBone->m_vec3OrgPosition ); }
//====== // 更新 //====== void cPMDIK::update( void ) { Vector3 vec3OrgTargetPos; vec3OrgTargetPos.x = m_pTargetBone->m_matLocal[3][0]; vec3OrgTargetPos.y = m_pTargetBone->m_matLocal[3][1]; vec3OrgTargetPos.z = m_pTargetBone->m_matLocal[3][2]; Vector3 vec3EffPos; Vector3 vec3TargetPos; for( short i = m_cbNumLink - 1 ; i >= 0 ; i-- ){ m_ppBoneList[i]->updateMatrix(); } m_pEffBone->updateMatrix(); for( unsigned short it = 0 ; it < m_unCount ; it++ ) { for( unsigned char cbLinkIdx = 0 ; cbLinkIdx < m_cbNumLink ; cbLinkIdx++ ) { // エフェクタの位置の取得 vec3EffPos.x = m_pEffBone->m_matLocal[3][0]; vec3EffPos.y = m_pEffBone->m_matLocal[3][1]; vec3EffPos.z = m_pEffBone->m_matLocal[3][2]; // ワールド座標系から注目ノードの局所(ローカル)座標系への変換 Matrix matInvBone; MatrixInverse( matInvBone, m_ppBoneList[cbLinkIdx]->m_matLocal ); // エフェクタ,到達目標のローカル位置 Vector3Transform( &vec3EffPos, &vec3EffPos, matInvBone ); Vector3Transform( &vec3TargetPos, &vec3OrgTargetPos, matInvBone ); // 十分近ければ終了 Vector3 vec3Diff; Vector3Sub( &vec3Diff, &vec3EffPos, &vec3TargetPos ); if( Vector3DotProduct( &vec3Diff, &vec3Diff ) < 0.0000001f ) return; // (1) 基準関節→エフェクタ位置への方向ベクトル Vector3Normalize( &vec3EffPos, &vec3EffPos ); // (2) 基準関節→目標位置への方向ベクトル Vector3Normalize( &vec3TargetPos, &vec3TargetPos ); // ベクトル (1) を (2) に一致させるための最短回転量(Axis-Angle) // // 回転角 float fRotAngle = acosf( Vector3DotProduct( &vec3EffPos, &vec3TargetPos ) ); if( 0.00000001f < fabsf( fRotAngle ) ) { if( fRotAngle < -m_fFact ) fRotAngle = -m_fFact; else if( m_fFact < fRotAngle ) fRotAngle = m_fFact; // 回転軸 Vector3 vec3RotAxis; Vector3CrossProduct( &vec3RotAxis, &vec3EffPos, &vec3TargetPos ); if( Vector3DotProduct( &vec3RotAxis, &vec3RotAxis ) < 0.0000001f ) continue; Vector3Normalize( &vec3RotAxis, &vec3RotAxis ); // 関節回転量の補正 Vector4 vec4RotQuat; QuaternionCreateAxis( &vec4RotQuat, &vec3RotAxis, fRotAngle ); if( m_ppBoneList[cbLinkIdx]->m_bIKLimitAngle ) limitAngle( &vec4RotQuat, &vec4RotQuat ); QuaternionNormalize( &vec4RotQuat, &vec4RotQuat ); QuaternionMultiply( &m_ppBoneList[cbLinkIdx]->m_vec4Rotation, &m_ppBoneList[cbLinkIdx]->m_vec4Rotation, &vec4RotQuat ); QuaternionNormalize( &m_ppBoneList[cbLinkIdx]->m_vec4Rotation, &m_ppBoneList[cbLinkIdx]->m_vec4Rotation ); for( short i = cbLinkIdx ; i >= 0 ; i-- ){ m_ppBoneList[i]->updateMatrix(); } m_pEffBone->updateMatrix(); } } } }