private static bool CheckExport(GameObject prefab, MeshAnimationExportParameter param)
        {
            if (string.IsNullOrEmpty(param.outputFilePath.Trim()))
            {
                EditorUtility.DisplayDialog("Missing Output File", "Please set a output file.", "OK");
                return(false);
            }

            if (prefab == null)
            {
                EditorUtility.DisplayDialog("Missing Base FBX", "Please specify a base FBX.", "OK");
                return(false);
            }
            if (PrefabUtility.GetPrefabParent(prefab) == null)
            {
                EditorUtility.DisplayDialog("GameObject must be an instance of a ModelPrefab", "Please select a valid GameObject", "OK");
            }

            bool clipsNotSet = true;

            for (int i = 0; i < param.animationClips.Length; i++)
            {
                if (param.animationClips[i] != null && string.IsNullOrEmpty(param.animationClipNames[i].Trim()))
                {
                    EditorUtility.DisplayDialog("Missing Animation Name", "Please specify a name for all animation files.", "OK");
                    return(false);
                }

                if (param.animationClips[i] != null)
                {
                    clipsNotSet = false;
                }
            }

            if (clipsNotSet)
            {
                EditorUtility.DisplayDialog("Missing Animation", "Please specify at least one animation file.", "OK");
                return(false);
            }

            for (int i = 0; i < param.boneTransforms.Length; i++)
            {
                if (param.boneTransforms[i] != null && string.IsNullOrEmpty(param.boneNames[i].Trim()))
                {
                    EditorUtility.DisplayDialog("Missing Bone Name", "Please specify a name for all bone transforms.", "OK");
                    return(false);
                }
            }

            return(true);
        }
        public static void ExportCombinedTexture(GameObject prefab, MeshAnimationExportParameter param, System.Action <float> pProgressBarUpdater = null)
        {
            if (!CheckExport(prefab, param))
            {
                return;
            }

            AnimationClip[] animationClips     = param.animationClips;
            string[]        animationClipNames = param.animationClipNames;
            Transform[]     boneTransforms     = param.boneTransforms;
            string[]        boneNames          = param.boneNames;
            GameObject      model         = prefab;
            Transform       rootTransform = prefab.transform;
            Animation       animation     = model.GetComponentInChildren <Animation>();

            SkinnedMeshRenderer[] meshRenders = model.GetComponentsInChildren <SkinnedMeshRenderer>();
            int meshRenderCount = meshRenders.Length;

            Mesh[] exportMeshs = new Mesh[meshRenderCount];
            for (int i = 0; i < meshRenderCount; ++i)
            {
                exportMeshs[i] = meshRenders[i].sharedMesh;
            }

            float frameInterval = 1.0f / param.framerate;


            //清空并重建目标目录
            if (System.IO.Directory.Exists(param.outputFilePath))
            {
                System.IO.Directory.Delete(param.outputFilePath, true);
            }
            System.IO.Directory.CreateDirectory(param.outputFilePath);

            int totalFrameCount = 0;

            totalFrameCount = 1 + meshRenderCount;

            int totalAniClipFrameCount = 0;

            foreach (var clip in animationClips)
            {
                totalAniClipFrameCount += (int)(clip.length / frameInterval) + 1;
            }

            // txture height
            // 1 + mesh count + all clip frame * mesh count
            totalFrameCount += totalAniClipFrameCount * meshRenderCount;

            int[] vertexCount    = new int[meshRenderCount];
            int   maxVertexCount = 0;

            for (int i = 0; i < meshRenderCount; ++i)
            {
                int count = exportMeshs[i].vertexCount;
                vertexCount[i] = count;
                if (count > maxVertexCount)
                {
                    maxVertexCount = count;
                }
            }

            // 行 : 每帧顶点数据
            // 列 : 1 + mesh count + all clip frame * mesh count
            Texture2D combinedTex = new Texture2D(maxVertexCount, totalFrameCount, TextureFormat.RGBAHalf, false);



            Vector3[][] defaultAnimationInfos = new Vector3[meshRenderCount][];
            for (int i = 0; i < meshRenderCount; i++)
            {
                defaultAnimationInfos[i] = new Vector3[8];
                for (int j = 0; j < 8; j++)
                {
                    defaultAnimationInfos[i][j] = new Vector3(0, 0, 0);
                }
            }

            string[]      defaultAnimationArray = new string[] { "Attack1", "Attack2", "Dead", "Hit", "Run", "Skill1", "Wait1", "Wait2" };
            List <string> defaultAnimationList  = new List <string>();

            for (int i = 0; i < defaultAnimationArray.Length; i++)
            {
                defaultAnimationList.Add(defaultAnimationArray[i].ToUpper());
            }

            // (0, 0)点存储   render的个数 和 最大顶点数
            combinedTex.SetPixel(0, 0, new Color(meshRenderCount, maxVertexCount, 0));

            int countData = 1 + meshRenderCount;

            for (int i = 0; i < meshRenderCount; ++i)
            {
                combinedTex.SetPixel(i + 1, 0, new Color(vertexCount[i], 0, 0));
                countData += exportMeshs[i].uv.Length / 2 + exportMeshs[i].triangles.Length / 3;
            }

            // 配置纹理 fps 、 uv count、uv、triangle count、 triangle
            int       texSize    = 64;
            int       texHeight  = (int)Mathf.Ceil(countData / (float)texSize);
            int       texWidth   = texSize;
            Texture2D cfgTexture = new Texture2D(texWidth, texHeight, TextureFormat.RGBAHalf, false);

            Color[] colors       = new Color[texWidth * texHeight];
            int     cfgDataIndex = 0;

            colors[cfgDataIndex++] = new Color(meshRenderCount, 0, 0);
            for (int i = 0; i < meshRenderCount; ++i)
            {
                colors[cfgDataIndex++] = new Color(param.framerate, exportMeshs[i].uv.Length, exportMeshs[i].triangles.Length);
            }

            int frame = 1 + meshRenderCount;

            for (int subMeshCount = 0; subMeshCount < meshRenderCount; ++subMeshCount)
            {
                for (int i = 0; i < param.clipCount; ++i)
                {
                    MeshAnimationBoneGroup boneGroup = new MeshAnimationBoneGroup(param.boneNames.ToList());
                    AnimationClip          clip      = param.animationClips[i];

                    if (null == clip)
                    {
                        continue;
                    }

                    int    infoIndex = -1;
                    string clipName  = clip.name;
                    if (clipName.Equals("walk"))
                    {
                        clipName = "Hit";
                    }
                    else if (clipName.Equals("cut"))
                    {
                        clipName = "Skill1";
                    }
                    else if (clipName.Equals("Victory"))
                    {
                        clipName = "Dead";
                    }

                    string upperName = clipName.ToUpper();
                    if (defaultAnimationList.Contains(upperName))
                    {
                        infoIndex = defaultAnimationList.IndexOf(upperName);
                        defaultAnimationInfos[subMeshCount][infoIndex].x = 1;
                    }

                    animation.AddClip(clip, clip.name);
                    animation.clip = clip;
                    AnimationState state = animation[clip.name];
                    state.enabled = true;
                    state.weight  = 1;

                    float clipLength = clip.length;

                    List <float> frameTimes = GetFrameTimes(clipLength, frameInterval);
                    try
                    {
                        defaultAnimationInfos[subMeshCount][infoIndex].y = frame;
                    }
                    catch
                    {
                        Debug.LogError(defaultAnimationInfos.Length + "," + defaultAnimationInfos.LongLength + "," + subMeshCount + "," + infoIndex);
                    }
                    foreach (float time in frameTimes)
                    {
                        state.time = time;

                        animation.Play();
                        animation.Sample();

                        // Grab the position and rotation for each bone at the current frame
                        for (int k = 0; k < param.boneTransforms.Length; k++)
                        {
                            string name = param.boneNames[k];

                            Vector3    pos = rootTransform.InverseTransformPoint(param.boneTransforms[k].position);
                            Quaternion rot = param.boneTransforms[k].rotation * Quaternion.Inverse(rootTransform.rotation);

                            boneGroup.boneInfos[name].positions.Add(pos);
                            boneGroup.boneInfos[name].rotations.Add(rot);
                        }

                        Mesh bakeMesh = null;

                        if (param.quaternionOffset != Quaternion.identity)
                        {
                            Matrix4x4 matrix = new Matrix4x4();
                            matrix.SetTRS(Vector2.zero, param.quaternionOffset, Vector3.one);
                            bakeMesh = BakeFrameAfterMatrixTransform(meshRenders[subMeshCount], matrix);
                        }
                        else
                        {
                            bakeMesh = new Mesh();
                            meshRenders[subMeshCount].BakeMesh(bakeMesh);
                        }

                        for (int k = 0; k < bakeMesh.vertexCount; k++)
                        {
                            Vector3 vertex = bakeMesh.vertices[k];
                            combinedTex.SetPixel(k, frame, new Color(vertex.x, vertex.y, vertex.z));
                        }

                        bakeMesh.Clear();
                        Object.DestroyImmediate(bakeMesh);

                        frame++;

                        animation.Stop();
                    }
                    //end frame position,exclude
                    defaultAnimationInfos[subMeshCount][infoIndex].z = frame;
                }

                for (int i = 0; i < exportMeshs[subMeshCount].uv.Length / 2; i++)
                {
                    int uvIdx = i * 2;
                    colors[cfgDataIndex++] = new Color(exportMeshs[subMeshCount].uv[uvIdx].x, exportMeshs[subMeshCount].uv[uvIdx].y,
                                                       exportMeshs[subMeshCount].uv[uvIdx + 1].x, exportMeshs[subMeshCount].uv[uvIdx + 1].y);
                }
                for (int i = 0; i < exportMeshs[subMeshCount].triangles.Length / 3; i++)
                {
                    int triIdx = i * 3;
                    colors[cfgDataIndex++] = new Color(exportMeshs[subMeshCount].triangles[triIdx], exportMeshs[subMeshCount].triangles[triIdx + 1],
                                                       exportMeshs[subMeshCount].triangles[triIdx + 2]);
                }
            }

            for (int j = 0; j < meshRenderCount; j++)
            {
                for (int i = 0; i < 8; i++)
                {
                    combinedTex.SetPixel(i, j + 1, new Color(defaultAnimationInfos[j][i].x, defaultAnimationInfos[j][i].y, defaultAnimationInfos[j][i].z));
                }
            }



            combinedTex.Apply(false);

            string dataPath = param.outputFilePath + "/" + "combinedTex" + ".asset";

            AssetDatabase.CreateAsset(combinedTex, dataPath);



            cfgTexture.SetPixels(colors);
            cfgTexture.Apply();



            AssetDatabase.CreateAsset(cfgTexture, param.outputFilePath + "/" + prefab.name + ".asset");

            if (pProgressBarUpdater != null)
            {
                pProgressBarUpdater((float)param.animationClips.Length / (float)(param.animationClips.Length + 1));
            }

            //MeshAnimationProtobufHelper.SerializeObject<MeshAnimationGroupSerializable>(pSettings.outputFilePath + "/" + pFbxInstance.name + ".bytes", group);

            EditorUtility.DisplayDialog("Tip", "Mesh Animation Export Complete" + prefab.name, "OK");
            AssetDatabase.Refresh();
        }
        public void OnGUI()
        {
            windowWidth = position.width;

            eulerAngle = EditorGUILayout.Vector3Field("Rotate Angle(除了特殊需求,一般按默认值导出)", eulerAngle);
            EditorGUILayout.Space();

            /*Rect rect = new Rect(0f, 40f, 200f, 0f);
             * rect.height = EditorGUIUtility.singleLineHeight;
             *
             * EditorGUI.LabelField(rect, "Export Parameter", EditorStyles.boldLabel);
             *
             * rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing;*/
            EditorGUILayout.LabelField("Output File");

            EditorGUILayout.BeginHorizontal();
            {
                m_MeshAnimationExportParameter.outputFilePath   = "Assets/" + "Data/Units/Troop/MeshAnimation/";
                m_MeshAnimationExportParameter.outputFolderPath = Path.GetDirectoryName(m_MeshAnimationExportParameter.outputFilePath);
                string projectRelativeFilePath = GetAssetPath(m_MeshAnimationExportParameter.outputFilePath);

                EditorGUILayout.SelectableLabel(projectRelativeFilePath,
                                                EditorStyles.textField,
                                                GUILayout.Height(EditorGUIUtility.singleLineHeight));

                GUI.SetNextControlName("BrowseButton");
                if (GUILayout.Button("Browse"))
                {
                    BrowseSaveFile();
                }
            }
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            {
                EditorGUILayout.LabelField("Base FBX:", GUILayout.Width(EditorGUIUtility.labelWidth - 4));
                GameObject newPrefab = EditorGUILayout.ObjectField(m_Prefab, typeof(GameObject), true) as GameObject;

                if (newPrefab != null && newPrefab != m_Prefab)
                {
                    // error if they drag the prefab itself, since it won't have any transform data
                    if (PrefabUtility.GetPrefabParent(newPrefab) != null)
                    {
                        m_Prefab = newPrefab;
                        m_MeshAnimationExportParameter.ParsePrefab(newPrefab);
                    }
                }
            }
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space();

            #region Framerate Setting
            m_MeshAnimationExportParameter.framerate = EditorGUILayout.FloatField("Capture Framerate:", m_MeshAnimationExportParameter.framerate);
            m_MeshAnimationExportParameter.framerate = Mathf.Max(m_MeshAnimationExportParameter.framerate, 1.0f);
            #endregion

            EditorGUILayout.Space();

            #region Clip Count Setting
            m_MeshAnimationExportParameter.clipCount = EditorGUILayout.IntField("Number of Clips:", m_MeshAnimationExportParameter.clipCount);
            #endregion

            EditorGUILayout.Space();

            labelWidth = GUILayout.Width(windowWidth * 0.3f);

            #region Animation Clip Setting
            EditorGUILayout.BeginHorizontal();
            {
                EditorGUILayout.LabelField("Animation Name:", labelWidth);
                EditorGUILayout.LabelField("Animation File:", labelWidth);
                EditorGUILayout.LabelField("Frames:", GUILayout.Width(windowWidth * 0.2f));
            }
            EditorGUILayout.EndHorizontal();

            DrawAnimationArrayGui();
            #endregion

            EditorGUILayout.Space();

            #region Bone Count Setting
            m_MeshAnimationExportParameter.boneCount = EditorGUILayout.IntField("Number of Bones:", m_MeshAnimationExportParameter.boneCount);
            #endregion

            EditorGUILayout.BeginHorizontal();
            {
                EditorGUILayout.LabelField("Bone Name:", labelWidth);
                EditorGUILayout.LabelField("Bone Transform:", labelWidth);
            }
            EditorGUILayout.EndHorizontal();

            DrawBoneArrayGui();

            #region Clear and Save Buttons
            EditorGUILayout.BeginHorizontal();
            {
                GUI.SetNextControlName("ClearButton");
                if (GUILayout.Button("Clear"))
                {
                    m_MeshAnimationExportParameter = new MeshAnimationExportParameter();
                    GUI.FocusControl("ClearButton");
                }

                if (GUILayout.Button("Export"))
                {
                    //Save
                    if (eulerAngle != Vector3.zero)
                    {
                        m_MeshAnimationExportParameter.quaternionOffset = Quaternion.Euler(eulerAngle);
                    }

                    //MeshAnimationExporter.Export(fbx, exportSettings);
                    MeshAnimationExporter.ExportCombinedTexture(m_Prefab, m_MeshAnimationExportParameter);
                }
            }

            EditorGUILayout.EndHorizontal();
            #endregion
        }