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"); }
// 解析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); }