ページ 11

Xファイルの行列アニメーションだけがうまくいきません

Posted: 2016年3月31日(木) 17:37
by H.MAI
Xファイルで回転・スケール・移動のアニメーションが設定されたファイルはうまく再生できるんですが
行列が格納されたファイルだけがうまく再生できません。
XファイルはたぶんSDKにある「tiny.x」というものなのですが、メッシュは正しく読み込めて表示もできますが
行列でアニメーションさせて見ても、変なガタガタした動きを少しするだけで、元々の動きとは似ても似つかない感じです。
一応、メッシュ自体は壊れないので、まったく見当違いな読み方はしてないとは思います。
ソースコードは全部を書くとすごく長くなるので、一部、問題がありそうな箇所だけ掲載してみます。
DirectX7ベースのコードです。

コード:


//使ってるクラスや構造体 -------
class RotateKey{
public:
	FLOAT time;
	D3DXQUATERNION rotate;
};


class ScaleKey{
public:
	FLOAT time;
	D3DXVECTOR3 scale;
};


class PositionKey{
public:
	FLOAT time;
	D3DXVECTOR3 position;
};

class MatrixKey{
public:
    FLOAT time;
    D3DMATRIX matrix;
};


class Animation{
public:
	std::string name;
	std::vector<RotateKey *> RotateKeyList;
	std::vector<ScaleKey *> ScaleKeyList;
	std::vector<PositionKey *> PositionKeyList;
    std::vector<MatrixKey *> MatrixKeyList;
	D3DMATRIX *m_mat;

	~Animation();
};


class CAnimationSet{
public:
	std::string name;
	std::vector<Animation *> AnimationList;

	HRESULT Load(char *fileName);
	~CAnimationSet();
};
//-------------



//アニメーションキー読み込み部分
HRESULT	ParseAnimationKey( LPDIRECTXFILEDATA pFileData, Animation* pAnimation)
{
	// Read	data from the file
	LONG  pData;
	DWORD dwSize;
	
	if(	FAILED(	pFileData->GetData(	NULL, &dwSize, (void**)&pData )	) )
		return NULL;
	
	// Read
	DWORD dwKeyType = *((DWORD*)pData);		pData += 4;
	DWORD dwNumKeys = *((DWORD*)pData);		pData += 4;
	
	RotateKey*		rotateKey;
	ScaleKey*		scaleKey;
	PositionKey*	positionKey;
    MatrixKey*      matrixKey;

    //CString dststr = "";
	
	for(DWORD i=0; i<dwNumKeys; i++)
	{
		DWORD dwTime		= *((DWORD*)pData);		pData += 4;
		DWORD dwFloatKeys	= *((DWORD*)pData);		pData += 4; // dwKeyTypeで分かるので無視
		
		switch(dwKeyType)
		{
		case 0: //回転キー
			{
				D3DXQUATERNION quat;
				quat.w = -*((float*)pData);		pData += 4;		// 逆にしてます
				quat.x = -*((float*)pData);		pData += 4;
				quat.y = -*((float*)pData);		pData += 4;
				quat.z = -*((float*)pData);		pData += 4;
				
				rotateKey = new RotateKey();
				rotateKey->time = (FLOAT)dwTime;
				rotateKey->rotate = quat;
				pAnimation->RotateKeyList.push_back( rotateKey );
			}
			break;
			
		case 1: //スケールキー
			{
				D3DXVECTOR3 v;
				v.x = *((float*)pData);		pData += 4;
				v.y = *((float*)pData);		pData += 4;
				v.z = *((float*)pData);		pData += 4;
				
				scaleKey = new ScaleKey();
				scaleKey->time = (FLOAT)dwTime;
				scaleKey->scale = v;
				pAnimation->ScaleKeyList.push_back( scaleKey );
			}
			break;
			
		case 2: //移動キー
			{
				D3DXVECTOR3 v;
				v.x = *((float*)pData);		pData += 4;
				v.y = *((float*)pData);		pData += 4;
				v.z = *((float*)pData);		pData += 4;
				
				positionKey = new PositionKey();
				positionKey->time = (FLOAT)dwTime;
				positionKey->position = v;
				pAnimation->PositionKeyList.push_back( positionKey );
			}
			break;
        default: //行列キーはこれでよい?
            {
                D3DMATRIX mat;
                mat._11 = *((float*)pData);		pData += 4;
                mat._12 = *((float*)pData);		pData += 4;
                mat._13 = *((float*)pData);		pData += 4;
                mat._14 = *((float*)pData);		pData += 4;
                mat._21 = *((float*)pData);		pData += 4;
                mat._22 = *((float*)pData);		pData += 4;
                mat._23 = *((float*)pData);		pData += 4;
                mat._24 = *((float*)pData);		pData += 4;
                mat._31 = *((float*)pData);		pData += 4;
                mat._32 = *((float*)pData);		pData += 4;
                mat._33 = *((float*)pData);		pData += 4;
                mat._34 = *((float*)pData);		pData += 4;
                mat._41 = *((float*)pData);		pData += 4;
                mat._42 = *((float*)pData);		pData += 4;
                mat._43 = *((float*)pData);		pData += 4;
                mat._44 = *((float*)pData);		pData += 4;

                matrixKey = new MatrixKey();
                matrixKey->time = (FLOAT)dwTime;
                matrixKey->matrix = mat;
                pAnimation->MatrixKeyList.push_back( matrixKey );
                
            }
            break;
		}
	}
	
	return S_OK;
}


//アニメーション再生部分(行列アニメ以外の回転・スケール・移動アニメは完璧に動作してる)
HRESULT CAnimObject::SetTime(FLOAT fTime)
{
	D3DXQUATERNION rotate;
	D3DXVECTOR3 scale, position;
	D3DMATRIX matRotate, matScale, matTrans, *mat = NULL, matMatrix;
	Animation* pTmpAnim;

	std::vector<Animation *>::iterator iter;
	for(iter = m_pAnimSet->AnimationList.begin(); iter != m_pAnimSet->AnimationList.end(); iter++){
		matRotate = InterpolateRotateKey(*iter, fTime);
		matScale = InterpolateScaleKey(*iter, fTime);
		matTrans = InterpolatePositionKey(*iter, fTime);
        matMatrix = InterpolateMatrixKey(*iter, fTime);

		pTmpAnim = *iter;
		mat = pTmpAnim->m_mat;

		D3DUtil_SetIdentityMatrix( *mat );
        D3DMath_MatrixMultiply( *mat, matTrans, *mat );
        D3DMath_MatrixMultiply( *mat, matRotate, *mat );
        D3DMath_MatrixMultiply( *mat, matScale, *mat );
        D3DMath_MatrixMultiply( *mat, matMatrix, *mat);
    }

	return S_OK;
}

//↑から呼び出されているキー検索部分
D3DMATRIX InterpolateMatrixKey(Animation *anim, FLOAT fTime)
{
	D3DMATRIX m;
	D3DMATRIX mat;
    D3DUtil_SetIdentityMatrix( mat );

	// 行列キーは存在しない
	if(anim->MatrixKeyList.size() == 0)	
        return mat;
	
	std::vector<MatrixKey *>::iterator first = anim->MatrixKeyList.begin();
	MatrixKey *pKey;
	
	// キーが一つしか存在しない場合
	pKey = *first;
	if(anim->MatrixKeyList.size() == 1){
		m = pKey->matrix;
		
	// キーが複数存在する場合
	}else{
        UINT iKey;
        UINT dwp2;
	    UINT dwp3;

        // 時間にあったキーフレームを検索する
		float Time = (float)fmod(fTime, anim->MatrixKeyList[anim->MatrixKeyList.size()-1]->time);
                                  
		for (iKey = 0 ;iKey < anim->MatrixKeyList.size() ; iKey++) {
			if ((float)anim->MatrixKeyList[iKey]->time > Time) {
				dwp3 = iKey;
				dwp2= (0<iKey)?(iKey - 1):iKey;
				break;
			}
		}
		float fTime1 = (float)anim->MatrixKeyList[dwp2]->time;
		float fTime2 = (float)anim->MatrixKeyList[dwp3]->time;
		// 時間の前後のキーフレームで近い方を選択する
		float fLerpValue = ((fTime2 - fTime1) !=0)?( (fTime - fTime1)  / (fTime2 - fTime1)):0;
		iKey = (0.5<fLerpValue)?dwp3:dwp2;
		m = anim->MatrixKeyList[iKey]->matrix;
	}

    D3DMath_MatrixMultiply(mat, m, mat);

	return mat;
}


Re: Xファイルの行列アニメーションだけがうまくいきません

Posted: 2016年3月31日(木) 21:01
by H.MAI
サンプルのXファイルはver8.0についていたものなようです。
8.0からシェーダが搭載されてるので、やっぱり7.0ベースのコードでは
同じようなアニメーションをさせるのは無理なのでしょうか?