public void CacheOverrideClips() { List <AnimationClip> clips = new List <AnimationClip>(); for (int i = 0; i < _controllers.Length; i++) { if (_controllers[i] != null) { foreach (AnimationClip clip in _controllers[i].animationClips) { if (clip != null && !clips.Contains(clip)) { clips.Add(clip); } } } } _overrideClips = new AnimationClipData[clips.Count]; for (int i = 0; i < _overrideClips.Length; i++) { _overrideClips[i] = new AnimationClipData() { _originalClip = clips[i], _overrideClip = GPUAnimatorOverrideController.CreateOverrideClip(clips[i]) }; } }
//[TODO-sin: 2022-3-14] Check if msKeyframeReduction is used private static Keyframe[] KeyframeReduction(Keyframe[] keys, float threshold, bool eraseFlatCurves) { AnimationClipData.Prepare(); int newCount = msKeyframeReduction(keys, keys.Length, threshold, ToByte(eraseFlatCurves)); var newKeys = new Keyframe[newCount]; if (newCount > 0) Array.Copy(keys, newKeys, newCount); return newKeys; }
public static BakedData BakeClips(GameObject animationRoot, AnimationClip[] animationClips, float framerate, LodData lods) { var skinRenderers = animationRoot.GetComponentsInChildren <SkinnedMeshRenderer>(); if (skinRenderers.Length != 1) { throw new System.ArgumentException("There must be exactly one SkinnedMeshRenderer"); } // @TODO: warning about more than one materials // Before messing about with some arbitrary game object hierarchy. // Instantiate the character, but make sure it's inactive so it doesn't trigger any unexpected systems. var wasActive = animationRoot.activeSelf; animationRoot.SetActive(false); var instance = GameObject.Instantiate(animationRoot, Vector3.zero, Quaternion.identity); animationRoot.SetActive(wasActive); instance.transform.localScale = Vector3.one; var skinRenderer = instance.GetComponentInChildren <SkinnedMeshRenderer>(); BakedData bakedData = new BakedData(); bakedData.NewMesh = CreateMesh(skinRenderer); var lod1Mesh = CreateMesh(skinRenderer, lods.Lod1Mesh); var lod2Mesh = CreateMesh(skinRenderer, lods.Lod2Mesh); var lod3Mesh = CreateMesh(skinRenderer, lods.Lod3Mesh); bakedData.lods = new LodData(lod1Mesh, lod2Mesh, lod3Mesh, lods.Lod1Distance, lods.Lod2Distance, lods.Lod3Distance); bakedData.Framerate = framerate; var sampledBoneMatrices = new List <Matrix4x4[, ]>(); int numberOfKeyFrames = 0; for (int i = 0; i < animationClips.Length; i++) { var sampledMatrix = SampleAnimationClip(instance, animationClips[i], skinRenderer, bakedData.Framerate); sampledBoneMatrices.Add(sampledMatrix); numberOfKeyFrames += sampledMatrix.GetLength(0); } int numberOfBones = sampledBoneMatrices[0].GetLength(1); var tex0 = bakedData.AnimationTextures.Animation0 = new Texture2D(numberOfKeyFrames, numberOfBones, TextureFormat.RGBAFloat, false); tex0.wrapMode = TextureWrapMode.Clamp; tex0.filterMode = FilterMode.Point; tex0.anisoLevel = 0; var tex1 = bakedData.AnimationTextures.Animation1 = new Texture2D(numberOfKeyFrames, numberOfBones, TextureFormat.RGBAFloat, false); tex1.wrapMode = TextureWrapMode.Clamp; tex1.filterMode = FilterMode.Point; tex1.anisoLevel = 0; var tex2 = bakedData.AnimationTextures.Animation2 = new Texture2D(numberOfKeyFrames, numberOfBones, TextureFormat.RGBAFloat, false); tex2.wrapMode = TextureWrapMode.Clamp; tex2.filterMode = FilterMode.Point; tex2.anisoLevel = 0; Color[] texture0Color = new Color[tex0.width * tex0.height]; Color[] texture1Color = new Color[tex0.width * tex0.height]; Color[] texture2Color = new Color[tex0.width * tex0.height]; int runningTotalNumberOfKeyframes = 0; for (int i = 0; i < sampledBoneMatrices.Count; i++) { for (int boneIndex = 0; boneIndex < sampledBoneMatrices[i].GetLength(1); boneIndex++) { //Color previousRotation = new Color(); for (int keyframeIndex = 0; keyframeIndex < sampledBoneMatrices[i].GetLength(0); keyframeIndex++) { //var rotation = GetRotation(Quaternion.LookRotation(sampledBoneMatrices[i][keyframeIndex, boneIndex].GetColumn(2), // sampledBoneMatrices[i][keyframeIndex, boneIndex].GetColumn(1))); //if (keyframeIndex != 0) //{ // if (Distance(previousRotation, rotation) > Distance(Negate(rotation), previousRotation)) // { // rotation = new Color(-rotation.r, -rotation.g, -rotation.b, -rotation.a); // } //} //var translation = GetTranslation(sampledBoneMatrices[i][keyframeIndex, boneIndex].GetColumn(3), rotation); //previousRotation = rotation; //int index = Get1DCoord(runningTotalNumberOfKeyframes + keyframeIndex, boneIndex, bakedData.TranslationTexture.width); //translations[index] = translation; //rotations[index] = rotation; int index = Get1DCoord(runningTotalNumberOfKeyframes + keyframeIndex, boneIndex, tex0.width); texture0Color[index] = sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(0); texture1Color[index] = sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(1); texture2Color[index] = sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(2); } } AnimationClipData clipData = new AnimationClipData { Clip = animationClips[i], PixelStart = runningTotalNumberOfKeyframes + 1, PixelEnd = runningTotalNumberOfKeyframes + sampledBoneMatrices[i].GetLength(0) - 1 }; if (clipData.Clip.wrapMode == WrapMode.Default) { clipData.PixelEnd -= 1; } bakedData.Animations.Add(clipData); runningTotalNumberOfKeyframes += sampledBoneMatrices[i].GetLength(0); } tex0.SetPixels(texture0Color); tex1.SetPixels(texture1Color); tex2.SetPixels(texture2Color); runningTotalNumberOfKeyframes = 0; for (int i = 0; i < sampledBoneMatrices.Count; i++) { for (int boneIndex = 0; boneIndex < sampledBoneMatrices[i].GetLength(1); boneIndex++) { for (int keyframeIndex = 0; keyframeIndex < sampledBoneMatrices[i].GetLength(0); keyframeIndex++) { //int d1_index = Get1DCoord(runningTotalNumberOfKeyframes + keyframeIndex, boneIndex, bakedData.Texture0.width); Color pixel0 = tex0.GetPixel(runningTotalNumberOfKeyframes + keyframeIndex, boneIndex); Color pixel1 = tex1.GetPixel(runningTotalNumberOfKeyframes + keyframeIndex, boneIndex); Color pixel2 = tex2.GetPixel(runningTotalNumberOfKeyframes + keyframeIndex, boneIndex); if ((Vector4)pixel0 != sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(0)) { Debug.LogError("Error at (" + (runningTotalNumberOfKeyframes + keyframeIndex) + ", " + boneIndex + ") expected " + Format(sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(0)) + " but got " + Format(pixel0)); } if ((Vector4)pixel1 != sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(1)) { Debug.LogError("Error at (" + (runningTotalNumberOfKeyframes + keyframeIndex) + ", " + boneIndex + ") expected " + Format(sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(1)) + " but got " + Format(pixel1)); } if ((Vector4)pixel2 != sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(2)) { Debug.LogError("Error at (" + (runningTotalNumberOfKeyframes + keyframeIndex) + ", " + boneIndex + ") expected " + Format(sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(2)) + " but got " + Format(pixel2)); } } } runningTotalNumberOfKeyframes += sampledBoneMatrices[i].GetLength(0); } tex0.Apply(false, true); tex1.Apply(false, true); tex2.Apply(false, true); bakedData.AnimationsDictionary = new Dictionary <string, AnimationClipData>(); foreach (var clipData in bakedData.Animations) { bakedData.AnimationsDictionary[clipData.Clip.name] = clipData; } GameObject.DestroyImmediate(instance); return(bakedData); }
public static BakedData BakeClips(SkinnedMeshRenderer originalRenderer, AnimationClip[] animationClips, LodData lods) { BakedData bakedData = new BakedData(); bakedData.NewMesh = CreateMesh(originalRenderer, lods.Scale); var lod1Mesh = CreateMesh(originalRenderer, lods.Scale, lods.Lod1Mesh); var lod2Mesh = CreateMesh(originalRenderer, lods.Scale, lods.Lod2Mesh); var lod3Mesh = CreateMesh(originalRenderer, lods.Scale, lods.Lod3Mesh); bakedData.lods = new LodData(lod1Mesh, lod2Mesh, lod3Mesh, lods.Lod1Distance, lods.Lod2Distance, lods.Lod3Distance); bakedData.Framerate = 60f; List <Matrix4x4[, ]> sampledBoneMatrices = new List <Matrix4x4[, ]>(); int numberOfKeyFrames = 0; var animationComponent = originalRenderer.GetComponentInParent <Animation>(); for (int i = 0; i < animationClips.Length; i++) { animationComponent[animationClips[i].name].enabled = false; animationComponent[animationClips[i].name].weight = 0f; } for (int i = 0; i < animationClips.Length; i++) { Debug.Log("x " + i + " " + animationClips[i].name); var sampledMatrix = SampleAnimationClip(animationClips[i], originalRenderer, bakedData.Framerate); sampledBoneMatrices.Add(sampledMatrix); numberOfKeyFrames += sampledMatrix.GetLength(0); } int numberOfBones = sampledBoneMatrices[0].GetLength(1); bakedData.Texture0 = new Texture2D(numberOfKeyFrames, numberOfBones, TextureFormat.RGBAFloat, false); bakedData.Texture0.wrapMode = TextureWrapMode.Clamp; bakedData.Texture0.filterMode = FilterMode.Point; bakedData.Texture0.anisoLevel = 0; bakedData.Texture1 = new Texture2D(numberOfKeyFrames, numberOfBones, TextureFormat.RGBAFloat, false); bakedData.Texture1.wrapMode = TextureWrapMode.Clamp; bakedData.Texture1.filterMode = FilterMode.Point; bakedData.Texture1.anisoLevel = 0; bakedData.Texture2 = new Texture2D(numberOfKeyFrames, numberOfBones, TextureFormat.RGBAFloat, false); bakedData.Texture2.wrapMode = TextureWrapMode.Clamp; bakedData.Texture2.filterMode = FilterMode.Point; bakedData.Texture2.anisoLevel = 0; Color[] texture0Color = new Color[bakedData.Texture0.width * bakedData.Texture0.height]; Color[] texture1Color = new Color[bakedData.Texture0.width * bakedData.Texture0.height]; Color[] texture2Color = new Color[bakedData.Texture0.width * bakedData.Texture0.height]; int runningTotalNumberOfKeyframes = 0; for (int i = 0; i < sampledBoneMatrices.Count; i++) { for (int boneIndex = 0; boneIndex < sampledBoneMatrices[i].GetLength(1); boneIndex++) { //Color previousRotation = new Color(); for (int keyframeIndex = 0; keyframeIndex < sampledBoneMatrices[i].GetLength(0); keyframeIndex++) { //var rotation = GetRotation(Quaternion.LookRotation(sampledBoneMatrices[i][keyframeIndex, boneIndex].GetColumn(2), // sampledBoneMatrices[i][keyframeIndex, boneIndex].GetColumn(1))); //if (keyframeIndex != 0) //{ // if (Distance(previousRotation, rotation) > Distance(Negate(rotation), previousRotation)) // { // rotation = new Color(-rotation.r, -rotation.g, -rotation.b, -rotation.a); // } //} //var translation = GetTranslation(sampledBoneMatrices[i][keyframeIndex, boneIndex].GetColumn(3), rotation); //previousRotation = rotation; //int index = Get1DCoord(runningTotalNumberOfKeyframes + keyframeIndex, boneIndex, bakedData.TranslationTexture.width); //translations[index] = translation; //rotations[index] = rotation; int index = Get1DCoord(runningTotalNumberOfKeyframes + keyframeIndex, boneIndex, bakedData.Texture0.width); texture0Color[index] = sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(0); texture1Color[index] = sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(1); texture2Color[index] = sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(2); } } AnimationClipData clipData = new AnimationClipData { Clip = animationClips[i], PixelStart = runningTotalNumberOfKeyframes + 1, PixelEnd = runningTotalNumberOfKeyframes + sampledBoneMatrices[i].GetLength(0) - 1 }; if (clipData.Clip.wrapMode == WrapMode.Default) { clipData.PixelEnd -= 1; } bakedData.Animations.Add(clipData); runningTotalNumberOfKeyframes += sampledBoneMatrices[i].GetLength(0); } bakedData.Texture0.SetPixels(texture0Color); bakedData.Texture0.Apply(false, false); bakedData.Texture1.SetPixels(texture1Color); bakedData.Texture1.Apply(false, false); bakedData.Texture2.SetPixels(texture2Color); bakedData.Texture2.Apply(false, false); runningTotalNumberOfKeyframes = 0; for (int i = 0; i < sampledBoneMatrices.Count; i++) { for (int boneIndex = 0; boneIndex < sampledBoneMatrices[i].GetLength(1); boneIndex++) { for (int keyframeIndex = 0; keyframeIndex < sampledBoneMatrices[i].GetLength(0); keyframeIndex++) { //int d1_index = Get1DCoord(runningTotalNumberOfKeyframes + keyframeIndex, boneIndex, bakedData.Texture0.width); Color pixel0 = bakedData.Texture0.GetPixel(runningTotalNumberOfKeyframes + keyframeIndex, boneIndex); Color pixel1 = bakedData.Texture1.GetPixel(runningTotalNumberOfKeyframes + keyframeIndex, boneIndex); Color pixel2 = bakedData.Texture2.GetPixel(runningTotalNumberOfKeyframes + keyframeIndex, boneIndex); if ((Vector4)pixel0 != sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(0)) { Debug.LogError("Error at (" + (runningTotalNumberOfKeyframes + keyframeIndex) + ", " + boneIndex + ") expected " + Format(sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(0)) + " but got " + Format(pixel0)); } if ((Vector4)pixel1 != sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(1)) { Debug.LogError("Error at (" + (runningTotalNumberOfKeyframes + keyframeIndex) + ", " + boneIndex + ") expected " + Format(sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(1)) + " but got " + Format(pixel1)); } if ((Vector4)pixel2 != sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(2)) { Debug.LogError("Error at (" + (runningTotalNumberOfKeyframes + keyframeIndex) + ", " + boneIndex + ") expected " + Format(sampledBoneMatrices[i][keyframeIndex, boneIndex].GetRow(2)) + " but got " + Format(pixel2)); } } } runningTotalNumberOfKeyframes += sampledBoneMatrices[i].GetLength(0); } bakedData.AnimationsDictionary = new Dictionary <string, AnimationClipData>(); foreach (var clipData in bakedData.Animations) { bakedData.AnimationsDictionary[clipData.Clip.name] = clipData; } return(bakedData); }
void OnUpdateAnimation(AnimationClip anim, AnimationClipData data) { m_log += "AnimationClip: " + anim.name + "\n"; }
/// <summary> /// Bake all animation clips to texture in format: /// [clip0[frame0[bone0[row0, row1, row0]..boneN[row0, row1, row0]]..frameM[bone0[row0, row1, row0]..boneN[row0, row1, row0]]]..clipK[.. /// </summary> /// <returns>BakedData - baked animation matrix to texture</returns> public BakedData BakeClips(float frameRate = 30f) { OnBeginBakeClips(); var bakedDataBuilder = BakedData.Bulder(1) .SetMaterial(CreateMaterial()) .SetMesh(CreateMesh()) .SetFrameRate(frameRate); var sampledBoneMatrices = SampleAnimationClips(frameRate, out var animationClips, out var numberOfKeyFrames, out var numberOfBones); // find minimum square texture size, size should be power of 2 var size = BakeryUtils.NextPowerOfTwo( (int)Math.Sqrt(numberOfBones * numberOfKeyFrames * MATRIX_ROWS_COUNT)); var texture = new Texture2D(size, size, TextureFormat.RGBAFloat, false) { wrapMode = TextureWrapMode.Clamp, filterMode = FilterMode.Point, anisoLevel = 0 }; var textureColor = new Color[texture.width * texture.height]; bakedDataBuilder.SetTexture(0, texture); bakedDataBuilder.SetBonesCount(numberOfBones); var clipOffset = 0; for (var clipIndex = 0; clipIndex < sampledBoneMatrices.Count; clipIndex++) { var framesCount = sampledBoneMatrices[clipIndex].GetLength(0); for (var keyframeIndex = 0; keyframeIndex < framesCount; keyframeIndex++) { var frameOffset = keyframeIndex * numberOfBones * MATRIX_ROWS_COUNT; for (var boneIndex = 0; boneIndex < numberOfBones; boneIndex++) { var index = clipOffset + frameOffset + boneIndex * MATRIX_ROWS_COUNT; var matrix = sampledBoneMatrices[clipIndex][keyframeIndex, boneIndex]; if ((Vector4)textureColor[index + 0] != Vector4.zero) { Debug.LogError($"Index {index + 0} not empty"); } if ((Vector4)textureColor[index + 1] != Vector4.zero) { Debug.LogError($"Index {index + 1} not empty"); } if ((Vector4)textureColor[index + 2] != Vector4.zero) { Debug.LogError($"Index {index + 2} not empty"); } textureColor[index + 0] = matrix.GetRow(0); textureColor[index + 1] = matrix.GetRow(1); textureColor[index + 2] = matrix.GetRow(2); } } var clip = animationClips[clipIndex]; var start = clipOffset; var end = clipOffset + (framesCount - 1) * MATRIX_ROWS_COUNT; var clipData = AnimationClipData.Create(clip, start, end, framesCount); bakedDataBuilder.AddClip(clipData); clipOffset += framesCount * numberOfBones * MATRIX_ROWS_COUNT; } texture.SetPixels(textureColor); texture.Apply(false, false); clipOffset = 0; for (var clipIndex = 0; clipIndex < sampledBoneMatrices.Count; clipIndex++) { var framesCount = sampledBoneMatrices[clipIndex].GetLength(0); for (var keyframeIndex = 0; keyframeIndex < framesCount; keyframeIndex++) { var frameOffset = keyframeIndex * numberOfBones * MATRIX_ROWS_COUNT; for (var boneIndex = 0; boneIndex < numberOfBones; boneIndex++) { var index = clipOffset + frameOffset + boneIndex * MATRIX_ROWS_COUNT; var matrix = sampledBoneMatrices[clipIndex][keyframeIndex, boneIndex]; var color0 = textureColor[index]; var index2D0 = BakeryUtils.To2D(index, texture.width); var pixel0 = texture.GetPixel(index2D0.x, index2D0.y); var row0 = (Color)matrix.GetRow(0); index++; var color1 = textureColor[index]; var index2D1 = BakeryUtils.To2D(index, texture.width); var pixel1 = texture.GetPixel(index2D1.x, index2D1.y); var row1 = (Color)matrix.GetRow(1); index++; var color2 = textureColor[index]; var index2D2 = BakeryUtils.To2D(index, texture.width); var pixel2 = texture.GetPixel(index2D2.x, index2D2.y); var row2 = (Color)matrix.GetRow(2); if (!Verify(pixel0, row0, color0, index2D0, clipIndex, keyframeIndex, boneIndex)) { break; } if (!Verify(pixel1, row1, color1, index2D1, clipIndex, keyframeIndex, boneIndex)) { break; } if (!Verify(pixel2, row2, color2, index2D2, clipIndex, keyframeIndex, boneIndex)) { break; } } } clipOffset += numberOfBones * framesCount * MATRIX_ROWS_COUNT; } var data = bakedDataBuilder.Build(); OnEndBakeClips(); return(data); }
// Main functioon, handles the baking of the animation public static AnimationData BakeAnimation(SkinnedMeshRenderer meshToSample) { // Create the default variables AnimationData bakedAnimData = new AnimationData(); List <Matrix4x4[, ]> boneMatrix = new List <Matrix4x4[, ]>(); int keyframes = 0; // Convert the skinned mesh to sample into a static mesh bakedAnimData.NewMesh = ConvertSkinnedMesh(meshToSample); // Get the animations from the user CG_GameManager UserAnimations = CG_GameManager.Instance; // Assign these animation clips. For this to work, the animations must be inserted into // the mesh renderers animator controller, however allows the hot swapping of animations AnimationClip[] animationClips = new AnimationClip[2]; // If the animations are found, add these to the clips if (UserAnimations.Animation1) { animationClips[0] = UserAnimations.Animation1; } if (UserAnimations.Animation2) { animationClips[1] = UserAnimations.Animation2; } // For both of the animation clips, sample their data for (int i = 0; i < animationClips.Length; i++) { Matrix4x4[,] sampledAim = SampleAnimation(animationClips[i], meshToSample); boneMatrix.Add(sampledAim); keyframes += sampledAim.GetLength(0); } // Initialise the texture data of the baked data bakedAnimData.textures = new Texture2D[3]; for (int i = 0; i < bakedAnimData.textures.Length; i++) { bakedAnimData.textures[i] = new Texture2D(keyframes, boneMatrix[0].GetLength(1), TextureFormat.RGBAFloat, false); } // Initialise the texture color data of the baked data int tCW = bakedAnimData.textures[0].width * bakedAnimData.textures[0].height; Color[] texture0Colour = new Color[tCW]; Color[] texture1Colour = new Color[tCW]; Color[] texture2Colour = new Color[tCW]; // loop through and assign this colour data int totalKeyframes = 0; for (int i = 0; i < boneMatrix.Count; i++) { for (int boneIdx = 0; boneIdx < boneMatrix[i].GetLength(1); boneIdx++) { for (int keyframeIdx = 0; keyframeIdx < boneMatrix[i].GetLength(0); keyframeIdx++) { int index = (boneIdx * bakedAnimData.textures[0].width + (totalKeyframes + keyframeIdx)); texture0Colour[index] = boneMatrix[i][keyframeIdx, boneIdx].GetRow(0); texture1Colour[index] = boneMatrix[i][keyframeIdx, boneIdx].GetRow(1); texture2Colour[index] = boneMatrix[i][keyframeIdx, boneIdx].GetRow(2); } } // set the color data bakedAnimData.textures[0].SetPixels(texture0Colour); // Apply this without setting minmaps and do not make them no longer readable bakedAnimData.textures[0].Apply(false, false); bakedAnimData.textures[1].SetPixels(texture1Colour); bakedAnimData.textures[1].Apply(false, false); bakedAnimData.textures[2].SetPixels(texture2Colour); bakedAnimData.textures[2].Apply(false, false); // Create the animation clip data AnimationClipData clipData = new AnimationClipData(); clipData.Clip = animationClips[i]; clipData.textureStart = totalKeyframes + 1; clipData.textureEnd = (totalKeyframes + boneMatrix[i].GetLength(0) - 1) - 1; // Add this animation to the animation clip data bakedAnimData.animationClipData.Add(clipData); // count the total running amount of keyframes totalKeyframes += boneMatrix[i].GetLength(0); } // Return the AnimatorData gathered return(bakedAnimData); }