Unity export fbx in Edit Mode

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