public MFABone(MFASkeletalModel model, GameObject obj, MFABone parent) { m_GameObj = obj; m_Parent = parent; MeshRenderer cmMeshRenderer = m_GameObj.GetComponent <MeshRenderer>(); if (cmMeshRenderer != null) { model.RegMesh(this); } SkinnedMeshRenderer cmSkinnedMeshRenderer = m_GameObj.GetComponent <SkinnedMeshRenderer>(); if (cmSkinnedMeshRenderer != null) { model.RegSkeletal(this); } model.RegBone(this); //添加子骨骼 int childCount = m_GameObj.transform.childCount; for (int i = 0; i < childCount; i++) { GameObject childObj = m_GameObj.transform.GetChild(i).gameObject; m_Child.Add(new MFABone(model, childObj, this)); } }
/* * List<Texture> tl = new List<Texture>(); * string[] paths = AssetDatabase.FindAssets("qibing_512red"); * foreach (var p in paths) * { * //Debug.Log(AssetDatabase.GUIDToAssetPath(p)); * var path = AssetDatabase.GUIDToAssetPath(p); * // path = path.Substring(7,path.Length-7); * Texture2D t = AssetDatabase.LoadAssetAtPath<Texture2D>(path); * * // AssetDatabase.LoadAssetAtPath<Texture>(path); * tl.Add(t); * } */ //反序列化测试 /* * { * using(MemoryStream mem = new MemoryStream( FileSystem.ReadFile(file.FullName))) * { * model.Deserialize(mem); * } * * }*/ //保存mesh并建立关联 /* * string modelFilePath = "Assets/Resources/model/@" + modelName +"/" + lodFlag + ".prefab";// modelPackPath * YQ2MFAFrames nFrames = model.GetComponent<YQ2MFAFrames>(); * for (int i = 0; i < nFrames.KeyFrames.Length;i++ ) * { * Mesh kfmesh = nFrames.KeyFrames[i]; * string meshPath = * string.Format("Assets/Resources/model/@{0}/Frames/{1}_{2:D2}.prefab", * modelName, * lodFlag, * i * ); * AssetDatabase.CreateAsset(kfmesh, meshPath); * * kfmesh = AssetDatabase.LoadAssetAtPath(meshPath, typeof(Mesh)) as Mesh; * nFrames.KeyFrames[i] = kfmesh; * } * * PrefabUtility.CreatePrefab(modelFilePath,model); * GameObject.DestroyImmediate(model); */ /// <summary> /// 从骨架动画组件生成模型对象 /// </summary> /// <returns></returns> static MFAModel FromYQ2AnimationClips(GameObject _obj, MFAAnimationExportInfo exportInfo) { var ModelClipsInfo = MFADatas.Single.ModelClips.Get(exportInfo.ModelClips); //检查剪辑帧数正确性 { foreach (var curr in ModelClipsInfo.Clips) { int fCount = -1; int eCount = -1; foreach (var curr2 in curr.FrameRanges) { if (fCount < 0) { fCount = curr2.ResFrameCount; } if (eCount < 0) { eCount = curr2.ExportFrameCount; } if (curr2.ResFrameCount != fCount) { throw new Exception("动画剪辑资源帧数不一致 " + curr.Name); } if (curr2.ExportFrameCount != eCount) { throw new Exception("动画剪辑导出帧数不一致 " + curr.Name); } } } } //YQ2ModelAnimationClip using (MFASkeletalModel skin_model = new MFASkeletalModel(_obj)) { string ckResTag = ""; //检查剪辑基本配置信息 foreach (var c1 in ModelClipsInfo.Clips) { SortedDictionary <string, string> tags = new SortedDictionary <string, string>(); foreach (var curr in c1.FrameRanges) { // if (!skin_model.HasClipInfo(curr.ResClipName)) // throw new Exception("不存在的动画剪辑 " + curr.ResClipName); if (curr.ExportFrameCount < 1) { throw new Exception(string.Format("动画剪辑{0} 导出帧数有误 ", c1.ClipName)); } if (curr.ResStartFrameIndex < 0) { throw new Exception(string.Format("动画剪辑{0} 起始帧配置错误", c1.ClipName)); } if (curr.ResEndFrameIndex - curr.ResStartFrameIndex < 1) { throw new Exception(string.Format("动画剪辑{0} 帧总数错误", c1.ClipName)); } if (tags.ContainsKey(curr.ResTag)) { throw new Exception(string.Format("动画剪辑{0} 重复的组件", c1.ClipName)); } tags.Add(curr.ResTag, curr.ResTag); } string tmpTag = ""; foreach (var curr in tags) { tmpTag += curr.Key; } if (string.IsNullOrEmpty(ckResTag)) { ckResTag = tmpTag; } else if (ckResTag != tmpTag) { throw new Exception(string.Format("动画剪辑{0} 各动作组件不一致", c1.ClipName)); } } //统计tag队列 /* * HashSet<string> tags = new HashSet<string>(); * foreach (var c1 in ModelClipsInfo.Clips) * { * foreach (var curr in c1.FrameRanges) tags.Add(curr.ResTag); * }*/ skin_model.ClearSnapshot(); //构建快照 foreach (var tag in exportInfo.Tags) { skin_model.BuildSnapshot(tag); } //过滤快照 List <MFASkeletalModel.MeshFrame> firstSnapshot = skin_model.FilterSnapshot(exportInfo.Tags); int indexCount = 0; int vertexCount = 0; //统计顶点和索引总量 foreach (MFASkeletalModel.MeshFrame mf in firstSnapshot) { Mesh mesh = mf.mesh; for (int i = 0; i < mesh.subMeshCount; i++) { indexCount += mesh.GetIndices(i).Length; } vertexCount += mesh.vertexCount; } //分配内存 int[] kfIndexs = new int[indexCount]; Vector2[] kfUV = new Vector2[vertexCount]; { int startUV = 0; int startIndex = 0; //填充uv和索引信息 foreach (MFASkeletalModel.MeshFrame mf in firstSnapshot) { Mesh mesh = mf.mesh; //填充子网数据 for (int i = 0; i < mesh.subMeshCount; i++) { int[] indexs = mesh.GetIndices(i); for (int ii = 0; ii < indexs.Length; ii++) { kfIndexs[ii + startIndex] = (ushort)(indexs[ii] + startUV); } startIndex += indexs.Length; } //填充UV数据 Array.Copy(mesh.uv, 0, kfUV, startUV, mesh.uv.Length); startUV += mesh.uv.Length; } } Dictionary <int, Mesh> KeyFramesIndexByID = new Dictionary <int, Mesh>(); //根据帧id索引的帧队列 Dictionary <long, List <KeyValuePair <Mesh, int> > > KeyFramesIndexByHash = new Dictionary <long, List <KeyValuePair <Mesh, int> > >(); //根据哈希值生成的帧队列 //GameObject reGameObject = new GameObject(); MFAModel reModel = new MFAModel(); reModel.m_Frames = new MFAFrames(); //处理关键帧和动画 foreach (var currC in ModelClipsInfo.Clips) { string _clipName = currC.ClipName; var ExportFrameCount = currC.FrameRanges[0].ExportFrameCount; var ResFrameCount = currC.FrameRanges[0].ResFrameCount; float frameRate = 0; foreach (var currClip in currC.FrameRanges) { if (skin_model.HasClipInfo(currClip.ResClipName)) { frameRate = skin_model.GetFrameRate(currClip.ResClipName); break; } } if (frameRate < 0.000001) { throw new Exception("无法正确获得帧率 " + _clipName); } MFAClip nClip = new MFAClip(); nClip.clipName = _clipName; nClip.frameDelay = ((ResFrameCount - 1) * (1.0f / frameRate)) / ExportFrameCount; nClip.KeyFrameIndexs = new int[ExportFrameCount]; reModel.m_ClipsIndexByName.Add(nClip.clipName, nClip); reModel.m_ClipsIndexByHashName.Add(nClip.clipName.GetHashCode(), nClip); for (int currFrame = 0; currFrame < ExportFrameCount; currFrame++) { skin_model.ClearSnapshot(); foreach (var currClip in currC.FrameRanges) { string skinClipName = currClip.ResClipName; float clipStartTime = currClip.ResStartFrameIndex * (1.0f / frameRate); //资源剪辑起始时间 float clipEndTime = clipStartTime + (currClip.ResFrameCount - 1) * (1.0f / frameRate); //资源剪辑终止时间 if (currClip.IsLoop) { clipEndTime -= nClip.frameDelay; } float timeBfb = (float)currFrame / (float)(ExportFrameCount - 1); float t = clipStartTime + (clipEndTime - clipStartTime) * timeBfb; //采样动画时间点的帧 skin_model.SetTime(skinClipName, t, currClip.ResTag); } List <MFASkeletalModel.MeshFrame> frameSnapshot = skin_model.FilterSnapshot(exportInfo.Tags); long hashV; Mesh kf = new Mesh(); Vector3[] kfvertexs = new Vector3[vertexCount]; { double _hashv = 0; //kf.possitionArray int startVertex = 0; //抓取当前顶点位置,并生成关键帧 foreach (MFASkeletalModel.MeshFrame mf in frameSnapshot) { Mesh mesh = mf.mesh; Vector3[] vertices = mesh.vertices; for (int vi = 0; vi < vertices.Length; vi++) { Vector3 v3 = vertices[vi]; kfvertexs[vi + startVertex] = mf.TransformMX.MultiplyPoint(v3); _hashv += v3.x; _hashv += v3.y; _hashv += v3.z; } startVertex += vertices.Length; } kf.vertices = kfvertexs; hashV = (long)_hashv; } int selectIndex = -1; if (KeyFramesIndexByHash.ContainsKey(hashV)) //哈希值存在 { //逐顶点比对 List <KeyValuePair <Mesh, int> > kfList = KeyFramesIndexByHash[hashV]; foreach (KeyValuePair <Mesh, int> currKF in kfList) { Vector3[] currKFVertices = currKF.Key.vertices; bool isLike = true; for (int i = 0; i < kfvertexs.Length; i++) { if (currKFVertices[i] != kfvertexs[i]) { isLike = false; break; } } if (isLike) { selectIndex = currKF.Value; break; } } } if (selectIndex < 0) { //生成法线信息 //填充uv kf.uv = kfUV; //填充索引 kf.triangles = kfIndexs; //加入到关键帧队列 int index = KeyFramesIndexByID.Count; KeyFramesIndexByID.Add(index, kf); if (!KeyFramesIndexByHash.ContainsKey(hashV)) { KeyFramesIndexByHash.Add(hashV, new List <KeyValuePair <Mesh, int> >()); } //加入到哈希索引 KeyFramesIndexByHash[hashV].Add(new KeyValuePair <Mesh, int>(kf, index)); //选择新生成的这个关键帧 selectIndex = index; } nClip.KeyFrameIndexs[currFrame] = selectIndex; } //end for(int currFrame = 0;currFrame<frameCount;currFrame++) } //end foreach (ModelAnimationClip currClip in clips) //填充关键帧 int keycount = KeyFramesIndexByID.Count; reModel.m_Frames.KeyFrames = new Mesh[keycount]; for (int kindex = 0; kindex < keycount; kindex++) { reModel.m_Frames.KeyFrames[kindex] = KeyFramesIndexByID[kindex]; } OptimalKeyFrames(reModel.m_Frames.KeyFrames); reModel.UpdateDefaultHashClipName(); return(reModel); } }