LoginSignup
3
4

More than 5 years have passed since last update.

Unity export fbx in Edit Mode

Posted at

Editor上で、[ExecuteInEditMode]を使って、Scene上に作成したColorやBoneWeight等の
情報を含むMeshを、一旦Assets/に保存して、ParticleSystem等で利用するという事がしたくて、作成。
自分仕様なので、中身は見づらいかも知れないが、一旦exportすることにより、
UnityのFbx ImporterのEdgeやTangents等をCalculateする機能が使えて、結構便利なので共有します。

使い方
・このComponentをAttachしたGameObjectを作成し、Inspector上で操作する。
・保存するMesh Rendererを含むGameObjectのRootをInspector/exportObjectにDrop。
・Inspector/zoom は大抵のfbx fileはそうだったので、defaultは100にしている。
・Inspector/exportFbx をtrueにするとexport実行。
・Inspector/exportTexture はRendererのmaterialsに含まれるテクスチャをpngで保存。

問題点
・ファイル仕様のバージョンが古いので、3Dアプリケーションなどからは読めない。
・AnimationClipをPlotして吐き出す事もやってみたが、あまりうまく行かない。

#if UNITY_EDITOR
using UnityEngine;
using System.Collections;
using System.IO;
using UnityEditor;

[ExecuteInEditMode]
public class FBXExporter2 : MonoBehaviour
{
    public GameObject exportObject = null;
    public string filePath = "";
    public float zoom = 100.0f;
    public int rotationPlotQuarity = 120;
    public bool exportFbx = false;
    public bool exportTexture = false;

    private GameObject lstObj;
    private string lstName;

    private string expTxt0 = "";
    private string expTxt1 = "";
    private Transform[] tfs = new Transform[0];
    enum Type
    {
        Null,
        Mesh,
        Skin
    }
    private Type[] types = new Type[0];
    private AnimationClip clip;

    private bool isSkin = false;
    private int mdlCnt = 0;
    private int dfmCnt = 0;
    private int pseCnt = 0;

    void Update ()
    {
        if ( exportObject != lstObj ) {
            lstObj = exportObject;
            filePath = "";
        } else if ( exportObject != null && exportObject.name != lstName ) {
            lstName = exportObject.name;
            filePath = "";
        }
        if ( exportFbx ) {
            exportFbx = false;
            ExportMain();
        }
        if ( exportTexture ) {
            exportTexture = false;
            ExportTexture();
        }
    }

    void ExportMain ()
    {
        if ( !exportObject ) { return; }
        if ( filePath == "" ) { filePath = exportObject.name; }

        SubMeshCheck();

        exportObject.transform.parent = null;
        int num;
        num = ObjCount(exportObject.transform, 0);
        tfs = new Transform[num];
        types = new Type[num];


        Dig(exportObject.transform, 0);

        expTxt0 = "";
        expTxt1 = "";

        //Body//
        AddExpTxt1("; Object properties");
        AddExpTxt1(";------------------------------------------------------------------");
        AddExpTxt1("");
        AddExpTxt1("Objects: {");
        ObjectsTxt(num);
        if ( isSkin ) { PoseTxt(num); }
        if ( isSkin ) { DeformerTxt(num); }
        AddExpTxt1("}");
        AddExpTxt1("");
        ConnectTxt(num);

        //Header//
        AddExpTxt0("; F 6.1 project file");
        AddExpTxt0("");
        AddExpTxt0("; Object definitions");
        AddExpTxt0(";------------------------------------------------------------------");
        AddExpTxt0("");
        AddExpTxt0("Definitions: {");
        AddExpTxt0("    Count: " + (mdlCnt + dfmCnt + pseCnt));
        if ( mdlCnt > 0 ) {
            AddExpTxt0("    ObjectType: \"Model\" {");
            AddExpTxt0("        Count: " + mdlCnt);
            AddExpTxt0("    }");
        }
        if ( dfmCnt > 0 ) {
            AddExpTxt0("    ObjectType: \"Deformer\" {");
            AddExpTxt0("        Count: " + dfmCnt);
            AddExpTxt0("    }");
        }
        if ( pseCnt > 0 ) {
            AddExpTxt0("    ObjectType: \"Pose\" {");
            AddExpTxt0("        Count: " + pseCnt);
            AddExpTxt0("    }");
        }
        AddExpTxt0("}");
        AddExpTxt0("");

        GetAnimationClip();
        if ( clip != null ) { AnimationText(); }

        Export("Assets/" + filePath + ".fbx", expTxt0 + expTxt1);

        SubMeshEndProcess();
    }

    //Number of objects in the hierarchy//
    int ObjCount (Transform tf, int num)
    {
        num++;

        int i;
        for ( i = 0; i < tf.childCount; i++ ) {
            num = ObjCount(tf.GetChild(i), num);
        }

        return num;
    }

    //Hierarchy expansion//
    int Dig (Transform tf, int no)
    {
        MeshRenderer mr = tf.GetComponent("MeshRenderer") as MeshRenderer;
        SkinnedMeshRenderer smr = tf.GetComponent("SkinnedMeshRenderer") as SkinnedMeshRenderer;

        tfs[no] = tf;
        if ( mr ) {
            types[no] = Type.Mesh;
        } else if ( smr ) {
            types[no] = Type.Skin;
            isSkin = true;
        } else {
            types[no] = Type.Null;
        }

        no++;

        int i;
        for ( i = 0; i < tf.childCount; i++ ) {
            no = Dig(tf.GetChild(i), no);
        }

        return no;
    }

    //Add 1 line of text//
    void AddExpTxt0 (string txt)
    {
        expTxt0 += txt + "\n";
    }
    void AddExpTxt1 (string txt)
    {
        expTxt1 += txt + "\n";
    }

    //Object definition in scene//
    void ObjectsTxt (int num)
    {
        int i;
        for ( i = 0; i < num; i++ ) {
            if ( types[i] == Type.Null ) {
                NullTxt(i);
            } else if ( types[i] == Type.Mesh ) {
                MeshTxt(i, types[i]);
            } else if ( types[i] == Type.Skin ) {
                MeshTxt(i, types[i]);
            }
        }
    }

    //Empty GameObject definition text//
    void NullTxt (int no)
    {
        Vector3 pos = VectorExponential(tfs[no].localPosition);
        pos.x *= -1;
        pos *= zoom;
        //回転軸順を調整 unity:zxy FBX:xyz//
        Quaternion rot = tfs[no].localRotation;
        Vector3 eul = VectorExponential(GetEulerXYZ(rot));
        eul.y = -eul.y;
        eul.z = -eul.z;
        Vector3 scl = VectorExponential(tfs[no].localScale);

        AddExpTxt1("    Model: \"Model::" + tfs[no].name + "\",\"Null\" {");
        AddExpTxt1("        Properties60: {");
        AddExpTxt1("            Property: \"Lcl Translation\", \"Lcl Translation\", \"A+\"," + VectorTxt(pos));
        AddExpTxt1("            Property: \"Lcl Rotation\", \"Lcl Rotation\", \"A+\"," + VectorTxt(eul));
        AddExpTxt1("            Property: \"Lcl Scaling\", \"Lcl Scaling\", \"A+\"," + VectorTxt(scl));
        AddExpTxt1("        }");
        AddExpTxt1("    }");

        mdlCnt++;
    }

    //Mesh definition text//
    void MeshTxt (int no, Type type)
    {
        Vector3 pos = VectorExponential(tfs[no].localPosition);
        pos.x = -pos.x;
        pos *= zoom;
        //回転軸順を調整 unity:zxy FBX:xyz//
        Quaternion rot = tfs[no].localRotation;
        Vector3 eul = VectorExponential(GetEulerXYZ(rot));
        eul.y *= -1;
        eul.z *= -1;
        Vector3 siz = VectorExponential(tfs[no].localScale);

        AddExpTxt1("    Model: \"Model::" + tfs[no].name + "\",\"Mesh\" {");
        AddExpTxt1("        Properties60: {");
        AddExpTxt1("            Property: \"Lcl Translation\", \"Lcl Translation\", \"A+\"," + VectorTxt(pos));
        AddExpTxt1("            Property: \"Lcl Rotation\", \"Lcl Rotation\", \"A+\"," + VectorTxt(eul));
        AddExpTxt1("            Property: \"Lcl Scaling\", \"Lcl Scaling\", \"A+\"," + VectorTxt(siz));
        AddExpTxt1("        }");

        int i;
        Mesh mesh = null;
        if ( type == Type.Mesh ) {
            MeshFilter meshf = tfs[no].GetComponent("MeshFilter") as MeshFilter;
            mesh = meshf.sharedMesh;
        } else if ( type == Type.Skin ) {
            SkinnedMeshRenderer smr = tfs[no].GetComponent("SkinnedMeshRenderer") as SkinnedMeshRenderer;
            mesh = smr.sharedMesh;
        }

        //Vertices//
        Vector3[] vrts = mesh.vertices;
        string vrtTxt = "";
        for ( i = 0; i < mesh.vertexCount; i++ ) {
            Vector3 vrt = VectorExponential(vrts[i]);
            vrt.x = -vrt.x;
            vrt *= zoom;
            if ( i > 0 )
                vrtTxt += ",";
            vrtTxt += VectorTxt(vrt);
        }
        AddExpTxt1("        Vertices: " + vrtTxt);

        //Triangles//
        int[] tris = mesh.triangles;
        string triTxt = "";
        for ( i = 0; i < tris.Length / 3; i++ ) {
            if ( i > 0 )
                triTxt += ",";
            triTxt += tris[i * 3 + 2];
            triTxt += ",";
            triTxt += tris[i * 3 + 1];
            triTxt += ",";
            triTxt += -(tris[i * 3 + 0] + 1);
        }
        AddExpTxt1("        PolygonVertexIndex: " + triTxt);

        //Normals//
        Vector3[] nrms = mesh.normals;
        string nrmTxt = "";
        for ( i = 0; i < nrms.Length; i++ ) {
            Vector3 nrm = nrms[i];
            nrm.x *= -1;
            if ( i > 0 )
                nrmTxt += ",";
            nrmTxt += VectorTxt(nrm);
        }
        AddExpTxt1("        LayerElementNormal: 0 {");
        AddExpTxt1("            MappingInformationType: \"ByVertice\"");
        AddExpTxt1("            ReferenceInformationType: \"Direct\"");
        AddExpTxt1("            Normals: " + nrmTxt);
        AddExpTxt1("        }");

        //UV//
        Vector2[] uvs = mesh.uv;
        if ( uvs.Length > 0 ) {
            string uvTxt = "";
            string uviTxt = "";
            for ( i = 0; i < uvs.Length; i++ ) {
                Vector2 uv = uvs[i];
                if ( i > 0 )
                    uvTxt += ",";
                uvTxt += FloatTxt(uv.x) + "," + FloatTxt(uv.y);

                if ( i > 0 )
                    uviTxt += ",";
                uviTxt += i;
            }
            AddExpTxt1("        LayerElementUV: 0 {");
            AddExpTxt1("            MappingInformationType: \"ByVertice\"");
            AddExpTxt1("            ReferenceInformationType: \"IndexToDirect\"");
            AddExpTxt1("            UV: " + uvTxt);
            AddExpTxt1("            UVIndex: " + uviTxt);
            AddExpTxt1("        }");
        }

        Vector2[] uv2s = mesh.uv2;
        if ( uv2s.Length > 0 ) {
            if ( uv2s.Length > 0 ) {
                string uvTxt = "";
                string uviTxt = "";
                for ( i = 0; i < uv2s.Length; i++ ) {
                    Vector2 uv = uv2s[i];
                    if ( i > 0 )
                        uvTxt += ",";
                    uvTxt += FloatTxt(uv.x) + "," + FloatTxt(uv.y);

                    if ( i > 0 )
                        uviTxt += ",";
                    uviTxt += i;
                }
                AddExpTxt1("        LayerElementUV: 1 {");
                AddExpTxt1("            MappingInformationType: \"ByVertice\"");
                AddExpTxt1("            ReferenceInformationType: \"IndexToDirect\"");
                AddExpTxt1("            UV: " + uvTxt);
                AddExpTxt1("            UVIndex: " + uviTxt);
                AddExpTxt1("        }");
            }
        }

        //Vertex Colors//
        Color[] colrs = mesh.colors;
        if ( colrs.Length > 0 ) {
            string colrTxt = "";
            string colriTxt = "";
            for ( i = 0; i < colrs.Length; i++ ) {
                Color clr = colrs[i];
                if ( i > 0 )
                    colrTxt += ",";
                colrTxt += clr.r + "," + clr.g + "," + clr.b + "," + clr.a;

                if ( i > 0 )
                    colriTxt += ",";
                colriTxt += i;
            }

            AddExpTxt1("        LayerElementColor: 0 {");
            AddExpTxt1("            MappingInformationType: \"ByVertice\"");
            AddExpTxt1("            ReferenceInformationType: \"IndexToDirect\"");
            AddExpTxt1("            Colors: " + colrTxt);
            AddExpTxt1("            ColorIndex: " + colriTxt);
            AddExpTxt1("        }");

        }

        //Layer infomation//
        AddExpTxt1("        Layer: 0 {");
        AddExpTxt1("            LayerElement: {");
        AddExpTxt1("                Type: \"LayerElementNormal\"");
        AddExpTxt1("                TypedIndex: 0");
        AddExpTxt1("            }");
        if ( uvs.Length > 0 ) {
            AddExpTxt1("            LayerElement: {");
            AddExpTxt1("                Type: \"LayerElementUV\"");
            AddExpTxt1("                TypedIndex: 0");
            AddExpTxt1("            }");
        }
        if ( colrs.Length > 0 ) {
            AddExpTxt1("            LayerElement: {");
            AddExpTxt1("                Type: \"LayerElementColor\"");
            AddExpTxt1("                TypedIndex: 0");
            AddExpTxt1("            }");
        }
        AddExpTxt1("        }");
        if ( uv2s.Length > 0 ) {
            AddExpTxt1("        Layer: 1 {");
            AddExpTxt1("            LayerElement: {");
            AddExpTxt1("                Type: \"LayerElementUV\"");
            AddExpTxt1("                TypedIndex: 1");
            AddExpTxt1("            }");
            AddExpTxt1("        }");
        }
        //AddExpTxt1("      NodeAttributeName: \"Geometry::" + exportObject.name + "\"");
        AddExpTxt1("    }");

        mdlCnt++;
    }

    void PoseTxt (int num)
    {
        int i;
        AddExpTxt1("    Pose: \"Pose::BIND_POSES\", \"BindPose\" {");
        AddExpTxt1("        NbPoseNodes: " + num);

        for ( i = 0; i < num; i++ ) {
            Transform tf = tfs[i];
            Transform pr = tf.parent;
            if ( !pr )
                pr = tf;
            Matrix4x4 mtx = exportObject.transform.localToWorldMatrix;
            Vector3 mtxVec = tf.position - exportObject.transform.position;
            mtxVec.x *= -1;
            mtx[0, 3] = mtxVec.x;
            mtx[1, 3] = mtxVec.y;
            mtx[2, 3] = mtxVec.z;

            mtx = MatrixExponential(mtx);
            string mtxTxt = MatrixTxt(mtx);

            AddExpTxt1("        PoseNode: {");
            AddExpTxt1("            Node: \"Model::" + tf.name + "\"");
            AddExpTxt1("            Matrix: " + mtxTxt);
            AddExpTxt1("        }");
        }
        AddExpTxt1("    }");
        pseCnt++;
    }

    //Deformer definition//
    void DeformerTxt (int num)
    {
        int i, j, k;

        Transform[] bnes = new Transform[0];
        BoneWeight[] wits = new BoneWeight[0];
        for ( i = 0; i < num; i++ ) {
            if ( types[i] == Type.Skin ) {
                SkinnedMeshRenderer smr = tfs[i].GetComponent("SkinnedMeshRenderer") as SkinnedMeshRenderer;
                bnes = smr.bones;
                Mesh mesh = smr.sharedMesh;
                wits = mesh.boneWeights;

                AddExpTxt1("    Deformer: \"Deformer::Skin " + tfs[i].name + "\", \"Skin\" {");
                AddExpTxt1("        Type: \"Skin\"");
                AddExpTxt1("    }");
                dfmCnt++;

                for ( j = 0; j < bnes.Length; j++ ) {
                    Transform bne = bnes[j];
                    string idxTxt = "";
                    string witTxt = "";
                    for ( k = 0; k < wits.Length; k++ ) {
                        BoneWeight wit = wits[k];
                        if ( wit.boneIndex0 == j && wit.weight0 > 0 ) {
                            if ( idxTxt.Length > 0 )
                                idxTxt += ",";
                            if ( witTxt.Length > 0 )
                                witTxt += ",";
                            idxTxt += k;
                            witTxt += FloatExponential(wit.weight0);
                        } else if ( wit.boneIndex1 == j && wit.weight1 > 0 ) {
                            if ( idxTxt.Length > 0 )
                                idxTxt += ",";
                            if ( witTxt.Length > 0 )
                                witTxt += ",";
                            idxTxt += k;
                            witTxt += FloatExponential(wit.weight1);
                        } else if ( wit.boneIndex2 == j && wit.weight2 > 0 ) {
                            if ( idxTxt.Length > 0 )
                                idxTxt += ",";
                            if ( witTxt.Length > 0 )
                                witTxt += ",";
                            idxTxt += k;
                            witTxt += FloatExponential(wit.weight2);
                        } else if ( wit.boneIndex3 == j && wit.weight3 > 0 ) {
                            if ( idxTxt.Length > 0 )
                                idxTxt += ",";
                            if ( witTxt.Length > 0 )
                                witTxt += ",";
                            idxTxt += k;
                            witTxt += FloatExponential(wit.weight3);
                        }
                    }


                    //Create bone rotation matrix//
                    Transform parent = bne.parent;
                    if ( !parent )
                        parent = bne;

                    Quaternion bRot = bne.rotation;
                    Vector3 eulr = bRot.eulerAngles;
                    eulr.y *= -1;
                    eulr.z *= -1;
                    bne.rotation = Quaternion.Euler(eulr);

                    Matrix4x4 mtx0 = tfs[i].transform.localToWorldMatrix * bne.worldToLocalMatrix;
                    //mtx0[0, 3] *= -1;//FBXとX方向が逆

                    Vector3 mtxVec = bne.position;
                    mtxVec.y *= -1;
                    mtxVec.z *= -1;
                    mtxVec = Quaternion.Inverse(bne.rotation) * mtxVec;
                    mtx0[0, 3] = mtxVec.x;
                    mtx0[1, 3] = mtxVec.y;
                    mtx0[2, 3] = mtxVec.z;

                    mtx0 = MatrixExponential(mtx0);
                    string tfTxt = MatrixTxt(mtx0);

                    bne.rotation = bRot;

                    Matrix4x4 mtx1 = parent.localToWorldMatrix * bne.worldToLocalMatrix;
                    mtx1 = MatrixExponential(mtx1);
                    string tflTxt = MatrixTxt(mtx1);

                    AddExpTxt1("    Deformer: \"SubDeformer::Cluster " + bne.name + "_" + tfs[i].name + "\", \"Cluster\" {");
                    AddExpTxt1("        Type: \"Cluster\"");
                    AddExpTxt1("        Indexes: " + idxTxt);
                    AddExpTxt1("        Weights: " + witTxt);
                    AddExpTxt1("        Transform: " + tfTxt);
                    AddExpTxt1("        TransformLink: " + tflTxt);
                    AddExpTxt1("    }");

                    dfmCnt++;
                }
            }
        }

    }

    //Connection definition//
    void ConnectTxt (int num)
    {
        AddExpTxt1("; Object connections");
        AddExpTxt1(";------------------------------------------------------------------");
        AddExpTxt1("");
        AddExpTxt1("Connections: {");

        int i, j;
        string name = "";
        string pname = "";
        Transform tf = null;
        Transform prt = null;
        for ( i = 0; i < num; i++ ) {
            tf = tfs[i];
            prt = tf.parent;
            if ( prt ) {
                pname = prt.name;
            } else {
                pname = "Scene";
            }
            name = tfs[i].name;

            AddExpTxt1("    Connect: \"OO\", \"Model::" + name + "\", \"Model::" + pname + "\"");
        }

        Transform[] bnes = new Transform[0];
        int skinCount = 0;
        if ( isSkin ) {
            for ( i = 0; i < num; i++ ) {
                if ( types[i] == Type.Skin ) {
                    tf = tfs[i];
                    SkinnedMeshRenderer smr = tf.GetComponent("SkinnedMeshRenderer") as SkinnedMeshRenderer;
                    if ( !smr )
                        continue;

                    skinCount++;
                    string skinName = "Skin " + tf.name;
                    AddExpTxt1("    Connect: \"OO\", \"Deformer::" + skinName + "\", \"Model::" + tf.name + "\"");

                    bnes = smr.bones;
                    for ( j = 0; j < bnes.Length; j++ ) {
                        Transform bne = bnes[j];
                        AddExpTxt1("    Connect: \"OO\", \"SubDeformer::Cluster " + bne.name + "_" + tf.name + "\", \"Deformer::" + skinName + "\"");
                        AddExpTxt1("    Connect: \"OO\", \"Model::" + bne.name + "\", \"SubDeformer::Cluster " + bne.name + "_" + tf.name + "\"");
                    }
                }
            }
        }
        AddExpTxt1("}");
    }

    //Animation definition//
    void AnimationText ()
    {
        AddExpTxt1(";Takes and animation section");
        AddExpTxt1(";------------------------------------------------------------------");
        AddExpTxt1("");
        AddExpTxt1("Takes:  {");
        AddExpTxt1("    Current: \"" + clip.name + "\"");
        AddExpTxt1("    Take: \"" + clip.name + "\" {");
        AddExpTxt1("        FileName: \"" + clip.name + ".tak\"");
        AddExpTxt1("        LocalTime: 0," + FloatExponential(clip.length));
        AddExpTxt1("        ReferenceTime: 0," + FloatExponential(clip.length));
        AddExpTxt1("");
        AddExpTxt1("        ;Models animation");
        AddExpTxt1("        ;----------------------------------------------------");
        AnimationModelText();
        AddExpTxt1("    }");
        AddExpTxt1("}");
    }

    public AnimationData[] animationDatas;
    void AnimationModelText ()
    {
        GetAnimationDatas();
        for ( int i = 0; i < animationDatas.Length; i++ ) {
            var animData = animationDatas[i];
            var anmTf = exportObject.transform.Find(animData.path);
            string name = animData.name;
            AddExpTxt1("        Model: \"Model::" + name + "\" {");
            AddExpTxt1("            Version: 1.1");
            AddExpTxt1("            Channel: \"Transform\" {");
            if ( animData.positionX.length > 0 && animData.positionY.length > 0 && animData.positionZ.length > 0 ) {
                var defaultPos = Vector3.zero;
                if ( anmTf != null ) {
                    defaultPos = anmTf.localPosition;
                }
                AddExpTxt1("                Channel: \"T\" {");
                AddExpTxt1("                    Channel: \"X\" {");
                AddExpTxt1("                        Default: " + FloatExponential(defaultPos.x * zoom));
                AddExpTxt1("                        KeyVer: 4005");
                AddExpTxt1("                        KeyCount: " + animData.positionX.keys.Length);
                AddExpTxt1("                        Key:" + KeyText(animData.positionX.keys, zoom));
                AddExpTxt1("                        Color: 1,0,0");
                AddExpTxt1("                    }");
                AddExpTxt1("                    Channel: \"Y\" {");
                AddExpTxt1("                        Default: " + FloatExponential(defaultPos.y * zoom));
                AddExpTxt1("                        KeyVer: 4005");
                AddExpTxt1("                        KeyCount: " + animData.positionY.keys.Length);
                AddExpTxt1("                        Key:" + KeyText(animData.positionY.keys, zoom));
                AddExpTxt1("                        Color: 0,1,0");
                AddExpTxt1("                    }");
                AddExpTxt1("                    Channel: \"Z\" {");
                AddExpTxt1("                        Default: " + FloatExponential(defaultPos.z * zoom));
                AddExpTxt1("                        KeyVer: 4005");
                AddExpTxt1("                        KeyCount: " + animData.positionZ.keys.Length);
                AddExpTxt1("                        Key:" + KeyText(animData.positionZ.keys, zoom));
                AddExpTxt1("                        Color: 0,0,1");
                AddExpTxt1("                    }");
                AddExpTxt1("                    LayerType: 1");
                AddExpTxt1("                }");
            }
            if ( animData.eulerX.length > 0 && animData.eulerY.length > 0 && animData.eulerZ.length > 0 ) {
                var eul = Vector3.zero;
                if ( anmTf != null ) {
                    eul = GetEulerXYZ(anmTf.localRotation);
                    eul.y = -eul.y;
                    eul.z = -eul.z;
                }
                AddExpTxt1("                Channel: \"R\" {");
                AddExpTxt1("                    Channel: \"X\" {");
                AddExpTxt1("                        Default: " + FloatExponential(eul.x));
                AddExpTxt1("                        KeyVer: 4005");
                AddExpTxt1("                        KeyCount: " + animData.eulerX.keys.Length);
                AddExpTxt1("                        Key:" + KeyText(animData.eulerX.keys, 1));
                AddExpTxt1("                        Color: 1,0,0");
                AddExpTxt1("                    }");
                AddExpTxt1("                    Channel: \"Y\" {");
                AddExpTxt1("                        Default: " + FloatExponential(eul.y));
                AddExpTxt1("                        KeyVer: 4005");
                AddExpTxt1("                        KeyCount: " + animData.eulerY.keys.Length);
                AddExpTxt1("                        Key:" + KeyText(animData.eulerY.keys, 1));
                AddExpTxt1("                        Color: 0,1,0");
                AddExpTxt1("                    }");
                AddExpTxt1("                    Channel: \"Z\" {");
                AddExpTxt1("                        Default: " + FloatExponential(eul.z));
                AddExpTxt1("                        KeyVer: 4005");
                AddExpTxt1("                        KeyCount: " + animData.eulerZ.keys.Length);
                AddExpTxt1("                        Key:" + KeyText(animData.eulerZ.keys, 1));
                AddExpTxt1("                        Color: 0,0,1");
                AddExpTxt1("                    }");
                AddExpTxt1("                    LayerType: 2");
                AddExpTxt1("                }");
            }
            if ( animData.scaleX.length > 0 && animData.scaleY.length > 0 && animData.scaleZ.length > 0 ) {
                var defaultScl = Vector3.zero;
                if ( anmTf != null ) {
                    defaultScl = anmTf.localPosition;
                }
                AddExpTxt1("                Channel: \"S\" {");
                AddExpTxt1("                    Channel: \"X\" {");
                AddExpTxt1("                        Default: " + FloatExponential(defaultScl.x));
                AddExpTxt1("                        KeyVer: 4005");
                AddExpTxt1("                        KeyCount: " + animData.scaleX.keys.Length);
                AddExpTxt1("                        Key:" + KeyText(animData.scaleX.keys, 1));
                AddExpTxt1("                        Color: 1,0,0");
                AddExpTxt1("                    }");
                AddExpTxt1("                    Channel: \"Y\" {");
                AddExpTxt1("                        Default: " + FloatExponential(defaultScl.y));
                AddExpTxt1("                        KeyVer: 4005");
                AddExpTxt1("                        KeyCount: " + animData.scaleY.keys.Length);
                AddExpTxt1("                        Key:" + KeyText(animData.scaleY.keys, 1));
                AddExpTxt1("                        Color: 0,1,0");
                AddExpTxt1("                    }");
                AddExpTxt1("                    Channel: \"Z\" {");
                AddExpTxt1("                        Default: " + FloatExponential(defaultScl.z));
                AddExpTxt1("                        KeyVer: 4005");
                AddExpTxt1("                        KeyCount: " + animData.scaleZ.keys.Length);
                AddExpTxt1("                        Key:" + KeyText(animData.scaleZ.keys, 1));
                AddExpTxt1("                        Color: 0,0,1");
                AddExpTxt1("                    }");
                AddExpTxt1("                    LayerType: 3");
                AddExpTxt1("                }");
                AddExpTxt1("            }");
            }
            AddExpTxt1("            Channel: \"Visibility\" {");
            AddExpTxt1("                Default: 1");
            AddExpTxt1("                Color: 0.75,0,0");
            AddExpTxt1("                LayerType: 1");
            AddExpTxt1("            }");
            AddExpTxt1("        }");
        }
    }

    string KeyText (Keyframe[] keys, float _zoom)
    {
        string text = "";
        int num = keys.Length;
        for ( int i = 0; i < num; i++ ) {
            text += ((double)keys[i].time * 46232344158).ToString();//FBXの謎定数46232344158
            text += ",";
            text += FloatExponential(keys[i].value * _zoom);
            text += ",U,s,";
            text += FloatExponential(keys[i].outTangent * _zoom);
            text += ",";
            if ( i < num - 1 ) {
                text += FloatExponential(keys[i + 1].inTangent * _zoom);
            } else {
                text += "0";
            }
            text += ",n";
            if ( i < num - 1 ) {
                text += ",";
            }
        }
        return text;
    }

    [System.Serializable]
    public class AnimationData
    {
        public string name;
        public string path;
        public AnimationCurve positionX;
        public AnimationCurve positionY;
        public AnimationCurve positionZ;
        public AnimationCurve eulerX;
        public AnimationCurve eulerY;
        public AnimationCurve eulerZ;
        public AnimationCurve rotationX;
        public AnimationCurve rotationY;
        public AnimationCurve rotationZ;
        public AnimationCurve rotationW;
        public AnimationCurve scaleX;
        public AnimationCurve scaleY;
        public AnimationCurve scaleZ;
        public AnimationData (string _path)
        {
            name = System.IO.Path.GetFileName(_path);
            path = _path;
            positionX = new AnimationCurve();
            positionY = new AnimationCurve();
            positionZ = new AnimationCurve();
            eulerX = new AnimationCurve();
            eulerY = new AnimationCurve();
            eulerZ = new AnimationCurve();
            rotationX = new AnimationCurve();
            rotationY = new AnimationCurve();
            rotationZ = new AnimationCurve();
            rotationW = new AnimationCurve();
            scaleX = new AnimationCurve();
            scaleY = new AnimationCurve();
            scaleZ = new AnimationCurve();
        }
    }

    void GetAnimationDatas ()
    {
        AnimationData[] _animDatas = new AnimationData[100];
        int pt = 0;
        var curveBindings = AnimationUtility.GetCurveBindings(clip);
        for ( int i = 0; i < curveBindings.Length; i++ ) {
            var binding = curveBindings[i];
            AnimationCurve curve = AnimationUtility.GetEditorCurve(clip, binding);


            if ( binding.type != typeof(Transform) ) { continue; }
            var datPath = binding.path;
            int hitPt = -1;
            for ( int j = 0; j < pt; j++ ) {
                if ( _animDatas[j].path == datPath ) {
                    hitPt = j;
                    break;
                }
            }
            if ( hitPt == -1 ) {
                hitPt = pt;
                pt++;
                _animDatas[hitPt] = new AnimationData(datPath);
            }
            var propertyName = binding.propertyName;
            if ( propertyName == "m_LocalPosition.x" ) {
                _animDatas[hitPt].positionX = CurveReverse(curve);
            } else if ( propertyName == "m_LocalPosition.y" ) {
                _animDatas[hitPt].positionY = curve;
            } else if ( propertyName == "m_LocalPosition.z" ) {
                _animDatas[hitPt].positionZ = curve;
            } else if ( propertyName == "localEulerAnglesRaw.x" ) {
                _animDatas[hitPt].eulerX = curve;
            } else if ( propertyName == "localEulerAnglesRaw.y" ) {
                _animDatas[hitPt].eulerY = curve;
            } else if ( propertyName == "localEulerAnglesRaw.z" ) {
                _animDatas[hitPt].eulerZ = curve;
            } else if ( propertyName == "m_LocalRotation.x" ) {
                _animDatas[hitPt].rotationX = curve;
            } else if ( propertyName == "m_LocalRotation.y" ) {
                _animDatas[hitPt].rotationY = curve;
            } else if ( propertyName == "m_LocalRotation.z" ) {
                _animDatas[hitPt].rotationZ = curve;
            } else if ( propertyName == "m_LocalRotation.w" ) {
                _animDatas[hitPt].rotationW = curve;
            } else if ( propertyName == "m_LocalScale.x" ) {
                _animDatas[hitPt].scaleX = curve;
            } else if ( propertyName == "m_LocalScale.y" ) {
                _animDatas[hitPt].scaleY = curve;
            } else if ( propertyName == "m_LocalScale.z" ) {
                _animDatas[hitPt].scaleZ = curve;
            } else {
                Debug.Log("AnimationPropertyName = " + propertyName);
            }
        }
        animationDatas = new AnimationData[pt];
        for ( int i = 0; i < pt; i++ ) {
            animationDatas[i] = _animDatas[i];
        }

        //Plot rotation once
        for ( int i = 0; i < pt; i++ ) {
            var anmData = animationDatas[i];
            if ( anmData.eulerX.length > 0 && anmData.eulerY.length > 0 && anmData.eulerZ.length > 0 ) {
                float anmLength = animationDatas[i].eulerX.keys[animationDatas[i].eulerX.keys.Length - 1].time;
                int numFrame = Mathf.FloorToInt(anmLength * rotationPlotQuarity) + 1;
                var keysX = new Keyframe[numFrame];
                var keysY = new Keyframe[numFrame];
                var keysZ = new Keyframe[numFrame];
                for ( int j = 0; j < numFrame; j++ ) {
                    float t = anmLength * j / (numFrame - 1);
                    var rot = Quaternion.Euler(anmData.eulerX.Evaluate(t), anmData.eulerY.Evaluate(t), anmData.eulerZ.Evaluate(t));
                    var eul = GetEulerXYZ(rot);
                    eul.y = -eul.y;
                    eul.z = -eul.z;
                    keysX[j] = new Keyframe();
                    keysX[j].time = t;
                    keysX[j].value = eul.x;
                    keysY[j] = new Keyframe();
                    keysY[j].time = t;
                    keysY[j].value = eul.y;
                    keysZ[j] = new Keyframe();
                    keysZ[j].time = t;
                    keysZ[j].value = eul.z;
                }
                anmData.eulerX = new AnimationCurve(Softkeys(keysX));
                anmData.eulerY = new AnimationCurve(Softkeys(keysY));
                anmData.eulerZ = new AnimationCurve(Softkeys(keysZ));
            } else if ( anmData.rotationX.length > 0 && anmData.rotationY.length > 0 && anmData.rotationZ.length > 0 && anmData.rotationW.length > 0 ) {
                float anmLength = animationDatas[i].rotationX.keys[animationDatas[i].rotationX.keys.Length - 1].time;
                int numFrame = Mathf.FloorToInt(anmLength * rotationPlotQuarity) + 1;
                var keysX = new Keyframe[numFrame];
                var keysY = new Keyframe[numFrame];
                var keysZ = new Keyframe[numFrame];
                for ( int j = 0; j < numFrame; j++ ) {
                    float t = anmLength * j / (numFrame - 1);
                    var rot = new Quaternion(anmData.rotationX.Evaluate(t), anmData.rotationY.Evaluate(t), anmData.rotationZ.Evaluate(t), anmData.rotationW.Evaluate(t));
                    var eul = GetEulerXYZ(rot);
                    eul.y = -eul.y;
                    eul.z = -eul.z;
                    keysX[j] = new Keyframe();
                    keysX[j].time = t;
                    keysX[j].value = eul.x;
                    keysY[j] = new Keyframe();
                    keysY[j].time = t;
                    keysY[j].value = eul.y;
                    keysZ[j] = new Keyframe();
                    keysZ[j].time = t;
                    keysZ[j].value = eul.z;
                }
                anmData.eulerX = new AnimationCurve(Softkeys(keysX));
                anmData.eulerY = new AnimationCurve(Softkeys(keysY));
                anmData.eulerZ = new AnimationCurve(Softkeys(keysZ));
            }
        }
    }

    //Soften key frame slope
    public Keyframe[] Softkeys (Keyframe[] keys)
    {
        int numKeys = keys.Length;
        for ( int i = 0; i < numKeys; i++ ) {
            float bt, bv, at, av;
            if ( i == 0 ) { bt = keys[i].time; bv = keys[i].value; } else { bt = keys[i - 1].time; bv = keys[i - 1].value; }
            if ( i < numKeys - 1 ) { at = keys[i + 1].time; av = keys[i + 1].value; } else { at = keys[i].time; av = keys[i].value; }
            float frameLength = at - bt;
            float tan;
            if ( frameLength != 0 ) { tan = (av - bv) / frameLength; } else { tan = 0f; }
            keys[i].inTangent = tan;
            keys[i].outTangent = tan;
        }
        return keys;
    }

    AnimationCurve CurveReverse (AnimationCurve curve)
    {
        var keys = curve.keys;
        for ( int i = 0; i < keys.Length; i++ ) {
            keys[i].value = -keys[i].value;
            keys[i].inTangent = -keys[i].inTangent;
            keys[i].outTangent = -keys[i].outTangent;
        }
        curve.keys = keys;
        return curve;
    }

    Vector3 VectorExponential (Vector3 vec)
    {
        return new Vector3(FloatExponential(vec.x), FloatExponential(vec.y), FloatExponential(vec.z));
    }

    Matrix4x4 MatrixExponential (Matrix4x4 mtx)
    {
        Vector4 mc0 = mtx.GetColumn(0);
        Vector4 mc1 = mtx.GetColumn(1);
        Vector4 mc2 = mtx.GetColumn(2);
        Vector4 mc3 = mtx.GetColumn(3);
        mc0[0] = FloatExponential(mc0[0]);
        mc0[1] = FloatExponential(mc0[1]);
        mc0[2] = FloatExponential(mc0[2]);
        mc0[3] = FloatExponential(mc0[3]);
        mc1[0] = FloatExponential(mc1[0]);
        mc1[1] = FloatExponential(mc1[1]);
        mc1[2] = FloatExponential(mc1[2]);
        mc1[3] = FloatExponential(mc1[3]);
        mc2[0] = FloatExponential(mc2[0]);
        mc2[1] = FloatExponential(mc2[1]);
        mc2[2] = FloatExponential(mc2[2]);
        mc2[3] = FloatExponential(mc2[3]);
        mc3[0] = FloatExponential(mc3[0]);
        mc3[1] = FloatExponential(mc3[1]);
        mc3[2] = FloatExponential(mc3[2]);
        mc3[3] = FloatExponential(mc3[3]);
        mtx.SetColumn(0, mc0);
        mtx.SetColumn(1, mc1);
        mtx.SetColumn(2, mc2);
        mtx.SetColumn(3, mc3);
        return mtx;
    }

    float FloatExponential (float f)
    {
        string s0 = "" + f;
        int len = s0.Length;
        int i, j;
        for ( i = 0; i < len; i++ ) {
            if ( s0.Substring(i, 1) == "E" ) {
                int exp;
                if ( s0.Substring(i + 1, 1) == "+" ) {
                    exp = System.Int32.Parse(s0.Substring(i + 2, len - i - 2));
                    for ( j = 0; j < exp; j++ ) {
                        f *= 10;
                    }
                    i = len;
                } else {
                    exp = System.Int32.Parse(s0.Substring(i + 2, len - i - 2));
                    for ( j = 0; j < exp; j++ ) {
                        f /= 10;
                    }
                    i = len;
                }
            }
        }

        if ( Mathf.Abs(f % 1) < 0.0001f || Mathf.Abs(f % 1) > 0.9999f ) {
            f = Mathf.Round(f);
        }

        return f;
    }

    string VectorTxt (Vector3 vec)
    {
        string vecTxt = FloatTxt(vec.x) + "," + FloatTxt(vec.y) + "," + FloatTxt(vec.z);
        return vecTxt;
    }

    string MatrixTxt (Matrix4x4 mtx)
    {
        Vector4 mc0 = mtx.GetColumn(0);
        Vector4 mc1 = mtx.GetColumn(1);
        Vector4 mc2 = mtx.GetColumn(2);
        Vector4 mc3 = mtx.GetColumn(3);

        string mtxTxt = FloatTxt(mc0[0]) + "," + FloatTxt(mc0[1]) + "," + FloatTxt(mc0[2]) + "," + FloatTxt(mc0[3]) +
            "," + FloatTxt(mc1[0]) + "," + FloatTxt(mc1[1]) + "," + FloatTxt(mc1[2]) + "," + FloatTxt(mc1[3]) +
            "," + FloatTxt(mc2[0]) + "," + FloatTxt(mc2[1]) + "," + FloatTxt(mc2[2]) + "," + FloatTxt(mc2[3]) +
            "," + FloatTxt(mc3[0] * zoom) + "," + FloatTxt(mc3[1] * zoom) + "," + FloatTxt(mc3[2] * zoom) + "," + FloatTxt(mc3[3]);
        return mtxTxt;
    }

    string FloatTxt (float f)
    {
        return "" + FloatExponential(f);
    }

    //Sub mesh process--------------------------------------------------------------------------------
    class DivisionSubMeshState
    {
        public Transform baseObj;
        public Transform parent;
        public Transform[] divisionObjs;
        public Vector3 position;
        public Quaternion rotation;
        public Vector3 scale;
        public DivisionSubMeshState (Transform _baseObj)
        {
            baseObj = _baseObj;
            parent = _baseObj.parent;
            divisionObjs = new Transform[0];
            position = _baseObj.transform.localPosition;
            rotation = _baseObj.transform.localRotation;
            scale = _baseObj.transform.localScale;
        }
    }
    private DivisionSubMeshState[] divStates;

    //Split objects including submeshes into multiple mesh objects
    void SubMeshCheck ()
    {
        divStates = new DivisionSubMeshState[0];
        var mfilts = exportObject.GetComponentsInChildren<MeshFilter>();
        if ( mfilts.Length > 0 ) {
            divStates = new DivisionSubMeshState[mfilts.Length];
            for ( int i = 0; i < mfilts.Length; i++ ) {
                var mesh = mfilts[i].sharedMesh;
                if ( mesh == null ) { continue; }
                if ( mesh.subMeshCount > 1 ) {
                    divStates[i] = DivisionSubMesh(mfilts[i].gameObject);
                    //サブメッシュオブジェをWorldRootに置き、分割オブジェを代わりに置く
                    if ( divStates[i].divisionObjs.Length > 0 ) {
                        for ( int j = 0; j < divStates[i].divisionObjs.Length; j++ ) {
                            divStates[i].divisionObjs[j].SetParent(divStates[i].parent);
                            divStates[i].divisionObjs[j].localPosition = divStates[i].position;
                            divStates[i].divisionObjs[j].localRotation = divStates[i].rotation;
                            divStates[i].divisionObjs[j].localScale = divStates[i].scale;
                        }
                        divStates[i].baseObj.SetParent(null);
                    }
                }
            }
            return;
        }
        var srends = exportObject.GetComponentsInChildren<SkinnedMeshRenderer>();
        if ( srends.Length > 0 ) {
            divStates = new DivisionSubMeshState[srends.Length];
            for ( int i = 0; i < srends.Length; i++ ) {
                var mesh = srends[i].sharedMesh;
                if ( mesh == null ) { continue; }
                if ( mesh.subMeshCount > 1 ) {
                    divStates[i] = DivisionSubMesh(srends[i].gameObject);
                    //サブメッシュオブジェをWorldRootに置き、分割オブジェを代わりに置く
                    if ( divStates[i].divisionObjs.Length > 0 ) {
                        for ( int j = 0; j < divStates[i].divisionObjs.Length; j++ ) {
                            divStates[i].divisionObjs[j].SetParent(divStates[i].parent);
                            divStates[i].divisionObjs[j].localPosition = divStates[i].position;
                            divStates[i].divisionObjs[j].localRotation = divStates[i].rotation;
                            divStates[i].divisionObjs[j].localScale = divStates[i].scale;
                        }
                        divStates[i].baseObj.SetParent(null);
                    }
                }
            }
        }
    }

    //Sub mesh object split
    DivisionSubMeshState DivisionSubMesh (GameObject meshObject)
    {
        var ret = new DivisionSubMeshState(meshObject.transform);
        if ( meshObject == null ) { return ret; }
        var _mrend = meshObject.GetComponent<MeshRenderer>();
        var _mfilt = meshObject.GetComponent<MeshFilter>();
        var _srend = meshObject.GetComponent<SkinnedMeshRenderer>();
        Material[] mats = new Material[0];
        Type type;
        Mesh _mesh = null;
        if ( _mfilt != null ) {
            if ( _mrend == null ) { return ret; }
            _mesh = _mfilt.sharedMesh;
            mats = _mrend.sharedMaterials;
            type = Type.Mesh;
        } else {
            if ( _srend == null ) { return ret; }
            _mesh = _srend.sharedMesh;
            mats = _srend.sharedMaterials;
            type = Type.Skin;
        }
        if ( _mesh == null ) { return ret; }
        int meshCount = _mesh.subMeshCount;
        if ( meshCount <= 1 ) { return ret; }
        ret.divisionObjs = new Transform[meshCount];

        for ( int i = 0; i < meshCount; i++ ) {
            Mesh mesh = new Mesh();
            mesh.name = _mesh.name + " " + i;
            GameObject gameObj = new GameObject(meshObject.name + " " + i);
            if ( type == Type.Mesh ) {
                var mrend = gameObj.AddComponent<MeshRenderer>();
                if ( mats.Length <= i + 1 ) {
                    mrend.sharedMaterial = mats[i];
                } else if ( mats.Length > 0 ) {
                    mrend.sharedMaterial = mats[0];
                }
                var mfilt = gameObj.AddComponent<MeshFilter>();
                mfilt.sharedMesh = mesh;
            } else if ( type == Type.Skin ) {
                var srend = gameObj.AddComponent<SkinnedMeshRenderer>();
                if ( mats.Length <= i + 1 ) {
                    srend.sharedMaterial = mats[i];
                } else if ( mats.Length > 0 ) {
                    srend.sharedMaterial = mats[0];
                }
                srend.bones = _srend.bones;
                srend.rootBone = _srend.rootBone;
                srend.sharedMesh = mesh;
            }

            Vector3[] _verts = _mesh.vertices;
            Vector2[] _uvs = _mesh.uv;
            Vector2[] _uv2s = _mesh.uv2;
            Vector2[] _uv3s = _mesh.uv3;
            Vector2[] _uv4s = _mesh.uv4;
            Vector3[] _norms = _mesh.normals;
            Color32[] _colrs = _mesh.colors32;
            Vector4[] _tans = _mesh.tangents;
            BoneWeight[] _weits = _mesh.boneWeights;
            Matrix4x4[] _poses = _mesh.bindposes;
            int[] tris = _mesh.GetTriangles(i);
            //使っている頂点を調べる
            bool[] uses = new bool[_mesh.vertexCount];
            for ( int j = 0; j < tris.Length; j++ ) {
                uses[tris[j]] = true;
            }
            //使わない頂点を省いたindex
            int[] idxs = new int[_mesh.vertexCount];
            int pt = 0;
            for ( int j = 0; j < _mesh.vertexCount; j++ ) {
                if ( uses[j] ) {
                    idxs[j] = pt;
                    pt++;
                }
            }
            //Reconstruct only with vertices used
            Vector3[] verts = new Vector3[pt];
            Vector2[] uvs = new Vector2[pt];
            Vector2[] uv2s = new Vector2[0];
            Vector2[] uv3s = new Vector2[0];
            Vector2[] uv4s = new Vector2[0];
            if ( _uv2s.Length > 0 ) { uv2s = new Vector2[pt]; }
            if ( _uv3s.Length > 0 ) { uv3s = new Vector2[pt]; }
            if ( _uv4s.Length > 0 ) { uv4s = new Vector2[pt]; }
            Vector3[] norms = new Vector3[0];
            if ( _norms.Length > 0 ) { norms = new Vector3[pt]; }
            Color32[] colrs = new Color32[0];
            if ( _colrs.Length > 0 ) { colrs = new Color32[pt]; }
            Vector4[] tans = new Vector4[0];
            if ( _tans.Length > 0 ) { tans = new Vector4[pt]; }
            BoneWeight[] weits = new BoneWeight[0];
            if ( _weits.Length > 0 ) { weits = new BoneWeight[pt]; }

            for ( int j = 0; j < tris.Length; j++ ) {
                tris[j] = idxs[tris[j]];
            }
            for ( int j = 0; j < _mesh.vertexCount; j++ ) {
                if ( uses[j] ) {
                    verts[idxs[j]] = _verts[j];
                    uvs[idxs[j]] = _uvs[j];
                    if ( _uv2s.Length > 0 ) { uv2s[idxs[j]] = _uv2s[j]; }
                    if ( _uv3s.Length > 0 ) { uv3s[idxs[j]] = _uv3s[j]; }
                    if ( _uv4s.Length > 0 ) { uv4s[idxs[j]] = _uv4s[j]; }
                    if ( _norms.Length > 0 ) { norms[idxs[j]] = _norms[j]; }
                    if ( _colrs.Length > 0 ) { colrs[idxs[j]] = _colrs[j]; }
                    if ( _tans.Length > 0 ) { tans[idxs[j]] = _tans[j]; }
                    if ( _weits.Length > 0 ) { weits[idxs[j]] = _weits[j]; }
                }
            }

            mesh.vertices = verts;
            mesh.uv = uvs;
            mesh.triangles = tris;
            if ( uv2s.Length > 0 ) { mesh.uv2 = uv2s; }
            if ( uv3s.Length > 0 ) { mesh.uv3 = uv3s; }
            if ( uv4s.Length > 0 ) { mesh.uv4 = uv4s; }
            if ( norms.Length > 0 ) { mesh.normals = norms; }
            if ( colrs.Length > 0 ) { mesh.colors32 = colrs; }
            if ( tans.Length > 0 ) { mesh.tangents = tans; }
            if ( weits.Length > 0 ) { mesh.boneWeights = weits; }
            if ( _poses.Length > 0 ) { mesh.bindposes = _poses; }
            ret.divisionObjs[i] = gameObj.transform;
        }
        return ret;
    }

    //Place the exploded object in WorldRoot and return the original submesh object
    void SubMeshEndProcess ()
    {
        if ( divStates != null ) {
            for ( int i = 0; i < divStates.Length; i++ ) {
                if ( divStates[i] != null && divStates[i].divisionObjs.Length > 0 ) {
                    for ( int j = 0; j < divStates[i].divisionObjs.Length; j++ ) {
                        divStates[i].divisionObjs[j].SetParent(null);
                    }
                    divStates[i].baseObj.SetParent(divStates[i].parent);
                }
            }
        }
    }

    //Euler of rotation axis XYZ//
    public Vector3 GetEulerXYZ (Quaternion rot)
    {
        if ( rot == Quaternion.identity )
            return Vector3.zero;
        Vector3 vec = rot * Vector3.right;
        float x = vec.x;
        float y = vec.y;
        float z = vec.z;
        float zRad = 0f;
        if ( Mathf.Abs(x) > Mathf.Abs(y) ) {
            if ( x > 0.00001f ) {
                zRad = Mathf.Atan(y / x);
            } else if ( x < -0.00001f ) {
                zRad = Mathf.Atan(y / x) + 3.14159265f;
                if ( zRad > 3.14159265f )
                    zRad -= 6.2831853f;
            } else if ( y > 0.00001f ) {
                zRad = -1.5707963f;
            } else {
                zRad = -1.5707963f;
            }
        } else {
            if ( y > 0.00001f ) {
                zRad = -Mathf.Atan(x / y) + 1.5707963f;
            } else if ( y < -0.00001f ) {
                zRad = -Mathf.Atan(x / y) - 1.5707963f;
            }
        }

        x = x * Mathf.Cos(-zRad) - y * Mathf.Sin(-zRad);

        float yRad = 0f;
        if ( Mathf.Abs(x) > Mathf.Abs(z) ) {
            if ( x > 0.00001f ) {
                yRad = -Mathf.Atan(z / x);
            } else if ( x < -0.00001f ) {
                yRad = Mathf.Atan(z / x) + 3.14159265f;
                if ( yRad > 3.14159265f )
                    yRad -= 6.2831853f;
            }
        } else {
            if ( z > 0.00001f ) {
                yRad = Mathf.Atan(x / z) - 1.5707963f;
            } else if ( z < -0.00001f ) {
                yRad = Mathf.Atan(x / z) + 1.5707963f;
            }
        }

        float yAng = yRad * 57.2957795f;
        float zAng = zRad * 57.2957795f;
        Quaternion xRot = Quaternion.Inverse(Quaternion.Euler(0, 0, zAng) * Quaternion.Euler(0, yAng, 0)) * rot;
        Vector3 xEul = xRot.eulerAngles;
        float xAng = xEul.x;
        if ( Mathf.Abs(Mathf.DeltaAngle(xEul.y, 0)) > 136 && Mathf.Abs(Mathf.DeltaAngle(xEul.z, 0)) > 136 )
            xAng = xAng * -1 + 180;

        if ( xAng < -180 )
            xAng = xAng % 360 + 360;
        if ( xAng > 180 )
            xAng = xAng % 360 - 360;
        if ( yAng < -180 )
            yAng = yAng % 360 + 360;
        if ( yAng > 180 )
            yAng = yAng % 360 - 360;
        if ( zAng < -180 )
            zAng = zAng % 360 + 360;
        if ( zAng > 180 )
            zAng = zAng % 360 - 360;

        return new Vector3(xAng, yAng, zAng);
    }

    //Extract clip from Animator or Animation on Root
    void GetAnimationClip ()
    {
        clip = null;
        var animator = exportObject.GetComponent<Animator>();
        if ( animator != null ) {
            //var info = animator.GetCurrentAnimatorStateInfo(0);
            if ( animator.runtimeAnimatorController != null ) {
                var clips = animator.runtimeAnimatorController.animationClips;
                if ( clips.Length > 0 ) {
                    clip = clips[0];
                }
            }
            return;
        }
        var animation = exportObject.GetComponent<Animation>();
        if ( animation != null ) {
            clip = animation.clip;
        }
    }

    void ExportTexture ()
    {
        if ( !exportObject ) { return; }
        if ( filePath == "" ) { filePath = exportObject.name; }
        var directory = System.IO.Path.GetDirectoryName(filePath);
        if ( directory.Length != 0 ) { directory += "/"; }
        var rends = exportObject.GetComponents<Renderer>();
        for ( int i = 0; i < rends.Length; i++ ) {
            var mats = rends[i].sharedMaterials;
            for ( int j = 0; j < mats.Length; j++ ) {
                if ( mats[i].HasProperty("_MainTex") ) {
                    Texture2D tex = (Texture2D)mats[i].GetTexture("_MainTex");
                    if ( tex != null ) {
                        var path = "Assets/" + System.IO.Path.GetDirectoryName(filePath) + tex.name + ".png";
                        Texture2D tex2 = TextreClone(tex);
                        Debug.Log(path);
                        System.IO.File.WriteAllBytes(path, tex2.EncodeToPNG());
                    }
                }
                if ( mats[i].HasProperty("_DetailTex") ) {
                    Texture2D tex = (Texture2D)mats[i].GetTexture("_DetailTex");
                    if ( tex != null ) {
                        var path = "Assets/" + System.IO.Path.GetDirectoryName(filePath) + tex.name + ".png";
                        Texture2D tex2 = TextreClone(tex);
                        System.IO.File.WriteAllBytes(path, tex2.EncodeToPNG());
                    }
                }
                if ( mats[i].HasProperty("_Texture") ) {
                    Texture2D tex = (Texture2D)mats[i].GetTexture("_Texture");
                    if ( tex != null ) {
                        var path = "Assets/" + System.IO.Path.GetDirectoryName(filePath) + tex.name + ".png";
                        Texture2D tex2 = TextreClone(tex);
                        System.IO.File.WriteAllBytes(path, tex2.EncodeToPNG());
                    }
                }
            }
        }
    }

    Texture2D TextreClone (Texture2D tex)
    {
        var temp = RenderTexture.GetTemporary(tex.width, tex.height);
        Graphics.Blit(tex, temp);
        var copy = new Texture2D(tex.width, tex.height);
        copy.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
        copy.Apply();
        RenderTexture.ReleaseTemporary(temp);
        return copy;
    }

    void Export (string path, string str)
    {
        AssetDatabase.DeleteAsset(path);
        StreamWriter sw;
        sw = new StreamWriter(path, true);
        sw.Write(str);
        sw.Close();
    }
}
#endif
3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4