void GenerateBoneInstanceMeshAndTexture(GameObject _targetFBX, AnimationClip[] _clips, string exposeBones)
        {
            if (!UEAsset.SelectDirectory(_targetFBX, out string savePath, out string meshName))
            {
                Debug.LogWarning("Invalid Folder Selected");
                return;
            }
            GameObject          _instantiatedObj     = GameObject.Instantiate(m_TargetPrefab);
            SkinnedMeshRenderer _skinnedMeshRenderer = _instantiatedObj.GetComponentInChildren <SkinnedMeshRenderer>();

            try
            {
                Matrix4x4[] bindPoses = _skinnedMeshRenderer.sharedMesh.bindposes;
                Transform[] bones     = _skinnedMeshRenderer.bones;
                #region Record Expose Bone
                List <AnimationInstanceExposeBone> exposeBoneParam = new List <AnimationInstanceExposeBone>();
                if (exposeBones != "")
                {
                    Transform[] activeTransforms = _instantiatedObj.GetComponentsInChildren <Transform>();
                    for (int i = 0; i < activeTransforms.Length; i++)
                    {
                        if (!System.Text.RegularExpressions.Regex.Match(activeTransforms[i].name, exposeBones).Success)
                        {
                            continue;
                        }
                        int       relativeBoneIndex = -1;
                        Transform relativeBone      = activeTransforms[i];
                        while (relativeBone != null)
                        {
                            relativeBoneIndex = System.Array.FindIndex(bones, p => p == relativeBone);
                            if (relativeBoneIndex != -1)
                            {
                                break;
                            }
                            relativeBone = relativeBone.parent;
                        }
                        if (relativeBoneIndex == -1)
                        {
                            continue;
                        }

                        Matrix4x4 rootWorldToLocal = _skinnedMeshRenderer.transform.worldToLocalMatrix;

                        exposeBoneParam.Add(new AnimationInstanceExposeBone()
                        {
                            m_BoneIndex = relativeBoneIndex,
                            m_BoneName  = activeTransforms[i].name,
                            m_Position  = rootWorldToLocal.MultiplyPoint(activeTransforms[i].transform.position),
                            m_Direction = rootWorldToLocal.MultiplyVector(activeTransforms[i].transform.forward)
                        });
                    }
                }
                #endregion
                #region Bake Animation Atlas
                int boneCount  = _skinnedMeshRenderer.sharedMesh.bindposes.Length;
                int totalWdith = boneCount * 3;
                int totalFrame = GetInstanceParams(_clips, out AnimationInstanceParam[] instanceParams);
                List <AnimationInstanceEvent> instanceEvents = new List <AnimationInstanceEvent>();

                Texture2D atlasTexture = new Texture2D(Mathf.NextPowerOfTwo(totalWdith), Mathf.NextPowerOfTwo(totalFrame), TextureFormat.RGBAHalf, false);
                atlasTexture.filterMode = FilterMode.Point;
                atlasTexture.wrapModeU  = TextureWrapMode.Clamp;
                atlasTexture.wrapModeV  = TextureWrapMode.Repeat;
                UBoundsChecker.Begin();
                for (int i = 0; i < _clips.Length; i++)
                {
                    AnimationClip clip       = _clips[i];
                    float         length     = clip.length;
                    float         frameRate  = clip.frameRate;
                    int           frameCount = (int)(length * frameRate);
                    int           startFrame = instanceParams[i].m_FrameBegin;
                    for (int j = 0; j < frameCount; j++)
                    {
                        clip.SampleAnimation(_instantiatedObj, length * j / frameCount);
                        for (int k = 0; k < boneCount; k++)
                        {
                            Matrix4x4 curFrameBoneMatrix = _skinnedMeshRenderer.transform.worldToLocalMatrix * bones[k].localToWorldMatrix * bindPoses[k];
                            atlasTexture.SetPixel(k * 3, startFrame + j, UColor.VectorToColor(curFrameBoneMatrix.GetRow(0)));
                            atlasTexture.SetPixel(k * 3 + 1, startFrame + j, UColor.VectorToColor(curFrameBoneMatrix.GetRow(1)));
                            atlasTexture.SetPixel(k * 3 + 2, startFrame + j, UColor.VectorToColor(curFrameBoneMatrix.GetRow(2)));
                        }

                        Mesh boundsCheckMesh = new Mesh();
                        _skinnedMeshRenderer.BakeMesh(boundsCheckMesh);
                        Vector3[] verticies = boundsCheckMesh.vertices;
                        for (int k = 0; k < verticies.Length; k++)
                        {
                            UBoundsChecker.CheckBounds(verticies[k].Divide(_skinnedMeshRenderer.transform.localScale));
                        }

                        boundsCheckMesh.Clear();
                    }
                }
                atlasTexture.Apply();
                #endregion
                #region Bake Mesh
                Mesh         instanceMesh = _skinnedMeshRenderer.sharedMesh.Copy();
                BoneWeight[] boneWeights  = instanceMesh.boneWeights;
                Vector4[]    uv1          = new Vector4[boneWeights.Length];
                Vector4[]    uv2          = new Vector4[boneWeights.Length];
                for (int i = 0; i < boneWeights.Length; i++)
                {
                    uv1[i] = new Vector4(boneWeights[i].boneIndex0, boneWeights[i].boneIndex1, boneWeights[i].boneIndex2, boneWeights[i].boneIndex3);
                    uv2[i] = new Vector4(boneWeights[i].weight0, boneWeights[i].weight1, boneWeights[i].weight2, boneWeights[i].weight3);
                }
                instanceMesh.SetUVs(1, uv1);
                instanceMesh.SetUVs(2, uv2);
                instanceMesh.boneWeights = null;
                instanceMesh.bindposes   = null;
                instanceMesh.bounds      = UBoundsChecker.CalculateBounds();
                #endregion
                DestroyImmediate(_instantiatedObj);

                GPUAnimationData data = ScriptableObject.CreateInstance <GPUAnimationData>();
                data.m_Animations  = instanceParams;
                data.m_ExposeBones = exposeBoneParam.ToArray();

                data = UEAsset.CreateAssetCombination(savePath + meshName + "_GPU_Bone.asset", data, new KeyValuePair <string, Object>(meshName + "_AnimationAtlas", atlasTexture), new KeyValuePair <string, Object>(meshName + "_InstanceMesh", instanceMesh));
                Object[] assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(data));
                foreach (var asset in assets)
                {
                    Texture2D atlas = asset as Texture2D;
                    Mesh      mesh  = asset as Mesh;
                    if (atlas)
                    {
                        data.m_AnimationAtlas = atlas;
                    }
                    if (mesh)
                    {
                        data.m_InstancedMesh = mesh;
                    }
                }
                AssetDatabase.SaveAssets();
            }
            catch (System.Exception e)
            {
                Debug.LogError("Generate Failed:" + e.Message);
                DestroyImmediate(_instantiatedObj);
            }
        }
        void GenerateVertexTexture(GameObject _targetFBX, AnimationClip[] _clips)
        {
            if (!UEAsset.SelectDirectory(_targetFBX, out string savePath, out string meshName))
            {
                Debug.LogWarning("Invalid Folder Selected");
                return;
            }
            GameObject          instantiatedObj     = GameObject.Instantiate(m_TargetPrefab);
            SkinnedMeshRenderer skinnedMeshRenderer = instantiatedObj.GetComponentInChildren <SkinnedMeshRenderer>();

            #region Bake Animation Atlas
            int vertexCount       = skinnedMeshRenderer.sharedMesh.vertexCount;
            int totalVertexRecord = vertexCount * 2;
            int totalFrame        = GetInstanceParams(_clips, out AnimationInstanceParam[] instanceParams);

            Texture2D atlasTexture = new Texture2D(Mathf.NextPowerOfTwo(totalVertexRecord), Mathf.NextPowerOfTwo(totalFrame), TextureFormat.RGBAHalf, false);
            atlasTexture.filterMode = FilterMode.Point;
            atlasTexture.wrapModeU  = TextureWrapMode.Clamp;
            atlasTexture.wrapModeV  = TextureWrapMode.Repeat;
            UBoundsChecker.Begin();
            for (int i = 0; i < _clips.Length; i++)
            {
                AnimationClip clip           = _clips[i];
                Mesh          vertexBakeMesh = new Mesh();
                float         length         = clip.length;
                float         frameRate      = clip.frameRate;
                int           frameCount     = (int)(length * frameRate);
                int           startFrame     = instanceParams[i].m_FrameBegin;
                for (int j = 0; j < frameCount; j++)
                {
                    clip.SampleAnimation(instantiatedObj, length * j / frameCount);
                    skinnedMeshRenderer.BakeMesh(vertexBakeMesh);
                    Vector3[] vertices = vertexBakeMesh.vertices;
                    Vector3[] normals  = vertexBakeMesh.normals;
                    for (int k = 0; k < vertexCount; k++)
                    {
                        UBoundsChecker.CheckBounds(vertices[k]);
                        atlasTexture.SetPixel(k * 2, startFrame + j, UColor.VectorToColor(vertices[k]));
                        atlasTexture.SetPixel(k * 2 + 1, startFrame + j, UColor.VectorToColor(normals[k]));
                    }
                }
                vertexBakeMesh.Clear();
            }
            atlasTexture.Apply();
            #endregion

            #region Bake Mesh
            Mesh instanceMesh = skinnedMeshRenderer.sharedMesh.Copy();
            instanceMesh.normals     = null;
            instanceMesh.tangents    = null;
            instanceMesh.boneWeights = null;
            instanceMesh.bindposes   = null;
            instanceMesh.bounds      = UBoundsChecker.CalculateBounds();
            #endregion
            DestroyImmediate(instantiatedObj);

            GPUAnimationData data = ScriptableObject.CreateInstance <GPUAnimationData>();
            data.m_Animations = instanceParams;
            data = UEAsset.CreateAssetCombination(savePath + meshName + "_GPU_Vertex.asset", data, new KeyValuePair <string, Object>(meshName + "_AnimationAtlas", atlasTexture), new KeyValuePair <string, Object>(meshName + "_InstanceMesh", instanceMesh));
            Object[] assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(data));
            foreach (var asset in assets)
            {
                Texture2D atlas = asset as Texture2D;
                Mesh      mesh  = asset as Mesh;
                if (atlas)
                {
                    data.m_AnimationAtlas = atlas;
                }
                if (mesh)
                {
                    data.m_InstancedMesh = mesh;
                }
            }
            AssetDatabase.SaveAssets();
        }