⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mlskinnedmesh.cpp

📁 这是一个混合动画的实例代码
💻 CPP
字号:
///////////////////////////////////////////////////////////////////////////////
// 
// File: mlSkinnedmesh.cpp
// 
// Author: Frank Luna (C) All Rights Reserved
//
// System: Athlon 1800+ XP, 512 DDR, Radeon 9500 Pro, Windows XP, MSVC++ 7.0 
//
// Desc: Contains the implementation of SkinnedMesh.
// 
///////////////////////////////////////////////////////////////////////////////

#include "mlSkinnedmesh.h"
#include <cassert>

using namespace dx_err;

SkinnedMesh::SkinnedMesh()
:_device(0), _skinnedMesh(0), _tex(0), _effect(0), _root(0), 
_maxVertInfluences(0), _numBones(0), _skinInfo(0), _animCtrl(0), _hTech(0), 
_hWorldViewProj(0), _hFinalTransforms(0), _hTex(0)
{
}

SkinnedMesh::~SkinnedMesh()
{
	deleteDeviceObjects();
}

void SkinnedMesh::initDeviceObjects(IDirect3DDevice9* device,
									const std::string& inputFilename)
{
	_device = device;

	AllocMeshHierarchy allocMeshHierarchy;
	THROW_DXERR(D3DXLoadMeshHierarchyFromX(inputFilename.c_str(), D3DXMESH_MANAGED,
		_device, &allocMeshHierarchy, 0, /* ignore user data */ 
		&_root,	&_animCtrl))


	D3DXFRAME* f = findNodeWithMesh(_root);
	if( f == 0 ) THROW_DXERR(E_FAIL);
	D3DXMESHCONTAINER* meshContainer = f->pMeshContainer;
	_skinInfo = meshContainer->pSkinInfo;
	_skinInfo->AddRef();


	_numBones = meshContainer->pSkinInfo->GetNumBones();
	_finalTransforms.resize(_numBones);
	_combinedTransforms.resize(_numBones);
	

	buildSkinnedMesh(meshContainer->MeshData.pMesh);
	buildCombinedTransforms();
	buildEffect();
	buildMaterials(meshContainer);
}

void SkinnedMesh::restoreDeviceObjects()
{
	// Call after a reset to restore the effect.
    if ( _effect )
        THROW_DXERR( _effect->OnResetDevice() )
}

void SkinnedMesh::deleteDeviceObjects()
{
	if( _root )
	{
		AllocMeshHierarchy allocMeshHierarchy;
		THROW_DXERR( D3DXFrameDestroy(_root, &allocMeshHierarchy) )
		_root = 0;
	}

	ReleaseCOM(_skinnedMesh);
	ReleaseCOM(_skinInfo);
	ReleaseCOM(_animCtrl);
	ReleaseCOM(_effect);
}

void SkinnedMesh::invalidateDeviceObjects()
{
	// Call before a reset device.
    if ( _effect )
        THROW_DXERR( _effect->OnLostDevice() );
}

HRESULT SkinnedMesh::confirmDevice(D3DCAPS9* pCaps)
{
	////////////////////////////////////////////////////////////////////////
	// User needs a graphics device that supports vertex shader version 2.0.

	if( pCaps->VertexShaderVersion < D3DVS_VERSION(2, 0) )
		return E_FAIL;

	return D3D_OK;
}

void SkinnedMesh::frameMove(float deltaTime, D3DXMATRIX& worldViewProj)
{
	//////////////////////////////////////////////////////////////////////
	// Animate the mesh.  The AnimationController has pointers to the 
	// hierarchy frame transform matrices.  The AnimationController updates
	// these matrices to reflect the given pose at the current time by 
	// interpolating between animation keyframes.

	_animCtrl->AdvanceTime(deltaTime, 0);

	
	//////////////////////////////////////////////////////////////////
	// Now that the frames are updated to the current pose, recurse
	// down the tree and generate a frame's combined-transform.

	D3DXMATRIX identity;
	D3DXMatrixIdentity(&identity);
	combineTransforms(static_cast<FrameEx*>(_root), identity);


	////////////////////////////////////////////////////////////
	// Add the offset-transform, note that this premultiplies 
	// the combined-transform.

	D3DXMATRIX offsetTemp, combinedTemp;
	for(UINT i = 0; i < _numBones; ++i)
	{
		offsetTemp   = *_skinInfo->GetBoneOffsetMatrix(i);
		combinedTemp = *_combinedTransforms[i];
		_finalTransforms[i] = offsetTemp * combinedTemp;
	}


	///////////////////////////////////////////////////////////////
	// Finally, set the final-transform matrix array to the effect.

	_effect->SetMatrix(_hWorldViewProj, &worldViewProj);
	_effect->SetMatrixArray(_hFinalTransforms, 
		&_finalTransforms[0], _finalTransforms.size());
}

void SkinnedMesh::render()
{
	_effect->SetTechnique(_hTech);
	UINT numPasses = 0;
	_effect->Begin(&numPasses, 0);

	for(UINT i = 0; i < numPasses; ++i)
	{
		_effect->BeginPass(i);

		// Draw the one and only subset.
		_skinnedMesh->DrawSubset(0);

		_effect->EndPass();
	}
	_effect->End();
}

D3DXFRAME* SkinnedMesh::findNodeWithMesh(D3DXFRAME* frame)
{
	// In this demo we stipulate that the input .X file contains only one
	// mesh.  So search for that one and only mesh.

	if( frame->pMeshContainer )
		if( frame->pMeshContainer->MeshData.pMesh != 0 )
			return frame;

	D3DXFRAME* f = 0;
	if(frame->pFrameSibling)
		if( f = findNodeWithMesh(frame->pFrameSibling) )	
			return f;

	if(frame->pFrameFirstChild)
		if( f = findNodeWithMesh(frame->pFrameFirstChild) )
			return f;

	return 0;
}

void SkinnedMesh::buildSkinnedMesh(ID3DXMesh* mesh)
{
	// The vertex format of the source mesh does not include vertex weights 
	// nor bone index data, both of which are needed for vertex blending.
	// Therefore, we must convert the source mesh to an "indexed-blended-mesh,"
	// which does have the necessary data.

	DWORD        numBoneComboEntries = 0;
	ID3DXBuffer* boneComboTable      = 0;

	THROW_DXERR( _skinInfo->ConvertToIndexedBlendedMesh(
		mesh, 
		D3DXMESH_MANAGED | D3DXMESH_WRITEONLY,  
		SkinnedMesh::MAX_NUM_BONES_SUPPORTED, 
		0, // ignore adjacency in
		0, // ignore adjacency out
		0, // ignore face remap
		0, // ignore vertex remap
		&_maxVertInfluences,
		&numBoneComboEntries, 
		&boneComboTable,
		&_skinnedMesh) )

	// We do not need the bone table, so just release it.
	ReleaseCOM(boneComboTable);
}

void SkinnedMesh::buildEffect()
{
	ID3DXBuffer* errorBuffer = 0;
	D3DXCreateEffectFromFile(_device, "vertBlendDynamic.txt", 0, 0,                
		D3DXSHADER_DEBUG, 0, &_effect, &errorBuffer);    

	if( errorBuffer )
	{
		::MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0, 0);
		ReleaseCOM(errorBuffer);
		ReleaseCOM(_effect);
	}
	else
	{
		_hTech            = _effect->GetTechniqueByName("VertexBlendingTech");
		_hWorldViewProj   = _effect->GetParameterByName(0, "WorldViewProj");
		_hFinalTransforms = _effect->GetParameterByName(0, "FinalTransforms");
		_hTex             = _effect->GetParameterByName(0, "Tex");
	}
}

void SkinnedMesh::buildMaterials(D3DXMESHCONTAINER* meshContainer)
{
	// In this demo we assume the skinned mesh has exactly one texture.
	// So load and set that texture with the effect interface.

	D3DXMATERIAL* mtrls = meshContainer->pMaterials;
	DWORD numMtrls = meshContainer->NumMaterials;
	assert(numMtrls == 1);

	if( mtrls[0].pTextureFilename )
	{
		IDirect3DTexture9* tex = 0;
		THROW_DXERR(
			D3DXCreateTextureFromFile(_device, mtrls[0].pTextureFilename, &tex))
		
		THROW_DXERR(_effect->SetTexture(_hTex, tex))
		ReleaseCOM(tex);
	}
}

void SkinnedMesh::buildCombinedTransforms()
{
	// Get an array of pointers to the combined frame transformations.  We 
	// store the pointers such that the ith pointer corresponds with the 
	// ith offset-matrix.  Thus, given the ith bone, we can obtain its ith 
	// offset matrix and ith transform.  
	//     We note that the skinInfo object converted the source mesh to a 
	// indexed-blended-mesh.  It follows then that the  bone indices for 
	// the vertices are relative to the skinInfo bone array.  Therefore
	// we base everything relative to the offset-matrix array since that
	// is the array the bone indices of the vertices are relative to.

	for(UINT i = 0; i < _numBones; ++i)
	{
		// Find the frame that corresponds with the ith bone offset matrix.
		const char* boneName = _skinInfo->GetBoneName(i);
		D3DXFRAME* frame = D3DXFrameFind(_root, boneName);
		if( frame )
		{
			FrameEx* frameEx = static_cast<FrameEx*>( frame );
			_combinedTransforms[i] = &frameEx->combinedTransform;
		}
	}
}

void SkinnedMesh::combineTransforms(FrameEx* frame, 
									D3DXMATRIX& P) // parent's combined transform
{
	// Recurse down the tree, combining transforms as we go along.  
	// Any node N's combined transform C is determined by its local 
	// transform L, and the combined transform P of its parent.
	// Thus C = L * P.

	// Save some references to economize line space.
    D3DXMATRIX& L = frame->TransformationMatrix;
    D3DXMATRIX& C = frame->combinedTransform;

    C = L * P;

    FrameEx* sibling    = (FrameEx*)frame->pFrameSibling;
    FrameEx* firstChild = (FrameEx*)frame->pFrameFirstChild;

	// Recurse down siblings.
	if( sibling )
		combineTransforms(sibling, P);

	// Recurse to first child.
	if( firstChild )
		combineTransforms(firstChild , C);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -