Unity运行时输出场景物体及角色为fbx文件

     在unity中导入fbx是个跟简单的事,只需要把fbx放到unity的项目文件夹下,它就能自动识别并读取了,但是在unity运行的过程中输出fbx却相当麻烦。因为工作项目的需求,需要把场景中的物体在运行时导出成fbx,所以对这个功能进行了研究,在unity商店也有一些导出的插件,但是基本都是只限于基本的几何体导出,要不就是不支持skinned mesh,要不就是不支持blendshape。因为这个项目的需求是需要把动作捕捉和面部捕捉的数据,写入到模型中并导出到fbx,所以也基本都不能满足需求,那就只能自己从头开始研究了。     

     要写fbx文件,就需要对fbx文件进行研究,简单来说fbx文件是类似于json结构的一种文件,首先是该fbx文件的基本信息,包括fbx版本,作者,标题、单位信息以及坐标系统信息。

 fbxExpter.SetFileExportVersion("FBX201400");
 fbxExpter.SetProgressCallback(fbxProgressCallback);
 FbxScene fbxScene = FbxScene.Create(fbxMgr, "Scene");
 FbxDocumentInfo fbxDocInfo = FbxDocumentInfo.Create(fbxMgr, "SceneInfo");
 fbxDocInfo.mTitle = "exports static meshes with materials and textures";
 fbxDocInfo.mSubject = "";
 fbxDocInfo.mAuthor = "bytework";
 fbxDocInfo.mRevision = "1.0";
 fbxDocInfo.mKeywords = "export mesh materials textures uvs";
 fbxDocInfo.mComment = "";
 fbxDocInfo.Original_ApplicationName.Set(string.Format("Unity {0}", "FBX Exporter"));
                fbxDocInfo.LastSaved_ApplicationName.Set(fbxDocInfo.Original_ApplicationName.Get());
                //fbxDocInfo.Original_ApplicationVersion.Set("1.0");
                fbxDocInfo.LastSaved_ApplicationVersion.Set(fbxDocInfo.Original_ApplicationVersion.Get());
fbxScene.SetSceneInfo(fbxDocInfo);
FbxGlobalSettings globalSettings = fbxScene.GetGlobalSettings();
globalSettings.SetSystemUnit(FbxSystemUnit.cm);
globalSettings.SetAxisSystem(FbxAxisSystem.MayaYUp);

然后是一个list类似的树状结构,每个根节点记录了该物体的名称,然后是子节点,一个物体包括多个子节点,包括mesh renderer,transform等节点信息,节点信息里有属性等细节信息。

    要写fbx文件,首先就是fbx sdk的封装,Autodesk官网提供了fbx的核心sdk,但是是c++版本的,需要对它进行一次C#封装,封装完之后就是unity端,c#导出脚本的编写了,我们要把unity的物体导出为fbx就需要把unity物体的每个组件都转换为fbx格式的组件,然后再写入fbx文件。这就需要我们手动对每个组件进行一次转换。例如unity中的Vector3,对应fbx中的就是FbxDouble3,unity中物体的旋转就是一个四元数,对应fbx的FbxQuaternion 。unity中的AnimationCurve 对应fbx中的FbxAnimCurve等。

  sdk封装和转换脚本写完后就可以进行实际的导出了,流程就是首先获取unity场景中的一个物体,然后获取该物体的所有子物体,对这些物体按找层级关系,写入一个fbxnode,节点名字就是物体名字,然后输出每个物体的Tranform组件,将其写入fbx中,因为每个物体都必定会有这个节点。

public static FbxVector4 ConvertQuaternionToXYZEuler(FbxQuaternion quat)
    {
        FbxAMatrix val = new FbxAMatrix();
        val.SetQ(quat);
        FbxVector4 r = val.GetR();
        return new FbxVector4(r.X, 0.0 - r.Y, 0.0 - r.Z, r.W);
    }

 

protected bool ExportTransform(Transform unityTransform, FbxNode fbxNode, Vector3 newCenter, TransformExportType exportType)
    {
        fbxNode.SetRotationOrder((FbxNode.EPivotSet)0, (FbxEuler.EOrder)0);
        Vector3 leftHandedVector;
        FbxDouble3 val = default(FbxDouble3);
        Vector3 val2;
        switch (exportType)
        {
            case TransformExportType.Reset:
                leftHandedVector = Vector3.zero;
                val = new FbxDouble3(0.0);
                val2 = Vector3.one;
                break;
            case TransformExportType.Global:
                leftHandedVector = GetRecenteredTranslation(unityTransform, newCenter);
                val = ConvertQuaternionToXYZEuler(unityTransform.rotation);
                val2 = unityTransform.lossyScale;
                break;
            default:
                leftHandedVector = unityTransform.localPosition;
                val = ConvertQuaternionToXYZEuler(unityTransform.localRotation);
                val2 = unityTransform.localScale;
                break;
        }
        FbxVector4 val3 = ConvertToRightHanded(leftHandedVector, 100f);
        FbxDouble3 val4 = default(FbxDouble3);
        val4 = new FbxDouble3(val2.x, val2.y, val2.z);
        fbxNode.LclTranslation.Set(new FbxDouble3(val3.X, val3.Y, val3.Z));
        fbxNode.LclRotation.Set(val);
        fbxNode.LclScaling.Set(val4);
        return true;
    }

如果这个物体是空物体,那么这个物体就导出成功了。接着再次循环物体,得到每个物体独有的组件,将其写入对应fbx节点。

例如下面的代码就是导出材质球的颜色的方法

    public FbxDouble3 GetMaterialColor(Material unityMaterial, string unityPropName, float defaultValue = 1f)
    {
        if (!unityMaterial)
        {
            return new FbxDouble3(defaultValue);
        }
        if (!unityMaterial.HasProperty(unityPropName))
        {
            return new FbxDouble3(defaultValue);
        }
        Color color = unityMaterial.GetColor(unityPropName);
        return new FbxDouble3(color.r, color.g, color.b);
    }

通过上述的循环完成后,一个完整的fbx文件也就导出来了。有什么问题欢迎大家交流,如果有类似需求的也可以交流合作。q2609087666

 

你可能感兴趣的:(Unity)