使用3Dmax导出插件导出模型信息解析
关关 2018-07-05 来源 : 阅读 621 评论 0

摘要:本篇3Dmax教程探讨了使用3Dmax导出插件导出模型信息,希望阅读本篇文章以后大家有所收获,帮助大家对3Dmax的掌握更加熟练。

    首先定义骨骼的结构:

 

view plaincopy to clipboardprint?

struct Bone   

{   

    INode* pNode;//该骨骼的节点   

    int parent;//父节点序号   

    typedef std::vector<int> Child_Vec;   

    Child_Vec childs;//子节点序号   

    Matrix3 matrix;//基本变换矩阵   

};   

typedef std::vector<Bone> Bone_Vec;   

Bone_Vec m_bones;  

struct Bone

{

    INode* pNode;//该骨骼的节点

    int parent;//父节点序号

    typedef std::vector<int> Child_Vec;

    Child_Vec childs;//子节点序号

    Matrix3 matrix;//基本变换矩阵

};

typedef std::vector<Bone> Bone_Vec;

Bone_Vec m_bones;

 

        我将骨骼结构放入一个顺序表中,Bone::parent和Bone::childs中存放的都是这个顺序表中的索引号.

    然后是权重信息.精粹2上是将权重信息放到骨骼的结构中去,我认为这样不太好.因为如果要使用硬件shader实现骨骼动画的话,是需要把权重信息放到顶点缓冲中去传送给显卡的,因此应该放到每个顶点的信息中去.

    我是这样定义:

  typedef std::map<int, float> Weight_Vertx;//权重顶点

    其中键是骨骼的索引号,值是权重.

    typedef std::vector<Weight_Vertx> Weight_Vertx_List;//权重顶点列表

    Weight_Vertx_List m_weight_vertexs;//权重顶点

    最终希望的是读取骨架结构,放入m_bones中,然后读取每点的权重,放入m_weight_vertexs

中.

=============================传说中的分割线======================================

    下面先给出整个导出类的定义:

 

view plaincopy to clipboardprint?

class Export_Mesh   

{   

public:   

    Export_Mesh(INode* pRoot);   

    ~Export_Mesh();   

    bool export_file(const TCHAR* name);   

private:   

    void export_mesh(INode* pNode);   

    int load_bone_struct(INode* pNode, int parentIdx);//读取骨架结构   

    bool load_bone_weights(INode* pNode);   

    bool is_mesh(INode* pNode);//判断一个节点是否是模型   

    bool is_bone(INode* pNode);//判断一个节点是否是骨骼   

    int get_bone_index(INode* pNode);//取得一个骨骼节点的序号   

    Modifier* get_mod(INode* pNode, Class_ID id);//取得指定变形器   

    void get_skin_weights(INode* pNode, Modifier* pMod);//取得皮肤权重   

    void get_physique_weights(INode* pNode, Modifier* pMod);//取得体形权重   

private:   

    INode* m_root;   

    typedef std::map<int, float> Weight_Vertx;//权重顶点   

    typedef std::vector<Weight_Vertx> Weight_Vertx_List;//权重顶点列表   

    Weight_Vertx_List m_weight_vertexs;//权重顶点   

    //一块骨骼   

    struct Bone   

    {   

        INode* pNode;//该骨骼的节点   

        int parent;//父节点序号   

        typedef std::vector<int> Child_Vec;   

        Child_Vec childs;//子节点序号   

        Matrix3 matrix;//基本变换矩阵   

    };   

    typedef std::vector<Bone> Bone_Vec;   

    Bone_Vec m_bones;   

};  

class Export_Mesh

{

public:

    Export_Mesh(INode* pRoot);

    ~Export_Mesh();

    bool export_file(const TCHAR* name);

private:

    void export_mesh(INode* pNode);

    int load_bone_struct(INode* pNode, int parentIdx);//读取骨架结构

    bool load_bone_weights(INode* pNode);

    bool is_mesh(INode* pNode);//判断一个节点是否是模型

    bool is_bone(INode* pNode);//判断一个节点是否是骨骼

    int get_bone_index(INode* pNode);//取得一个骨骼节点的序号

    Modifier* get_mod(INode* pNode, Class_ID id);//取得指定变形器

    void get_skin_weights(INode* pNode, Modifier* pMod);//取得皮肤权重

    void get_physique_weights(INode* pNode, Modifier* pMod);//取得体形权重

private:

    INode* m_root;

    typedef std::map<int, float> Weight_Vertx;//权重顶点

    typedef std::vector<Weight_Vertx> Weight_Vertx_List;//权重顶点列表

    Weight_Vertx_List m_weight_vertexs;//权重顶点

    //一块骨骼

    struct Bone

    {

        INode* pNode;//该骨骼的节点

        int parent;//父节点序号

        typedef std::vector<int> Child_Vec;

        Child_Vec childs;//子节点序号

        Matrix3 matrix;//基本变换矩阵

    };

    typedef std::vector<Bone> Bone_Vec;

    Bone_Vec m_bones;

};

 

先给出几个基本的函数的实现,在精粹2上都有的:

 

view plaincopy to clipboardprint?

bool Export_Mesh::is_mesh(INode* pNode)   

{   

    if(NULL == pNode) return false;   

    ObjectState os = pNode->EvalWorldState(0);   

    if(!os.obj) return false;   

    return os.obj->SuperClassID() == GEOMOBJECT_CLASS_ID;   

}   

//-----------------------------------------------------------------------------   

bool Export_Mesh::is_bone(INode* pNode)   

{   

    if(NULL == pNode) return false;   

    ObjectState os = pNode->EvalWorldState(0);   

    if(!os.obj) return false;   

    if( os.obj->ClassID() == Class_ID(BONE_CLASS_ID, 0) ) return true;   

    if( os.obj->ClassID() == Class_ID(DUMMY_CLASS_ID, 0) ) return false;   

    Control* cont = pNode->GetTMController();   

    //Biped部分   

    return cont->ClassID() == BIPSLAVE_CONTROL_CLASS_ID || //Biped root "Bip01"   

           cont->ClassID() == BIPBODY_CONTROL_CLASS_ID;   

}  

bool Export_Mesh::is_mesh(INode* pNode)

{

    if(NULL == pNode) return false;

    ObjectState os = pNode->EvalWorldState(0);

    if(!os.obj) return false;

    return os.obj->SuperClassID() == GEOMOBJECT_CLASS_ID;

}

//-----------------------------------------------------------------------------

bool Export_Mesh::is_bone(INode* pNode)

{

    if(NULL == pNode) return false;

    ObjectState os = pNode->EvalWorldState(0);

    if(!os.obj) return false;

    if( os.obj->ClassID() == Class_ID(BONE_CLASS_ID, 0) ) return true;

    if( os.obj->ClassID() == Class_ID(DUMMY_CLASS_ID, 0) ) return false;

    Control* cont = pNode->GetTMController();

    //Biped部分

    return cont->ClassID() == BIPSLAVE_CONTROL_CLASS_ID || //Biped root "Bip01"

           cont->ClassID() == BIPBODY_CONTROL_CLASS_ID;

}

 

    我改动的一点是取得骨骼的索引值(get_bone_index函数).按照精粹2的写法,取得的索引值不是从0开始连续的,因此不容易按照他给的索引值放到一个顺序表中.因此我换了一种方法.

    还记得在struct Bone结构中的INode* pNode;指针么,我是先读取整个骨架结构,然后将每个读取到的骨骼放入顺序表中,并记录下每个骨骼的节点指针.这样需要取得指定骨骼节点的索引只需要去查骨骼列表就好了.废话不多说了,实现如下:

 

view plaincopy to clipboardprint?

int Export_Mesh::load_bone_struct(INode* pNode, int parentIdx)   

{   

    //如果该节点为骨骼节点   

    if(this->is_bone(pNode))   

    {   

        //向骨骼列表中添加该节点   

        Bone bone;   

        bone.pNode = pNode;//记录该节点指针   

        bone.parent = parentIdx;//记录父节点索引   

        bone.matrix = pNode->GetNodeTM(0.0f);//记录基本变换矩阵   

        bone.matrix.NoScale();   

        bone.matrix.Invert();   

        m_bones.push_back(bone);   

        const int currIdx = static_cast<int>(m_bones.size() - 1);   

        //递归遍历所有子节点   

        for(int i=0;i<pNode->NumberOfChildren();i++)   

        {   

            INode* cNode = pNode->GetChildNode(i);   

            int cIdx = this->load_bone_struct(pNode->GetChildNode(i), currIdx);   

            if(cIdx >= 0)   

            {   

                m_bones.at(currIdx).childs.push_back(cIdx);   

            }   

        }   

        return currIdx;   

    }   

    else//如果该节点不是骨骼节点,则递归遍历子节点   

    {   

        for(int i = 0; i < pNode->NumberOfChildren(); ++i)   

        {   

            this->load_bone_struct(pNode->GetChildNode(i), -1);   

        }   

        return -1;   

    }   

}  

int Export_Mesh::load_bone_struct(INode* pNode, int parentIdx)

{

    //如果该节点为骨骼节点

    if(this->is_bone(pNode))

    {

        //向骨骼列表中添加该节点

        Bone bone;

        bone.pNode = pNode;//记录该节点指针

        bone.parent = parentIdx;//记录父节点索引

        bone.matrix = pNode->GetNodeTM(0.0f);//记录基本变换矩阵

        bone.matrix.NoScale();

        bone.matrix.Invert();

        m_bones.push_back(bone);

        const int currIdx = static_cast<int>(m_bones.size() - 1);

        //递归遍历所有子节点

        for(int i=0;i<pNode->NumberOfChildren();i++)

        {

            INode* cNode = pNode->GetChildNode(i);

            int cIdx = this->load_bone_struct(pNode->GetChildNode(i), currIdx);

            if(cIdx >= 0)

            {

                m_bones.at(currIdx).childs.push_back(cIdx);

            }

        }

        return currIdx;

    }

    else//如果该节点不是骨骼节点,则递归遍历子节点

    {

        for(int i = 0; i < pNode->NumberOfChildren(); ++i)

        {

            this->load_bone_struct(pNode->GetChildNode(i), -1);

        }

        return -1;

    }

}

 

在这个函数完成工作后,就可以通过get_bone_index函数查找骨骼的索引了.

 

view plaincopy to clipboardprint?

int Export_Mesh::get_bone_index(INode* pNode)   

{   

    //测试该节点是否为骨骼节点   

    if(!this->is_bone(pNode))   

    {   

        return -1;   

    }   

    //遍历骨骼数组查找该节点是否存在其中   

    for(int i=0; i < m_bones.size(); ++i)   

    {   

        if(m_bones.at(i).pNode == pNode)   

        {   

            return i;   

        }   

    }   

    return -1;   

}  

int Export_Mesh::get_bone_index(INode* pNode)

{

    //测试该节点是否为骨骼节点

    if(!this->is_bone(pNode))

    {

        return -1;

    }

    //遍历骨骼数组查找该节点是否存在其中

    for(int i=0; i < m_bones.size(); ++i)

    {

        if(m_bones.at(i).pNode == pNode)

        {

            return i;

        }

    }

    return -1;

    接下来是读取权重信息.先看看load_bone_weights函数的实现:

 

view plaincopy to clipboardprint?

bool Export_Mesh::load_bone_weights(INode* pNode)   

{   

    if((!pNode)||(!this->is_mesh(pNode))) return false;   

    //尝试取得体形变形器   

    Modifier* pmf = this->get_mod(pNode, Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B));   

    if(pmf)//如果取得成功   

    {   

        //设置权重顶点尺寸   

        this->get_physique_weights(pNode, pmf);   

    }   

    else//如果没有,尝试取得皮肤变形器   

    {   

        pmf = this->get_mod(pNode, SKIN_CLASSID);   

        if(pmf)   

        {   

            this->get_skin_weights(pNode, pmf);   

        }   

    }   

    //递归处理子节点   

    const int childCnt = pNode->NumberOfChildren();   

    for(int i = 0; i < childCnt; ++i)   

    {   

        this->load_bone_weights(pNode->GetChildNode(i));   

    }   

    return true;   

}  

bool Export_Mesh::load_bone_weights(INode* pNode)

{

    if((!pNode)||(!this->is_mesh(pNode))) return false;

    //尝试取得体形变形器

    Modifier* pmf = this->get_mod(pNode, Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B));

    if(pmf)//如果取得成功

    {

        //设置权重顶点尺寸

        this->get_physique_weights(pNode, pmf);

    }

    else//如果没有,尝试取得皮肤变形器

    {

        pmf = this->get_mod(pNode, SKIN_CLASSID);

        if(pmf)

        {

            this->get_skin_weights(pNode, pmf);

        }

    }

    //递归处理子节点

    const int childCnt = pNode->NumberOfChildren();

    for(int i = 0; i < childCnt; ++i)

    {

        this->load_bone_weights(pNode->GetChildNode(i));

    }

    return true;

}

 

在3dmax中,骨骼动画可能由常规的皮肤构造,也可以由character studio构造(好吧,我承认我是猜的.实际上我基本没用过3dmax).因此一个带有骨骼动画的模型节点可能存在两种变形器:体形变形器和皮肤变形器.要导出权重就需要变形器对象.下面看看取得变形器使用的函数:

view plaincopy to clipboardprint?

Modifier* Export_Mesh::get_mod(INode* pNode, Class_ID id)   

{   

    Object* pObj = pNode->GetObjectRef();   

    if(!pObj) return NULL;   

    //是否是个导出对象   

    while(pObj->SuperClassID() == GEN_DERIVOB_CLASS_ID)   

    {   

        //如果是导出对象   

        IDerivedObject* pDerivedObj = static_cast<IDerivedObject*>(pObj);   

        //循环变形器堆栈上的所有实体   

        for(int i=0; i<pDerivedObj->NumModifiers(); ++i)   

        {   

            //取得当前的变形器   

            Modifier* pMod = pDerivedObj->GetModifier(i);   

            //是否是体形?   

            if(pMod->ClassID() == id)   

            {   

                return pMod;   

            }   

        }   

        pObj = pDerivedObj->GetObjRef();   

    }   

    //没有找到   

    return NULL;   

}  

Modifier* Export_Mesh::get_mod(INode* pNode, Class_ID id)

{

    Object* pObj = pNode->GetObjectRef();

    if(!pObj) return NULL;

    //是否是个导出对象

    while(pObj->SuperClassID() == GEN_DERIVOB_CLASS_ID)

    {

        //如果是导出对象

        IDerivedObject* pDerivedObj = static_cast<IDerivedObject*>(pObj);

        //循环变形器堆栈上的所有实体

        for(int i=0; i<pDerivedObj->NumModifiers(); ++i)

        {

            //取得当前的变形器

            Modifier* pMod = pDerivedObj->GetModifier(i);

            //是否是体形?

            if(pMod->ClassID() == id)

            {

                return pMod;

            }

        }

        pObj = pDerivedObj->GetObjRef();

    }

    //没有找到

    return NULL;

    这个函数没有什么好解释的,就是检查下ClassID的工作.

    下面是重点,从变形器中取出顶点在各个骨骼上的权重,先看下取得形体变形器的get_physique_weights:

view plaincopy to clipboardprint?

void Export_Mesh::get_physique_weights(INode* pNode, Modifier* pMod)   

{   

    //为变形器创建一个体形导出接口   

    IPhysiqueExport* phyInterface = (IPhysiqueExport*)pMod->GetInterface(I_PHYINTERFACE);   

    if(!phyInterface) return;   

    //为指定节点创建一个ModContext导出接口   

    IPhyContextExport* modContextInt =    

        (IPhyContextExport*)phyInterface->GetContextInterface(pNode);   

    if(modContextInt)   

    {   

        //需要顶点接口(现在只支持刚体)   

        modContextInt->ConvertToRigid(TRUE);   

        //允许每个节点超过一个骨骼   

        modContextInt->AllowBlending(TRUE);   

        const int totalVtx = modContextInt->GetNumberVertices();//取得总顶点数   

        //调整权重顶点的尺寸   

        assert(m_weight_vertexs.size() == 0);   

        m_weight_vertexs.resize(totalVtx);   

        for(int i = 0; i < totalVtx; ++i)//遍历所有的顶点   

        {   

            //取得顶点导出器的接口   

            IPhyVertexExport* vtxInterface =    

                (IPhyVertexExport*)modContextInt->GetVertexInterface(i);   

            if(!vtxInterface) continue;   

            int vtxType = vtxInterface->GetVertexType();   

            if(RIGID_TYPE == vtxType)//只受一块骨骼影响,权重为1   

            {   

                //取得骨骼节点   

                INode* boneNode = ((IPhyRigidVertex*)vtxInterface)->GetNode();   

                int boneIdx = this->get_bone_index(boneNode);   

                //设置骨骼权重   

                m_weight_vertexs.at(i)[boneIdx] = 1.0f;   

            }   

            else if(RIGID_BLENDED_TYPE == vtxType)//受多块骨骼影响   

            {   

                IPhyBlendedRigidVertex* vtxBlendedInt =    

                            (IPhyBlendedRigidVertex*)vtxInterface;   

                assert(vtxBlendedInt);   

                for(int j = 0; j < vtxBlendedInt->GetNumberNodes(); ++j)   

                {   

                    INode* boneNode = vtxBlendedInt->GetNode(j);   

                    int boneIdx = this->get_bone_index(boneNode);   

                    //查找此权重顶点中是否存在此骨骼的权重   

                    Weight_Vertx::iterator fpos = m_weight_vertexs.at(i).find(boneIdx);   

                    if(fpos == m_weight_vertexs.at(i).end())//如果不存在   

                    {   

                        //则向当前骨骼的权重列表中添加新的一项   

                        m_weight_vertexs.at(i)[boneIdx] = vtxBlendedInt->GetWeight(j);   

                    }   

                    else//如果存在   

                    {   

                        //则累加上当前骨骼的权重   

                        fpos->second += vtxBlendedInt->GetWeight(j);   

                    }   

                }   

            }   

        }   

        phyInterface->ReleaseContextInterface(modContextInt);   

    }   

    pMod->ReleaseInterface(I_PHYINTERFACE, phyInterface);   

}  

void Export_Mesh::get_physique_weights(INode* pNode, Modifier* pMod)

{

    //为变形器创建一个体形导出接口

    IPhysiqueExport* phyInterface = (IPhysiqueExport*)pMod->GetInterface(I_PHYINTERFACE);

    if(!phyInterface) return;

    //为指定节点创建一个ModContext导出接口

    IPhyContextExport* modContextInt = 

        (IPhyContextExport*)phyInterface->GetContextInterface(pNode);

    if(modContextInt)

    {

        //需要顶点接口(现在只支持刚体)

        modContextInt->ConvertToRigid(TRUE);

        //允许每个节点超过一个骨骼

        modContextInt->AllowBlending(TRUE);

        const int totalVtx = modContextInt->GetNumberVertices();//取得总顶点数

        //调整权重顶点的尺寸

        assert(m_weight_vertexs.size() == 0);

        m_weight_vertexs.resize(totalVtx);

        for(int i = 0; i < totalVtx; ++i)//遍历所有的顶点

        {

            //取得顶点导出器的接口

            IPhyVertexExport* vtxInterface = 

                (IPhyVertexExport*)modContextInt->GetVertexInterface(i);

            if(!vtxInterface) continue;

            int vtxType = vtxInterface->GetVertexType();

            if(RIGID_TYPE == vtxType)//只受一块骨骼影响,权重为1

            {

                //取得骨骼节点

                INode* boneNode = ((IPhyRigidVertex*)vtxInterface)->GetNode();

                int boneIdx = this->get_bone_index(boneNode);

                //设置骨骼权重

                m_weight_vertexs.at(i)[boneIdx] = 1.0f;

            }

            else if(RIGID_BLENDED_TYPE == vtxType)//受多块骨骼影响

            {

                IPhyBlendedRigidVertex* vtxBlendedInt = 

                            (IPhyBlendedRigidVertex*)vtxInterface;

                assert(vtxBlendedInt);

                for(int j = 0; j < vtxBlendedInt->GetNumberNodes(); ++j)

                {

                    INode* boneNode = vtxBlendedInt->GetNode(j);

                    int boneIdx = this->get_bone_index(boneNode);

                    //查找此权重顶点中是否存在此骨骼的权重

                    Weight_Vertx::iterator fpos = m_weight_vertexs.at(i).find(boneIdx);

                    if(fpos == m_weight_vertexs.at(i).end())//如果不存在

                    {

                        //则向当前骨骼的权重列表中添加新的一项

                        m_weight_vertexs.at(i)[boneIdx] = vtxBlendedInt->GetWeight(j);

                    }

                    else//如果存在

                    {

                        //则累加上当前骨骼的权重

                        fpos->second += vtxBlendedInt->GetWeight(j);

                    }

                }

            }

        }

        phyInterface->ReleaseContextInterface(modContextInt);

    }

    pMod->ReleaseInterface(I_PHYINTERFACE, phyInterface);

    我想代码的注释已经很清楚了,没有必要解释了吧?get_skin_weights函数基本和上面那个是一样的:

 

view plaincopy to clipboardprint?

void Export_Mesh::get_skin_weights(INode* pNode, Modifier* pMod)   

{   

    //为变形器创建一个皮肤导出接口   

    ISkin* skin = (ISkin*)pMod->GetInterface(I_SKIN);   

    if(!skin) return;   

    //为指定节点创建一个皮肤上下文   

    ISkinContextData* skincontext = skin->GetContextInterface(pNode);   

    if(skincontext)   

    {   

        //遍历所有顶点,取得权重   

        const int numVert = skincontext->GetNumPoints();   

        //调整权重顶点的尺寸   

        assert(m_weight_vertexs.size() == 0);   

        m_weight_vertexs.resize(numVert);   

        for(int i = 0; i < numVert; ++i)   

        {   

            const int numBones = skincontext->GetNumAssignedBones(i);   

            for(int j = 0; j < numBones; ++j)   

            {   

                INode* bone = skin->GetBone(skincontext->GetAssignedBone(i,j));//do not use j,but use GetAssignedBone(i,j)   

                if(!bone) continue;   

                int boneIdx = this->get_bone_index(bone);   

                if(-1 == boneIdx) continue;   

 

                //查找此权重顶点中是否存在此骨骼的权重   

                Weight_Vertx::iterator fpos = m_weight_vertexs.at(i).find(boneIdx);   

                if(fpos == m_weight_vertexs.at(i).end())//如果不存在   

                {   

                    //则向当前骨骼的权重列表中添加新的一项   

                    m_weight_vertexs.at(i)[boneIdx] = skincontext->GetBoneWeight(i,j);   

                }   

                else//如果存在   

                {   

                    //则累加上当前骨骼的权重   

                    fpos->second += skincontext->GetBoneWeight(i,j);   

                }   

            }   

        }   

    }   

    pMod->ReleaseInterface(I_SKIN, skin);   

}  

void Export_Mesh::get_skin_weights(INode* pNode, Modifier* pMod)

{

    //为变形器创建一个皮肤导出接口

    ISkin* skin = (ISkin*)pMod->GetInterface(I_SKIN);

    if(!skin) return;

    //为指定节点创建一个皮肤上下文

    ISkinContextData* skincontext = skin->GetContextInterface(pNode);

    if(skincontext)

    {

        //遍历所有顶点,取得权重

        const int numVert = skincontext->GetNumPoints();

        //调整权重顶点的尺寸

        assert(m_weight_vertexs.size() == 0);

        m_weight_vertexs.resize(numVert);

        for(int i = 0; i < numVert; ++i)

        {

            const int numBones = skincontext->GetNumAssignedBones(i);

            for(int j = 0; j < numBones; ++j)

            {

                INode* bone = skin->GetBone(skincontext->GetAssignedBone(i,j));//do not use j,but use GetAssignedBone(i,j)

                if(!bone) continue;

                int boneIdx = this->get_bone_index(bone);

                if(-1 == boneIdx) continue;

 

                //查找此权重顶点中是否存在此骨骼的权重

                Weight_Vertx::iterator fpos = m_weight_vertexs.at(i).find(boneIdx);

                if(fpos == m_weight_vertexs.at(i).end())//如果不存在

                {

                    //则向当前骨骼的权重列表中添加新的一项

                    m_weight_vertexs.at(i)[boneIdx] = skincontext->GetBoneWeight(i,j);

                }

                else//如果存在

                {

                    //则累加上当前骨骼的权重

                    fpos->second += skincontext->GetBoneWeight(i,j);

                }

            }

        }

    }

    pMod->ReleaseInterface(I_SKIN, skin);

}

 

最后要导出整个模型的全部信息,就冲根节点开始递归遍历所有节点进行导出工作:

view plaincopy to clipboardprint?

void Export_Mesh::export_mesh(INode* pNode)   

{   

    if(this->is_mesh(pNode))   

    {   

        this->load_bone_weights(pNode);   

    }   

    //递归遍历所有的模型子节点   

    for(int i = 0; i < pNode->NumberOfChildren(); ++i)   

    {   

        this->export_mesh(pNode->GetChildNode(i));   

    }   

}  

void Export_Mesh::export_mesh(INode* pNode)

{

    if(this->is_mesh(pNode))

    {

        this->load_bone_weights(pNode);

    }

    //递归遍历所有的模型子节点

    for(int i = 0; i < pNode->NumberOfChildren(); ++i)

    {

        this->export_mesh(pNode->GetChildNode(i));

    }

    现在终于把骨骼动画的信息按照我需要的格式放进内存了.为了看下导出的效果,输出到文本文件:

 

view plaincopy to clipboardprint?

bool Export_Mesh::export_file(const TCHAR* name)   

{   

    std::ofstream outfile(name);   

    //先读取骨架信息   

    this->load_bone_struct(pRoot, -1);   

    //遍历所有的模型节点,读出权重信息   

    this->export_mesh(m_root);   

    //输出骨架信息   

    outfile << "Bone Information: " << m_bones.size() << "/n";   

    for(int i = 0; i < m_bones.size(); ++i)   

    {   

        outfile << "Bone Index: " << i << "/n"  

                << "Bone id: " << (void*)(m_bones.at(i).pNode) << "/n"  

                << "Parent Index: " << m_bones.at(i).parent << "/n"  

                << "Childs Index: ";   

        for( Bone::Child_Vec::iterator j = m_bones.at(i).childs.begin();   

             j != m_bones.at(i).childs.end(); ++j )   

        {   

            outfile << *j << " ";   

        }   

        outfile << "/n=======================================================/n";   

    }   

    outfile << "Bone Weights: " << m_weight_vertexs.size() << "/n";   

    for(int i = 0; i < m_weight_vertexs.size(); ++i)   

    {   

        outfile << "Vertex Index:" << i << "/n";   

        for(Weight_Vertx::iterator j = m_weight_vertexs.at(i).begin();   

            j != m_weight_vertexs.at(i).end(); ++j)   

        {   

            outfile << "/tBone Index:" << j->first << "; Weight: " << j->second << "/n";   

        }   

        outfile << "/n=======================================================/n";   

    }   

    outfile.flush();   

    outfile.close();   

    return true;   

}  

bool Export_Mesh::export_file(const TCHAR* name)

{

    std::ofstream outfile(name);

    //先读取骨架信息

    this->load_bone_struct(pRoot, -1);

    //遍历所有的模型节点,读出权重信息

    this->export_mesh(m_root);

    //输出骨架信息

    outfile << "Bone Information: " << m_bones.size() << "/n";

    for(int i = 0; i < m_bones.size(); ++i)

    {

        outfile << "Bone Index: " << i << "/n"

                << "Bone id: " << (void*)(m_bones.at(i).pNode) << "/n"

                << "Parent Index: " << m_bones.at(i).parent << "/n"

                << "Childs Index: ";

        for( Bone::Child_Vec::iterator j = m_bones.at(i).childs.begin();

             j != m_bones.at(i).childs.end(); ++j )

        {

            outfile << *j << " ";

        }

        outfile << "/n=======================================================/n";

    }

    outfile << "Bone Weights: " << m_weight_vertexs.size() << "/n";

    for(int i = 0; i < m_weight_vertexs.size(); ++i)

    {

        outfile << "Vertex Index:" << i << "/n";

        for(Weight_Vertx::iterator j = m_weight_vertexs.at(i).begin();

            j != m_weight_vertexs.at(i).end(); ++j)

        {

            outfile << "/tBone Index:" << j->first << "; Weight: " << j->second << "/n";

        }

        outfile << "/n=======================================================/n";

    }

    outfile.flush();

    outfile.close();

    return true;

}

 

    最后一步,在3dmax导出插件中让它起作用:

 

view plaincopy to clipboardprint?

int pge_3dmax_exporter::DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts, DWORD options)   

{   

    Export_Mesh export_mesh(i->GetRootNode());   

    export_mesh.export_file(name);   

 

    return TRUE;   

}  

int pge_3dmax_exporter::DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts, DWORD options)

{

    Export_Mesh export_mesh(i->GetRootNode());

    export_mesh.export_file(name);

 

    return TRUE;

}

 

 最终输出的文本文件如下:

Bone Information: 32

Bone Index: 0

Bone id: 08CC6CB0

Parent Index: -1

Childs Index: 1 

=======================================================

Bone Index: 1

Bone id: 08CC33A0

Parent Index: 0

Childs Index: 2 

=======================================================

......

 

Bone Weights: 462

Vertex Index:0

Bone Index:26; Weight: 1

=======================================================

Vertex Index:1

Bone Index:7; Weight: 0.999999

Bone Index:18; Weight: 1.01289e-006

=======================================================

Vertex Index:2

Bone Index:5; Weight: 9.13872e-006

Bone Index:7; Weight: 0.999991

 

本文由职坐标整理发布,欢迎关注职坐标3Dmax频道,学习更多相关知识!

本文由 @关关 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程