void StartSampleClip(short clipIdx) { _isSampling = true; if (_sampleParam != null) { _sampleParam.aniState.enabled = false; } AnimationClip clip = _clips[clipIdx]; _sampleParam = new SampleParam(); _sampleParam.clipIdx = clipIdx; _sampleParam.clip = clip; AnimationState aniState = _animation[clip.name]; aniState.enabled = true; aniState.weight = 1; aniState.normalizedTime = 0f; aniState.speed = 1f; _sampleParam.aniState = aniState; _sampleParam.frameRate = SAMPLER_FRAME_RATE; _sampleParam.frameCount = (short)(clip.length * SAMPLER_FRAME_RATE); _sampleParam.currFrameIdx = 0; GetAnimationCurves(); transform.parent = null; transform.position = Vector3.zero; transform.rotation = Quaternion.identity; transform.localScale = Vector3.one; foreach (var boneData in _allBoneDatas) { boneData.matrixes[_sampleParam.clipIdx] = new Matrix4x4[_sampleParam.frameCount]; } foreach (var jointData in _allJointDatas) { jointData.matrixes[_sampleParam.clipIdx] = new PosRot[_sampleParam.frameCount]; } _rootMotionData.matrixes[_sampleParam.clipIdx] = new PosRot[_sampleParam.frameCount]; _sampleParams.Add(_sampleParam); Debug.LogFormat("<color=yellow>Start sample clip <{0}>[{1}],length:{2},frameRate:{3},frameCount:{4}</color>", clip.name, clipIdx, clip.length, _sampleParam.frameRate, _sampleParam.frameCount); }
private void WriteToFile() { string savePath = string.Format("{0}{1}.asset", SKINNING_DATA_SAVE_DIR, transform.name); SkinningData skinningData = AssetDatabase.LoadAssetAtPath <SkinningData>(savePath); if (skinningData == null) { skinningData = ScriptableObject.CreateInstance <SkinningData>(); skinningData.name = transform.name; AssetDatabase.CreateAsset(skinningData, savePath); } skinningData.frameRate = SAMPLER_FRAME_RATE; skinningData.boneInfos = GetBoneInfos(); skinningData.clipInfos = new BakedClipInfo[_sampleParams.Count]; Vector2 texSize = CalcTextureSize(); Texture2D tex = new Texture2D((int)texSize.x, (int)texSize.y, TextureFormat.RGBAHalf, false, true); Color[] pixels = tex.GetPixels(); int pixelIdx = 0; /* * layout: Clip -> FrameIdx -> Bone,存储完某一帧内所有骨头再存下一帧,原因是同一帧内数据相互靠近可以提高显存 cache 命中率 * 简化存储可以使用 Dual Quaternion 或者只存储位移和旋转,然后在 shader 里还原(可能会耗费一定性能) */ for (int i = 0; i < _sampleParams.Count; i++) { SampleParam sampleParam = _sampleParams[i]; BakedClipInfo clipData = new BakedClipInfo(); int frameCnt = sampleParam.frameCount; clipData.name = sampleParam.clip.name; clipData.frameCount = sampleParam.frameCount; clipData.duration = sampleParam.clip.length; clipData.wrapMode = sampleParam.clip.wrapMode; clipData.localBounds = sampleParam.clip.localBounds; clipData.clipPixelOffset = pixelIdx; clipData.frameRate = skinningData.frameRate; // TODO 先临时复制一下全局帧率 clipData.curveDatas = _curveDatas[i]; skinningData.clipInfos[i] = clipData; for (int j = 0; j < frameCnt; j++) { foreach (var boneData in _allBoneDatas) { if (boneData.isJoint) { continue; } Matrix4x4 matrix = boneData.matrixes[i][j]; // 去掉第四行(0,0,0,1) //matrix.GetRow(0); pixels[pixelIdx++] = new Color(matrix.m00, matrix.m01, matrix.m02, matrix.m03); pixels[pixelIdx++] = new Color(matrix.m10, matrix.m11, matrix.m12, matrix.m13); pixels[pixelIdx++] = new Color(matrix.m20, matrix.m21, matrix.m22, matrix.m23); } } } tex.SetPixels(pixels); tex.Apply(); skinningData.width = (short)texSize.x; skinningData.height = (short)texSize.y; skinningData.bakedBoneDatas = tex.GetRawTextureData(); /* * save joints and rootMotion */ //skinningData.jointNames = _allJointDatas.Select(jointData => jointData.transform.name).ToArray(); skinningData.bakedJointDatas = new List <JointClipData>(); //new PosRot[_clips.Length][][]; skinningData.rootMotions = new List <RootMotionClipData>(); //new PosRot[_clips.Length][]; int jointCount = _allJointDatas.Count; for (int i = 0; i < _sampleParams.Count; i++) { SampleParam sampleParam = _sampleParams[i]; int frameCnt = sampleParam.frameCount; skinningData.bakedJointDatas.Add(new JointClipData()); skinningData.bakedJointDatas[i].clipName = sampleParam.clip.name; skinningData.rootMotions.Add(new RootMotionClipData()); for (int j = 0; j < frameCnt; j++) { skinningData.bakedJointDatas[i].frameData.Add(new JointFrameData()); for (int k = 0; k < jointCount; k++) { skinningData.bakedJointDatas[i].frameData[j].jointData.Add(_allJointDatas[k].matrixes[i][j]); } skinningData.rootMotions[i].data.Add(_rootMotionData.matrixes[i][j]); } } /* * save animation events */ for (int i = 0; i < _sampleParams.Count; i++) { SampleParam sampleParam = _sampleParams[i]; AnimationEvent[] aniEvents = sampleParam.clip.events; EventInfo[] events = new EventInfo[aniEvents.Length]; for (int j = 0; j < aniEvents.Length; j++) { events[j] = new EventInfo(aniEvents[j]); } skinningData.clipInfos[i].events = events; } EditorUtility.SetDirty(skinningData); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); }