directx加载ms3d动画模型

最近刚完成了ms3d模型的加载及动画显示,为了让更多的人容易学会和使用该模型,本人就自己所掌握的内容稍微谈谈。

说起骨骼动画,大家一定不会陌生,这里本人假定大家都了解骨骼动画的基本原理。如果不熟悉的话可参考《Advanced Animation with DirectX》和《Focus.On.3D.Models》。其中《Advanced Animation with DirectX》讲了基本的骨骼原理和.x文件动画的显示,《Focus.On.3D.Models》讲了骨骼原理、ms3d格式(还有几种)及动画的显示。

在DirectX下实现ms3d模型与在opengl下有着微妙的不同。本人就是搜索了很多英文网站也只找到了两份有用的源代码,一份是nehe的opengl代码,一份是milkshape写的directx代码。前一份代码阅读性很强,很容易看懂,本人的代码也是参考自它。后一份代码功能强大,但就我来说它不适于开始学习,太复杂了点,而且尽管是用direcxt,里面的坐标也全是基于右手的。

下面开始实现:由于模型空间为右手系,dx为左手系,因此代码中还得对坐标进行转换
#pragma pack(push) //保存对齐状态

#pragma pack(1)//设定为4字节对齐

//-----------------------ms3d数据-------------------------------
typedef struct MS3DHeader_TYP
{
        char m_ID[10];                                // Must be 'MS3D000000'
        int  m_version;                                // File format version (3 or 4)
} MS3DHeader;

// Vertex information
typedef struct MS3DVertex_TYP
{
        unsigned char m_flags;                        // Editor flags
        float m_vertex[3];                                // World coordinates                
        char m_boneID;                                // -1 = no bone
        unsigned char m_refCount;                // Reference count
} MS3DVertex;

// Triangle information
typedef struct MS3DTriangle_TYP
{
        unsigned short m_flags;                                // Editor flags
        unsigned short m_vertexIndices[3];        // Vertex indices
        float m_vertexNormals[3][3];                        // Normals (each vertex, x/y/z)
        float m_u[3];                                                // Texture u coordinate
        float m_v[3];                                                // Texture v coordinate
        unsigned char m_smoothingGroup;        // Smoothing group
        unsigned char m_groupIndex;                // Material group
} MS3DTriangle;

///Mesh information
typedef struct MS3DMesh_TYP
{
        unsigned char m_flags;                                // Editor flags
        char m_name[32];                                        // Name of group
        unsigned short  m_numTriangles;                // # faces in group
        unsigned short *m_TriangleIndices;        // Face indices
        char m_MaterialIndex;                                // -1 = no material
} MS3DMesh;

// Material information
typedef struct MS3DMaterial_TYP
{
            char m_name[32];                                        // Material name
            float m_ambient[4];                                        // Ambient colors
            float m_diffuse[4];                                        // Diffuse colors
            float m_specular[4];                                        // Specular colors
            float m_emissive[4];                                        // Emmisive colors
            float m_shininess;                                        // Shininess strength
            float m_transparency;                                // Transparency amount
            char m_mode;                                                // Mode 0-3 0, 1, 2 is unused now
            char m_texture[128];                                        // Texture map .bmp filename
            char m_alphamap[128];                                // Alpha map .bmp filename
} MS3DMaterial;

//-------------------------骨骼部分----------------------------
//        Joint information
struct MS3DJoint
{
        char m_flags;
        char m_name[32];
        char m_parentName[32];
        float m_rotation[3];
        float m_translation[3];
        unsigned short m_numRotationKeyframes;
        unsigned short m_numTranslationKeyframes;
};

// Keyframe data
struct MS3DKeyframe
{
        float m_time;
        float m_parameter[3];
};

#pragma pack(pop)

以上是对整个ms3d文件内部组成的说明,我们使用c++的文件输入来读取其中内容,当然也可以使用其它io方法,只要效果一样即可。
bool CMs3dMesh:oad(IDirect3DDevice9 *pDevice, const char *filename, float scale, char *TexturePath)
{
        if ((m_pDevice = pDevice) == NULL)
                return false;
        
        std::ifstream file(filename, std::ios::in | std::ios::binary);
        //Open the .ms3d model file
        if (file == NULL)
                return false;

        file.seekg(0, std::ios::end);
        long fileSize = file.tellg();
        file.seekg(0, std::ios::beg);

        char *pBuffer = new char[fileSize];
        file.read(pBuffer, fileSize);
        file.close();

        const unsigned char *pPtr = (const unsigned char *)pBuffer;
                
        MS3DHeader *pHeader = (MS3DHeader *)pPtr;
        pPtr += sizeof(MS3DHeader);
        if (::strncmp(pHeader->m_ID, "MS3D000000", 10) != 0)
        { 
                MessageBox(NULL,"id error","ERROR",MB_OK|MB_ICONEXCLAMATION);
                return false;
        }
        if (pHeader->m_version < 3)// ||Header.m_version > 4)//支持1.5
        {
                MessageBox(NULL,"version error","ERROR",MB_OK|MB_ICONEXCLAMATION);
                return false; // "Unhandled file version. Only Milkshape3D Version 1.3 and 1.4 or above is supported." );
        }

        m_numVertices = *(unsigned short *)pPtr;
        pPtr += sizeof(unsigned short);

        m_pVertices = new Vertex[m_numVertices];
        for (unsigned short i = 0; i < m_numVertices; i++)
        {
                MS3DVertex *pVertex = (MS3DVertex *)pPtr;

                /////////////data copy
                m_pVertices.m_location[0] = pVertex->m_vertex[0];
                m_pVertices.m_location[1] = pVertex->m_vertex[1];
                //右手到左手
                m_pVertices.m_location[2] = -pVertex->m_vertex[2];
                ///////////////zoom
                m_pVertices.m_location[0] *= scale;
                m_pVertices.m_location[1] *= scale;
                m_pVertices.m_location[2] *= scale;

                //骨骼
                m_pVertices.m_boneID = pVertex->m_boneID;
                pPtr += sizeof(MS3DVertex);
        }
        
            ///////////read Triangles///////////////////////////
        m_numTriangles = *(unsigned short *)pPtr;
        pPtr += sizeof(unsigned short);
        m_pTriangles = new Triangle[m_numTriangles];

        for (i = 0; i < m_numTriangles; i++)
        {
                MS3DTriangle *pTriangle = (MS3DTriangle *)pPtr;

                //////////////////////////////////////////////////////////////////////
                ::memcpy(m_pTriangles.m_normal, pTriangle->m_vertexNormals, sizeof(float)*9);
                //右手到左手
                m_pTriangles.m_normal[0][2] = -m_pTriangles.m_normal[0][2];
                m_pTriangles.m_normal[1][2] = -m_pTriangles.m_normal[1][2];
                m_pTriangles.m_normal[2][2] = -m_pTriangles.m_normal[2][2];

                ::memcpy(m_pTriangles.m_u, pTriangle->m_u, sizeof( float )*3);
                ::memcpy(m_pTriangles.m_v, pTriangle->m_v, sizeof( float )*3);
                ::memcpy(m_pTriangles.m_vertexIndices, pTriangle->m_vertexIndices, sizeof(unsigned short )*3);

                m_pTriangles.m_groupID = pTriangle->m_groupIndex;
                pPtr += sizeof(MS3DTriangle);
        }

        //////////////read Meshes/////////////
           m_numMeshes = *(unsigned short *)pPtr;
        pPtr += sizeof(unsigned short);
        m_pMeshes = new Mesh[m_numMeshes];

        for (i = 0; i < m_numMeshes; i++)
        {
                pPtr += sizeof(unsigned char);        // flags
                pPtr += 32;                                // name

                unsigned short nTriangles = *(unsigned short *)pPtr;
                pPtr += sizeof(unsigned short);
                unsigned short *pTriangleIndices = new unsigned short[nTriangles];
                for (int j = 0; j < nTriangles; j++)
                {
                        pTriangleIndices[j] = *(unsigned short *)pPtr;
                        pPtr += sizeof(unsigned short);
                }

                char materialIndex = *(char *)pPtr;
                pPtr += sizeof(char);
        
                m_pMeshes.m_textureIndex = materialIndex;
                m_pMeshes.m_numTriangles = nTriangles;
                m_pMeshes.m_pTriangleIndices = pTriangleIndices;
        }

            ////////////////read texture/////////////
            // Read materials, creating a default one if none in file
        m_numMaterials = *(unsigned short *)pPtr;
        pPtr += sizeof(short);
        if (!m_numMaterials)
        {
                // Create a single material and color it white
                m_numMaterials = 1;
                m_pMaterial = new MATERIAL[1];
                ZeroMemory(&m_pMaterial[0], sizeof(MATERIAL));
                m_pMaterial[0].MatD3D.Diffuse.a = 
                m_pMaterial[0].MatD3D.Diffuse.r = 
                m_pMaterial[0].MatD3D.Diffuse.g = 
                m_pMaterial[0].MatD3D.Diffuse.b = 1.0f;

                // Set all groups to use material #0
                // If there are no materials, set all groups to 
                // use material #0
                if (m_numMeshes) 
                {
                        for (i=0; i<m_numMeshes; i++)
                                m_pMeshes.m_textureIndex = 0;
                }
        }
        else
        {
                m_pMaterial = new MATERIAL[m_numMaterials];
                ZeroMemory(m_pMaterial, sizeof(MATERIAL)*m_numMaterials);
                
                // Read in all materials from file
                for (i=0; i<m_numMaterials; i++)
                {
                        MS3DMaterial *pMaterial = (MS3DMaterial *)pPtr;
                        
                        /////////////////拷贝
                        m_pMaterial.MatD3D.Diffuse.a = pMaterial->m_diffuse[3];
                        m_pMaterial.MatD3D.Diffuse.r = pMaterial->m_diffuse[2];
                        m_pMaterial.MatD3D.Diffuse.g = pMaterial->m_diffuse[1];
                        m_pMaterial.MatD3D.Diffuse.b = pMaterial->m_diffuse[0];
                        m_pMaterial.MatD3D.Ambient.a = pMaterial->m_ambient[3];
                        m_pMaterial.MatD3D.Ambient.r = pMaterial->m_ambient[2];
                        m_pMaterial.MatD3D.Ambient.g = pMaterial->m_ambient[1];
                        m_pMaterial.MatD3D.Ambient.b = pMaterial->m_ambient[0];
                        m_pMaterial.MatD3D.Specular.a = pMaterial->m_specular[3];
                        m_pMaterial.MatD3D.Specular.r = pMaterial->m_specular[2];
                        m_pMaterial.MatD3D.Specular.g = pMaterial->m_specular[1];
                        m_pMaterial.MatD3D.Specular.b = pMaterial->m_specular[0];
                        m_pMaterial.MatD3D.Emissive.a = pMaterial->m_emissive[3];
                        m_pMaterial.MatD3D.Emissive.r = pMaterial->m_emissive[2];
                        m_pMaterial.MatD3D.Emissive.g = pMaterial->m_emissive[1];
                        m_pMaterial.MatD3D.Emissive.b = pMaterial->m_emissive[0];
                        m_pMaterial.MatD3D.Power = pMaterial->m_shininess;

                        if (pMaterial->m_texture)
                        {
                                char TextureFile[250] = {0};
                                // MS3D 1.5.x 相对路径
                                if (::strncmp(pMaterial->m_texture, ".\", 2 ) == 0 ) 
                                        ParseTextureFileName(pMaterial->m_texture);
                                
                                sprintf(TextureFile, "%s%s", TexturePath, pMaterial->m_texture);
                                
                                if (FAILED(D3DXCreateTextureFromFile(m_pDevice, TextureFile, &m_pMaterial.pTexture)))
                                {
                                        D3DXCreateTextureFromFile(m_pDevice, pMaterial->m_texture, &m_pMaterial.pTexture);
                                }
                        }

                        pPtr += sizeof(MS3DMaterial);
                }
        }

        //骨骼动画部分
        m_fFps = *(float *)pPtr;
        pPtr += sizeof(float);

        // skip currentTime
        pPtr += sizeof(float);

        int totalFrames = *(int *)pPtr;
        pPtr += sizeof(int);

        m_totalTime = totalFrames*1000.0/m_fFps;

        m_numJoints = *(unsigned short *)pPtr;
        pPtr += sizeof(unsigned short);
        //有骨骼信息
        if (m_numJoints > 0)
        {
                m_pJoints = new Joint[m_numJoints];
                
                const unsigned char *pTempPtr = pPtr;

                JointNameListRec *pNameList = new JointNameListRec[m_numJoints];
                unsigned short i = 0;
                for (i = 0; i < m_numJoints; i++)
                {
                        MS3DJoint *pJoint = (MS3DJoint *)pTempPtr;
                        pTempPtr += sizeof(MS3DJoint);
                        pTempPtr += sizeof(MS3DKeyframe)*(pJoint->m_numRotationKeyframes+pJoint->m_numTranslationKeyframes);

                        pNameList.m_jointIndex = i;
                        pNameList.m_pName = pJoint->m_name;
                }

                for (i = 0; i < m_numJoints; i++)
                {
                        MS3DJoint *pJoint = (MS3DJoint *)pPtr;
                        pPtr += sizeof(MS3DJoint);

                        int j, parentIndex = -1;
                        if (::strlen(pJoint->m_parentName) > 0)
                        {
                                for (j = 0; j < m_numJoints; j++)
                                {
                                        if (::stricmp(pNameList[j].m_pName, pJoint->m_parentName) == 0)
                                        {
                                                parentIndex = pNameList[j].m_jointIndex;
                                                break;
                                        }
                                }
                                if (parentIndex == -1) 
                                {
                                        MessageBox(NULL, "55", 0, 0);
                                        return false;
                                }
                        }

                        ::memcpy(m_pJoints.m_localRotation, pJoint->m_rotation, sizeof(float)*3);
                        ::memcpy(m_pJoints.m_localTranslation, pJoint->m_translation, sizeof(float)*3);

                        //右手到左手
                        m_pJoints.m_localRotation[0] = -m_pJoints.m_localRotation[0];
                        m_pJoints.m_localRotation[1] = -m_pJoints.m_localRotation[1];
                        m_pJoints.m_localTranslation[2] = -m_pJoints.m_localTranslation[2];

                        m_pJoints.m_localTranslation[0] *= scale;
                        m_pJoints.m_localTranslation[1] *= scale;
                        m_pJoints.m_localTranslation[2] *= scale;
                        
                        m_pJoints.m_parent = parentIndex;
                        m_pJoints.m_numRotationKeyframes = pJoint->m_numRotationKeyframes;
                        m_pJoints.m_pRotationKeyframes = new Keyframe[pJoint->m_numRotationKeyframes];
                        m_pJoints.m_numTranslationKeyframes = pJoint->m_numTranslationKeyframes;
                        m_pJoints.m_pTranslationKeyframes = new Keyframe[pJoint->m_numTranslationKeyframes];

                        for (j = 0; j < pJoint->m_numRotationKeyframes; j++)
                        {
                                MS3DKeyframe *pKeyframe = (MS3DKeyframe *)pPtr;
                                pPtr += sizeof(MS3DKeyframe);

                                SetJointKeyframe(i, j, pKeyframe->m_time*1000.0f, pKeyframe->m_parameter, true);
                        }

                        for (j = 0; j < pJoint->m_numTranslationKeyframes; j++)
                        {
                                MS3DKeyframe *pKeyframe = (MS3DKeyframe *)pPtr;
                                pPtr += sizeof(MS3DKeyframe);

                                SetJointKeyframe(i, j, pKeyframe->m_time*1000.0f, pKeyframe->m_parameter, false, scale);
                        }
                }
                delete[] pNameList;
        }

        delete []pBuffer;

        GenerateVB();

        ComputBoxAndSphere();

        if (m_numJoints > 0)
        {
                SetupJoints();
                Restart();
        }
    
        return true;
}

大家主意到上面代码里本人使用反转z坐标来实现右手到左手的转换,同时由于右手空间中旋转方向为逆时针方向,而dx空间为顺时针方向,旋转时也得反转。读者可以自己在草稿上笔画,一边是左手坐标变换,一边是右手坐标变换,左手中该怎么变换才能同右手效果一样。我讲的方法只是其中一种,只要是最终显示效果跟右手空间中显示效果一样,此方法即可。

void CMs3dMesh::SetJointKeyframe(int jointIndex, int keyframeIndex, float time, float *parameter, bool isRotation, float scale)
{
        Keyframe& keyframe = isRotation ? m_pJoints[jointIndex].m_pRotationKeyframes[keyframeIndex] :
                m_pJoints[jointIndex].m_pTranslationKeyframes[keyframeIndex];

        keyframe.m_jointIndex = jointIndex;
        keyframe.m_time = time;
        ::memcpy(keyframe.m_parameter, parameter, sizeof(float)*3);

        //右手到左手
        if (isRotation)
        {
                keyframe.m_parameter[0] = -keyframe.m_parameter[0];
                keyframe.m_parameter[1] = -keyframe.m_parameter[1];
//
        }
        else
        {
                keyframe.m_parameter[2] = -keyframe.m_parameter[2];
                keyframe.m_parameter[0] *= scale;
                keyframe.m_parameter[1] *= scale;
                keyframe.m_parameter[2] *= scale;
        }
}
这里旋转的z值不要反转了,大家画图就可知道。^_^
缩放系数是我代码里的功能,读者都把其看作1即可。

void CMs3dMesh::SetupJoints()
{
        unsigned short i;
        for (i = 0; i < m_numJoints; i++)
        {
                Joint &joint = m_pJoints;

                D3DXVECTOR3 vecRol(joint.m_localRotation[0], joint.m_localRotation[1], joint.m_localRotation[2]);
                D3DXVECTOR3 vecPos(joint.m_localTranslation[0], joint.m_localTranslation[1], joint.m_localTranslation[2]);

                D3DXMatrixFromRotXYZPos(&joint.m_relative, vecRol, vecPos);
                
                if (joint.m_parent != -1)
                {
                        joint.m_absolute = joint.m_relative*m_pJoints[joint.m_parent].m_absolute;
                }
                else
                        joint.m_absolute = joint.m_relative;

                D3DXMatrixInverse(&m_pJoints.m_offset, NULL, &m_pJoints.m_absolute);
        }

        for (i = 0; i < m_numVertices; i++)
        {
                Vertex &vertex = m_pVertices;

                if (vertex.m_boneID != -1)
                {
                        const D3DXMATRIX &matrix = m_pJoints[vertex.m_boneID].m_offset;

                        D3DXVECTOR3 vec(m_pVertices.m_location[0], m_pVertices.m_location[1], m_pVertices.m_location[2]);
                        D3DXVec3TransformCoord(&vec, &vec, &matrix);
                        m_pVertices.m_location[0] = vec.x;
                        m_pVertices.m_location[1] = vec.y;
                        m_pVertices.m_location[2] = vec.z;
                }
        }

        for (i = 0; i < m_numTriangles; i++) 
        {
                Triangle &triangle = m_pTriangles;
                for (int j = 0; j < 3; j++)
                {
                        const Vertex &vertex = m_pVertices[triangle.m_vertexIndices[j]];
                        if (vertex.m_boneID != -1) 
                        {
                                const D3DXMATRIX &matrix = m_pJoints[vertex.m_boneID].m_offset;

                                D3DXVECTOR3 vec(triangle.m_normal[j][0], triangle.m_normal[j][1], triangle.m_normal[j][2]);
                                D3DXVec3TransformNormal(&vec, &vec, &matrix);
                                D3DXVec3Normalize(&vec, &vec);
                                triangle.m_normal[j][0] = vec.x;
                                triangle.m_normal[j][1] = vec.y;
                                triangle.m_normal[j][2] = vec.z;
                        }
                }
        }
}

看到没,所有代码基本上都是参考自nehe的代码。^_^,感谢网络!
以下得坐标原点为整个模型得坐标原点。
这里右手坐标为数学坐标,dx与其相反。在数学坐标下矩阵相乘由右到左,dx下由左到右。
代码中的relative(相对)矩阵是每个joint自己的空间矩阵,你把每个joint看成是个模型。而absolute(绝对)矩阵则是每个joint到坐标原点的变换矩阵。对此矩阵进行求逆,得offset矩阵,对每个joint实行offset矩阵变换,每个节点就会回到坐标原点。这里上面方法调用完每个顶点都可以进行动画矩阵变换了。

void CMs3dMesh::UpdateAnimation(DWORD time, bool bLoop)
{
        if (time > m_totalTime)
        {
                if (bLoop)
                {
                        time %= m_totalTime;

                        if (time <= m_dwSpeed)
                                Restart();
                }
                else
                        time = m_totalTime;
        } 

        for (int i = 0; i < m_numJoints; i++)
        {
                float transVec[3] = {0.0f, 0.0f, 0.0f};
                D3DXMATRIX transform;
                int frame;
                Joint *pJoint = &m_pJoints;

                if (pJoint->m_numRotationKeyframes == 0 && pJoint->m_numTranslationKeyframes == 0)
                {
                        pJoint->m_final = pJoint->m_absolute;
                        continue;
                }

                frame = pJoint->m_currentTranslationKeyframe;
                while (frame < pJoint->m_numTranslationKeyframes && pJoint->m_pTranslationKeyframes[frame].m_time < time)
                {
                        frame++;
                }
                pJoint->m_currentTranslationKeyframe = frame;

                if (frame == 0)
                        ::memcpy(transVec, pJoint->m_pTranslationKeyframes[0].m_parameter, sizeof(float)*3);
                else if (frame == pJoint->m_numTranslationKeyframes)
                        ::memcpy(transVec, pJoint->m_pTranslationKeyframes[frame-1].m_parameter, sizeof(float)*3);
                else
                {
                        const Keyframe &curFrame = pJoint->m_pTranslationKeyframes[frame];
                        const Keyframe &prevFrame = pJoint->m_pTranslationKeyframes[frame-1];

                        float timeDelta = curFrame.m_time-prevFrame.m_time;
                        float interpValue = (float)((time-prevFrame.m_time)/timeDelta);

                        transVec[0] = prevFrame.m_parameter[0]+(curFrame.m_parameter[0]-prevFrame.m_parameter[0])*interpValue;
                        transVec[1] = prevFrame.m_parameter[1]+(curFrame.m_parameter[1]-prevFrame.m_parameter[1])*interpValue;
                        transVec[2] = prevFrame.m_parameter[2]+(curFrame.m_parameter[2]-prevFrame.m_parameter[2])*interpValue; 
                }

                frame = pJoint->m_currentRotationKeyframe;
                while (frame < pJoint->m_numRotationKeyframes && pJoint->m_pRotationKeyframes[frame].m_time < time)
                {
                        frame++;
                }
                pJoint->m_currentRotationKeyframe = frame;

                float rotVec[3] = {0.0f, 0.0f, 0.0f};

                if (frame == 0)
                        ::memcpy(rotVec, pJoint->m_pRotationKeyframes[0].m_parameter, sizeof(float)*3);
                else if (frame == pJoint->m_numRotationKeyframes)
                        ::memcpy(rotVec, pJoint->m_pRotationKeyframes[frame-1].m_parameter, sizeof(float)*3);
                else
                {
                        const Keyframe& curFrame = pJoint->m_pRotationKeyframes[frame];
                        const Keyframe& prevFrame = pJoint->m_pRotationKeyframes[frame-1];
                        
                        float timeDelta = curFrame.m_time-prevFrame.m_time;
                        float interpValue = (float)((time-prevFrame.m_time)/timeDelta);

                        rotVec[0] = prevFrame.m_parameter[0]+(curFrame.m_parameter[0]-prevFrame.m_parameter[0])*interpValue;
                        rotVec[1] = prevFrame.m_parameter[1]+(curFrame.m_parameter[1]-prevFrame.m_parameter[1])*interpValue;
                        rotVec[2] = prevFrame.m_parameter[2]+(curFrame.m_parameter[2]-prevFrame.m_parameter[2])*interpValue;
                }

                D3DXVECTOR3 vecRol(rotVec[0], rotVec[1], rotVec[2]);
                D3DXVECTOR3 vecPos(transVec[0], transVec[1], transVec[2]);
                D3DXMatrixFromRotXYZPos(&transform, vecRol, vecPos);

                D3DXMATRIX relativeFinal = transform*pJoint->m_relative;

                if (pJoint->m_parent == -1)
                        pJoint->m_final = relativeFinal;
                else
                {
                        pJoint->m_final = relativeFinal*m_pJoints[pJoint->m_parent].m_final;
                }
        }
}

每个节点变换完自己得动画后才再实现父节点得变换,pJoint->m_final = relativeFinal*m_pJoints[pJoint->m_parent].m_final。而自己得动画变化是在自己节点得空间矩阵下进行的,所以:relativeFinal = transform*pJoint->m_relative;

VOID D3DXMatrixFromRotXYZPos(
                                                                        D3DXMATRIX *pOut,
                                                                        D3DXVECTOR3 rot,
                                                                        D3DXVECTOR3 pos)
{
        D3DXMATRIX matRotX, matRotY, matRotZ;

        D3DXMatrixRotationX(&matRotX, rot.x);
        D3DXMatrixRotationY(&matRotY, rot.y);
        D3DXMatrixRotationZ(&matRotZ, rot.z);

        *pOut = matRotX;
        *pOut *= matRotY;
        *pOut *= matRotZ;
        pOut->_41 = pos.x;
        pOut->_42 = pos.y;
        pOut->_43 = pos.z;
}

最后是更新:
void CMs3dMesh::Update(DWORD time, bool bLoop)
{
        if (m_numJoints == 0)
                return;
        
        UpdateAnimation(time, bLoop);
        UpdateVB();//更新vertex buffer
}

代码还存在许多可以优化得地方,如可用shader等,这方面网上有相关资料。矩阵旋转我也没用四元数,这个我也不怎么熟也不想用的复杂,简单得东西就行!

所有得代码本人还没整理好,但已经能很好得显示ms3d动画了。这点请大家放心!
由于时间仓促,有说错或改进得地方请大家多多指教,再次声明:这只是本人兴致所致,随便谈谈,只要对大家有点帮助得话本人就足矣!

以下图片为显示ms3d模型动画得效果

原文地址:https://www.cnblogs.com/chunlinge/p/3783451.html