private static void RecursiveBones(Transform root, List <SkinBone> bones, int depth)
    {
        for (int i = 0; i < root.childCount; ++i)
        {
            Transform transform = root.GetChild(i);

            bool isBone = true;
            foreach (var comp in transform.GetComponents <Component>())
            {
                if (!(comp is Transform))
                {
                    isBone = false;
                    break;
                }
            }

            if (isBone)
            {
                SkinBone bone = new SkinBone();
                bone.depth     = depth;
                bone.transform = transform;
                bones.Add(bone);
                RecursiveBones(transform, bones, depth + 1);
            }
        }
    }
    private static List <SkinBone> GenerateBones(string fbxfile)
    {
        GameObject gameObject = AssetDatabase.LoadAssetAtPath <GameObject>(fbxfile);

        List <SkinBone> bones = new List <SkinBone>();

        RecursiveBones(gameObject.transform, bones, 0);

        bones.Sort((SkinBone a, SkinBone b) => {
            if (a.depth < b.depth)
            {
                return(-1);
            }
            else if (a.depth == b.depth)
            {
                return(0);
            }
            else
            {
                return(1);
            }
        });

        Dictionary <string, int> indexDict = new Dictionary <string, int>();

        for (int i = 0; i < bones.Count; ++i)
        {
            SkinBone bone = bones[i];
            indexDict[bone.transform.name] = i;

            bone.index = i;

            int parentIndex = -1;
            if (bone.transform.parent != null && indexDict.TryGetValue(bone.transform.parent.name, out parentIndex))
            {
                bone.parent = parentIndex;
            }
            else
            {
                bone.parent = -1;
            }
        }

        return(bones);
    }
    private static void GenerateClip(List <SkinBone> bones, AnimationClip clip, string file)
    {
        EditorCurveBinding[] curveDatas = AnimationUtility.GetCurveBindings(clip);

        float        frequency   = 1.0f / 30.0f;
        int          keyframeLen = (int)Mathf.Ceil(clip.length / frequency) + 1;
        List <float> times       = new List <float>();

        for (int i = 0; i < keyframeLen; ++i)
        {
            times.Add(i * frequency >= clip.length ? clip.length : i * frequency);
        }

        SkinAnimationClip newClip = ScriptableObject.CreateInstance <SkinAnimationClip>();

        newClip.frequency = frequency;
        newClip.times     = times.ToArray();
        newClip.datas     = new float[bones.Count * keyframeLen * SkinAnimationClip.STRIDE];
        newClip.length    = clip.length;
        newClip.animName  = clip.name;
        newClip.nodeCount = bones.Count;

        Dictionary <string, int> boneIndexMap = new Dictionary <string, int>();

        for (int i = 0; i < bones.Count; ++i)
        {
            SkinBone   bone = bones[i];
            Vector3    pos  = bone.transform.localPosition;
            Quaternion rot  = bone.transform.localRotation;

            int frameIndex = i * keyframeLen * SkinAnimationClip.STRIDE;
            for (int j = 0; j < keyframeLen; ++j)
            {
                int curveIndex = j * SkinAnimationClip.STRIDE;
                newClip.datas[frameIndex + curveIndex + 0] = pos.x;
                newClip.datas[frameIndex + curveIndex + 1] = pos.y;
                newClip.datas[frameIndex + curveIndex + 2] = pos.z;

                newClip.datas[frameIndex + curveIndex + 3] = rot.x;
                newClip.datas[frameIndex + curveIndex + 4] = rot.y;
                newClip.datas[frameIndex + curveIndex + 5] = rot.z;
                newClip.datas[frameIndex + curveIndex + 6] = rot.w;
            }

            boneIndexMap[bone.transform.name] = i;
        }

        float[] values = new float[keyframeLen];

        for (int i = 0; i < curveDatas.Length; ++i)
        {
            EditorCurveBinding binding = curveDatas[i];
            string             name    = binding.path.Substring(binding.path.LastIndexOf('/') + 1);
            AnimationCurve     curve   = AnimationUtility.GetEditorCurve(clip, binding);

            int offset = -1;
            switch (binding.propertyName)
            {
            case "m_LocalPosition.x": offset = 0; break;

            case "m_LocalPosition.y": offset = 1; break;

            case "m_LocalPosition.z": offset = 2; break;

            case "m_LocalRotation.x": offset = 3; break;

            case "m_LocalRotation.y": offset = 4; break;

            case "m_LocalRotation.z": offset = 5; break;

            case "m_LocalRotation.w": offset = 6; break;
            }

            if (offset == -1)
            {
                continue;
            }

            if (!boneIndexMap.ContainsKey(name))
            {
                continue;
            }

            for (int j = 0; j < keyframeLen; ++j)
            {
                values[j] = curve.Evaluate(times[j]);
            }

            int frameIndex = boneIndexMap[name] * keyframeLen * SkinAnimationClip.STRIDE;
            for (int j = 0; j < keyframeLen; ++j)
            {
                int curveIndex = j * SkinAnimationClip.STRIDE;
                newClip.datas[frameIndex + curveIndex + offset] = values[j];
            }
        }

        string basePath = Path.GetDirectoryName(file) + "/" + Path.GetFileNameWithoutExtension(file);

        string clipPath = basePath + clip.name + ".anim.asset";

        AssetDatabase.CreateAsset(newClip, clipPath);

        AnimationClip  emptyClip  = new AnimationClip();
        AnimationCurve emptyCurve = new AnimationCurve();

        emptyCurve.AddKey(new Keyframe(0.0f, 0.0f));
        emptyCurve.AddKey(new Keyframe(clip.length, clip.length));
        emptyClip.SetCurve("", typeof(SkinFloat), "value", emptyCurve);
        AssetDatabase.CreateAsset(emptyClip, basePath + clip.name + ".anim");
    }
Пример #4
0
    // 解析fbx
    public void AnalysisFbx(GameObject pFbxInstance, Quaternion quaternionOffset)
    {
        Clear();
        float      frameInterval = 1.0f / IGGUtil.framerate;
        GameObject go            = GameObject.Instantiate(pFbxInstance) as GameObject;

        if (!go)
        {
            Debug.Log("pFbxInstance is null!");
            return;
        }
        this.m_ActorName = go.name;

        Transform baseTransform = go.transform;

        Animation Ani = go.GetComponentInChildren <Animation>();

        if (!Ani)
        {
            Debug.Log("Target game object has no Animation component!");
            return;
        }

        int totalframe = 0;

        foreach (AnimationState state in Ani)
        {
            AniMeshClip clip = new AniMeshClip();
            clip.clipName   = state.clip.name;
            clip.clip       = state.clip;
            clip.StartFrame = totalframe;
            float frames = state.clip.length / frameInterval + 1;
            clip.FrameCount = (int)frames;
            clip.EndFrame   = clip.StartFrame + clip.FrameCount - 1;
            totalframe     += clip.FrameCount;
            m_AniMeshClip.Add(clip);
        }

        SkinnedMeshRenderer renderArray = go.GetComponentInChildren <SkinnedMeshRenderer>();

        m_Mesh       = new SubMesh();
        m_Mesh.bones = renderArray.bones.Length;
        m_SkinBones  = new List <SkinBone>();
        for (int i = 0; i < renderArray.bones.Length; i++)
        {
            SkinBone skin = new SkinBone();
            skin.transform = renderArray.bones[i];
            skin.bindpose  = renderArray.sharedMesh.bindposes[i];
            // 获取父骨骼节点。
            skin.parentBoneIndex = System.Array.IndexOf(renderArray.bones, skin.transform.parent);
            if (skin.transform.childCount > 0)
            {
                skin.childrenBonesIndices = new int[skin.transform.childCount];
                for (int k = 0; k < skin.transform.childCount; k++)
                {
                    skin.childrenBonesIndices[k] = System.Array.IndexOf(renderArray.bones, skin.transform.GetChild(k));
                }
            }
            m_SkinBones.Add(skin);
        }
        //
        m_Mesh.m_vertices   = renderArray.sharedMesh.vertices;
        m_Mesh.m_UV         = renderArray.sharedMesh.uv;
        m_Mesh.m_Triangles  = renderArray.sharedMesh.triangles;
        m_Mesh.m_BoneWeight = renderArray.sharedMesh.boneWeights;
        // 解析 ani mesh 数据
        for (int i = 0; i < m_AniMeshClip.Count; i++)
        {
            // Set the animation clip to export
            AnimationClip clip = m_AniMeshClip[i].clip;
            if (null == clip)
            {
                continue;
            }

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

            float        clipLength = clip.length;
            List <float> frameTimes = GetFrameTimes(clipLength, frameInterval);

            foreach (float time in frameTimes)
            {
                state.time = time;

                Ani.Play();
                Ani.Sample();
                Mesh bakeMesh = null;

                if (quaternionOffset != Quaternion.identity)
                {
                    Matrix4x4 matrix = new Matrix4x4();
                    matrix.SetTRS(Vector2.zero, quaternionOffset, Vector3.one);
                    bakeMesh = BakeFrameAfterMatrixTransform(renderArray, matrix);
                }
                else
                {
                    bakeMesh = new Mesh();
                    renderArray.BakeMesh(bakeMesh);
                }
                m_Mesh.m_AniMesh.Add(bakeMesh.vertices);

                // 骨骼数据
                Matrix4x4[] boneFrame = new Matrix4x4[m_SkinBones.Count];
                for (int k = 0; k < m_SkinBones.Count; k++)
                {
                    SkinBone CurBone = m_SkinBones [k];
                    boneFrame [k] = CurBone.bindpose;
                    do
                    {
                        Matrix4x4 mat = Matrix4x4.TRS(CurBone.transform.localPosition, CurBone.transform.localRotation, CurBone.transform.localScale);
                        //Matrix4x4 mat = Matrix4x4.TRS(CurBone.transform.localPosition, CurBone.transform.localRotation, Vector3.one);
                        boneFrame [k] = mat * boneFrame [k];
                        if (CurBone.parentBoneIndex == -1)
                        {
                            break;
                        }
                        else
                        {
                            CurBone = m_SkinBones[CurBone.parentBoneIndex];
                        }
                    }while(true);
                }

                m_Mesh.m_AniBone.Add(boneFrame);


                bakeMesh.Clear();
                Object.DestroyImmediate(bakeMesh);
                Ani.Stop();
            }
        }
        GameObject.DestroyImmediate(go);
    }