void OnGUI() { targetGo = (GameObject)EditorGUILayout.ObjectField(targetGo, typeof(GameObject), true); subPath = targetGo == null ? subPath : targetGo.name; EditorGUILayout.LabelField(string.Format("保存路径output path:{0}", Path.Combine(path, subPath))); path = EditorGUILayout.TextField(path); subPath = EditorGUILayout.TextField(subPath); if (GUILayout.Button("Bake")) { if (targetGo == null) { EditorUtility.DisplayDialog("err", "targetGo is null!", "OK"); return; } if (baker == null) { baker = new AnimMapBaker(); } baker.SetAnimData(targetGo); List <BakedData> list = baker.Bake(); if (list != null) { for (int i = 0; i < list.Count; i++) { BakedData data = list[i]; Save(ref data); } } } }
private Material SaveAsMat(ref BakedData data) { if (animMapShader == null) { EditorUtility.DisplayDialog("err", "shader is null!!", "OK"); return(null); } if (targetGo == null || !targetGo.GetComponentInChildren <SkinnedMeshRenderer>()) { EditorUtility.DisplayDialog("err", "SkinnedMeshRender is null!!", "OK"); return(null); } SkinnedMeshRenderer smr = targetGo.GetComponentInChildren <SkinnedMeshRenderer>(); Material mat = new Material(smr.sharedMaterial); Texture2D animMap = SaveAsAsset(ref data); //mat.SetTexture("_MainTex", smr.sharedMaterial.mainTexture); mat.SetTexture("_AnimMap", animMap); mat.SetFloat("_AnimLen", data.animLen); string folderPath = CreateFolder(); AssetDatabase.CreateAsset(mat, Path.Combine(folderPath, data.name + ".mat")); return(mat); }
private void SaveAsAsset(ref BakedData data) { MemoryStream file = new MemoryStream(1024); BinaryWriter writer = new BinaryWriter(file); writer.Write(data.animMapWidth); writer.Write(data.animMapHeight); writer.Write(data.animLen); for (int i = 0; i < data.animData.Length; ++i) { var point = data.animData[i]; writer.Write((short)(point.x * 1000f)); writer.Write((short)(point.y * 1000f)); writer.Write((short)(point.z * 1000f)); } StringBuilder pathBuilder = new StringBuilder(1024); pathBuilder.Append(Application.dataPath).Append('/'); pathBuilder.Append(subPath).Append('/'); pathBuilder.Append(data.name).Append(".bytes"); var fullPath = pathBuilder.ToString(); var directory = Path.GetDirectoryName(fullPath); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } File.WriteAllBytes(fullPath, file.GetBuffer()); }
private Mesh SaveAsMesh(ref BakedData data) { if (targetGo == null || !targetGo.GetComponentInChildren <SkinnedMeshRenderer>()) { EditorUtility.DisplayDialog("err", "SkinnedMeshRender is null!!", "OK"); return(null); } SkinnedMeshRenderer smr = targetGo.GetComponentInChildren <SkinnedMeshRenderer>(); var mesh = new Mesh(); smr.BakeMesh(mesh); var uv2 = new Vector2[mesh.vertexCount]; for (var i = mesh.vertexCount - 1; i >= 0; i--) { uv2[i] = new Vector2(i, i); } mesh.uv2 = uv2; string folderPath = CreateFolder(); AssetDatabase.CreateAsset(mesh, Path.Combine(folderPath, data.name + ".mesh")); return(mesh); }
private static Material SaveAsMat(ref BakedData data) { if (_animMapShader == null) { EditorUtility.DisplayDialog("err", "shader is null!!", "OK"); return(null); } if (_targetGo == null || !_targetGo.GetComponentInChildren <SkinnedMeshRenderer>()) { EditorUtility.DisplayDialog("err", "SkinnedMeshRender is null!!", "OK"); return(null); } var smr = _targetGo.GetComponentInChildren <SkinnedMeshRenderer>(); var mat = new Material(_animMapShader); var animMap = SaveAsAsset(ref data); mat.SetTexture(MainTex, smr.sharedMaterial.mainTexture); mat.SetTexture(AnimMap, animMap); mat.SetFloat(AnimLen, data.AnimLen); var folderPath = CreateFolder(); AssetDatabase.CreateAsset(mat, Path.Combine(folderPath, $"{data.Name}.mat")); return(mat); }
private void SaveAsPrefab(ref BakedData data, int i, Mesh mesh) { Material mat = SaveAsMat(ref data, i); if (mat == null) { EditorUtility.DisplayDialog("err", "mat is null!!", "OK"); return; } GameObject go = new GameObject(); go.AddComponent <MeshRenderer>().sharedMaterial = mat; go.AddComponent <MeshFilter>().sharedMesh = mesh; mat.enableInstancing = true; string folderPath = CreateFolder(); string prefabName = data.name; //if (data.name.LastIndexOf("_") >= 0) //{ // prefabName = data.name.Substring(0, data.name.LastIndexOf("_")); //} prefabName += "prefab"; PrefabUtility.CreatePrefab(Path.Combine(folderPath, prefabName + ".prefab").Replace("\\", "/"), go); GameObject.DestroyImmediate(go); }
private Material SaveAsMat(ref BakedData data, int i) { if (animMapShader == null) { animMapShader = Shader.Find("Custom/CharactorShader"); } if (targetGo == null || !targetGo.GetComponentInChildren <SkinnedMeshRenderer>()) { EditorUtility.DisplayDialog("err", "SkinnedMeshRender is null!!", "OK"); return(null); } SkinnedMeshRenderer smr = targetGo.GetComponentInChildren <SkinnedMeshRenderer>(); Material mat = new Material(animMapShader); Texture2D animMap = SaveAsAsset(ref data, i); mat.SetTexture("_MainTex", smr.sharedMaterial.mainTexture); mat.SetTexture("_AnimMap", animMap); mat.SetFloat("_AnimAll", data.animLen); string folderPath = CreateFolder(); string matName = data.name; //if (data.name.LastIndexOf("_") >= 0) //{ // matName = data.name.Substring(0, data.name.LastIndexOf("_")); //} matName += "matbaked"; AssetDatabase.CreateAsset(mat, Path.Combine(folderPath, matName + ".mat")); return(mat); }
private Material SaveAsMat(ref BakedData data) { if (_animMapShader == null) { EditorUtility.DisplayDialog("err", "shader is null!!", "OK"); return(null); } if (_targetGo == null || !_targetGo.GetComponentInChildren <SkinnedMeshRenderer>()) { EditorUtility.DisplayDialog("err", "SkinnedMeshRender is null!!", "OK"); return(null); } var smr = _targetGo.GetComponentInChildren <SkinnedMeshRenderer>(); var mat = new Material(_animMapShader); var animMap = SaveAsAsset(ref data); mat.SetTexture("_MainTex", smr.sharedMaterial.mainTexture); mat.SetTexture("_AnimMap", animMap); mat.SetFloat("_AnimLen", data.AnimLen); mat.SetInt("_AnimOffsetYPixel", data.AnimOffsetYPixel); if (data.VATMultipleRows) { mat.EnableKeyword("VATMultipleRows_ON"); mat.SetInt("_VATMultipleRows", 1); } mat.enableInstancing = true; var folderPath = CreateFolder(); AssetDatabase.CreateAsset(mat, Path.Combine(folderPath, data.Name + ".mat")); return(mat); }
private Material[] SaveAsMat(ref BakedData data) { if (animMapShader == null) { EditorUtility.DisplayDialog("err", "shader is null!!", "OK"); return(null); } if (targetGo == null || !targetGo.GetComponentInChildren <SkinnedMeshRenderer>()) { EditorUtility.DisplayDialog("err", "SkinnedMeshRender is null!!", "OK"); return(null); } SkinnedMeshRenderer smr = targetGo.GetComponentInChildren <SkinnedMeshRenderer>(); Material[] mats = new Material[smr.sharedMaterials.Length]; for (int i = 0; i < smr.sharedMaterials.Length; i++) { Material mat = new Material(animMapShader); Texture2D animMap = SaveAsAsset(ref data); mat.SetTexture("_MainTex", smr.sharedMaterials[i].mainTexture); mat.SetTexture("_AnimMap", animMap); mat.SetFloat("_AnimLen", data.animLen); mat.enableInstancing = true; string folderPath = CreateFolder(); AssetDatabase.CreateAsset(mat, Path.Combine(folderPath, data.name + i + ".mat")); mats[i] = mat; } return(mats); }
void OnGUI() { GUILayout.Label("Target Prefab"); GameObject oldObj = targetGo; targetGo = (GameObject)EditorGUILayout.ObjectField(targetGo, typeof(GameObject), true); GUILayout.Label("Target Animation FBX"); animationFBX = (GameObject)EditorGUILayout.ObjectField(animationFBX, typeof(GameObject), true); if (targetGo != oldGameObject) { oldGameObject = targetGo; } GUILayout.Label("RootBone GameObject"); rootBone = (GameObject)EditorGUILayout.ObjectField(rootBone, typeof(GameObject), true); Object target = PrefabUtility.GetPrefabParent(targetGo); path = AssetDatabase.GetAssetPath(target); if (path == "") { path = AssetDatabase.GetAssetPath(targetGo); } int index = path.LastIndexOf("/"); if (index >= 0) { path = path.Substring(7, index - 7); } EditorGUILayout.LabelField(string.Format("output path:{0}", path)); path = EditorGUILayout.TextField(path); if (GUILayout.Button("Bake")) { if (targetGo == null) { EditorUtility.DisplayDialog("err", "targetGo is null!", "OK"); return; } baker = new AnimMapBaker(); baker.SetAnimData(targetGo, animationFBX, path); Dictionary <string, string> dic = new Dictionary <string, string>(); Mesh tarMesh = null; List <BakedData> list = baker.Bake(targetGo, animationFBX, rootBone, path, dic, ref tarMesh); if (list != null) { for (int i = 0; i < list.Count; i++) { BakedData data = list[i]; Save(ref data, i, tarMesh); } } } }
private static Texture2D SaveAsAsset(ref BakedData data) { var folderPath = CreateFolder(); var animMap = new Texture2D(data.AnimMapWidth, data.AnimMapHeight, TextureFormat.RGBAHalf, false); animMap.LoadRawTextureData(data.RawAnimMap); AssetDatabase.CreateAsset(animMap, Path.Combine(folderPath, data.Name + ".asset")); return(animMap); }
private Texture2D SaveAsAsset(ref BakedData data) { string folderPath = CreateFolder(); Texture2D animMap = new Texture2D(data.animMapWidth, data.animMapHeight, TextureFormat.RGBAHalf, false); animMap.LoadRawTextureData(data.rawAnimMap); AssetDatabase.CreateAsset(animMap, Path.Combine(folderPath, data.name + ".asset")); return(animMap); }
private Texture2D SaveAsAsset(ref BakedData data, int i) { string folderPath = CreateFolder(); Texture2D animMap = new Texture2D(data.animMapWidth, data.animMapHeight, AnimMapBaker.format, false); animMap.filterMode = FilterMode.Point; animMap.LoadRawTextureData(data.rawAnimMap); AssetDatabase.CreateAsset(animMap, Path.Combine(folderPath, data.name + ".asset")); return(animMap); }
private TextAsset SaveAsTextAsset(ref BakedData data) { var folderPath = CreateFolder(); Debug.LogError(data.JsonInfo); var text = new TextAsset(data.JsonInfo); AssetDatabase.CreateAsset(text, Path.Combine(folderPath, data.Name + "Info.asset")); return(text); }
private Texture2D SaveAsAsset(ref BakedData data) { var folderPath = CreateFolder(); var animMap = new Texture2D(data.AnimMapWidth, data.AnimMapHeight, TextureFormat.RGBAHalf, false); animMap.wrapMode = TextureWrapMode.Clamp; animMap.filterMode = FilterMode.Point; animMap.LoadRawTextureData(data.RawAnimMap); AssetDatabase.CreateAsset(animMap, Path.Combine(folderPath, data.Name + ".asset")); SaveAsTextAsset(ref data); return(animMap); }
private void Save(ref BakedData data, int i, Mesh mesh) { if (i == 0) { SaveAsPrefab(ref data, i, mesh); } else { SaveAsAsset(ref data, i); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); }
public static BakedData Bake(this GameObject model, AnimationClip[] animationClips, bool applyRootMotion, int fps, int textureWidth) { BakedData bakedData = new BakedData() { mesh = null, positionMaps = new List <Texture2D>(), minBounds = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue), maxBounds = new Vector3(float.MinValue, float.MinValue, float.MinValue) }; // Calculate what our max frames/time is going to be. int maxFrames = 0; foreach (AnimationClip ac in animationClips) { int frames = Mathf.FloorToInt(fps * ac.length); if (maxFrames < frames) { maxFrames = frames; } } // Get the target mesh to calculate the animation info. Mesh mesh = model.GetComponent <SkinnedMeshRenderer>().sharedMesh; // Get the info for the biggest animation. AnimationInfo animationInfo = new AnimationInfo(mesh, applyRootMotion, maxFrames, textureWidth, fps); foreach (AnimationClip ac in animationClips) { // Set the frames for this animation. animationInfo.frames = Mathf.FloorToInt(fps * ac.length); BakedData bd = Bake(model, ac, animationInfo); bakedData.mesh = bd.mesh; bakedData.positionMaps.AddRange(bd.positionMaps); bakedData.maxFrames = maxFrames; bakedData.minBounds = Vector3.Min(bakedData.minBounds, bd.minBounds); bakedData.maxBounds = Vector3.Max(bakedData.maxBounds, bd.maxBounds); } bakedData.mesh.bounds = new Bounds() { max = bakedData.maxBounds, min = bakedData.minBounds }; return(bakedData); }
private void SaveAsPrefab(ref BakedData data) { Material mat = SaveAsMat(ref data); if (mat == null) { EditorUtility.DisplayDialog("err", "mat is null!!", "OK"); return; } GameObject go = new GameObject(); go.AddComponent <MeshRenderer>().sharedMaterial = mat; go.AddComponent <MeshFilter>().sharedMesh = targetGo.GetComponentInChildren <SkinnedMeshRenderer>().sharedMesh; string folderPath = CreateFolder(); PrefabUtility.CreatePrefab(Path.Combine(folderPath, data.name + ".prefab").Replace("\\", "/"), go); }
private void Save(ref BakedData data) { switch (_stratege) { case SaveStrategy.AnimMap: SaveAsAsset(ref data); break; case SaveStrategy.Mat: SaveAsMat(ref data); break; // case SaveStrategy.Prefab: // SaveAsPrefab(ref data); // break; } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); }
public static BakedData Bake(this GameObject model, AnimationClip animationClip, AnimationInfo animationInfo) { Mesh mesh = new Mesh { name = string.Format("{0}", model.name) }; // Set root motion options. if (model.TryGetComponent(out Animator animator)) { animator.applyRootMotion = animationInfo.applyRootMotion; } // Bake mesh for a copy and to apply the new UV's to. SkinnedMeshRenderer skinnedMeshRenderer = model.GetComponent <SkinnedMeshRenderer>(); skinnedMeshRenderer.BakeMesh(mesh); mesh.RecalculateBounds(); mesh.uv3 = mesh.BakePositionUVs(animationInfo); BakedAnimation bakedAnimation = BakeAnimation(model, animationClip, animationInfo); BakedData bakedData = new BakedData() { mesh = mesh, positionMaps = new List <Texture2D>() { bakedAnimation.positionMap }, maxFrames = animationInfo.maxFrames, minBounds = bakedAnimation.minBounds, maxBounds = bakedAnimation.maxBounds }; mesh.bounds = new Bounds() { max = bakedAnimation.maxBounds, min = bakedAnimation.minBounds }; return(bakedData); }
private static void SaveAsPrefab(ref BakedData data) { var mat = SaveAsMat(ref data); if (mat == null) { EditorUtility.DisplayDialog("err", "mat is null!!", "OK"); return; } var go = new GameObject(); go.AddComponent <MeshRenderer>().sharedMaterial = mat; go.AddComponent <MeshFilter>().sharedMesh = _targetGo.GetComponentInChildren <SkinnedMeshRenderer>().sharedMesh; var folderPath = CreateFolder(); PrefabUtility.SaveAsPrefabAsset(go, Path.Combine(folderPath, $"{data.Name}.prefab") .Replace("\\", "/")); }
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); }
public GPUAnimDrawer(IBakery bakery, IConfig config) { this.data = bakery.BakeClips(config.FrameRate); this.config = config; }
/// <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); }
private void Save(ref BakedData data) { SaveAsAsset(ref data); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); }
void OnGUI() { if (animMapShader == null) { animMapShader = Shader.Find("chenjd/AnimMapShader"); } if (obj != null && objIndex < obj.Length) { targetGo = obj[objIndex] as GameObject; } targetGo = (GameObject)EditorGUILayout.ObjectField(targetGo, typeof(GameObject), true); subPath = targetGo == null ? subPath : targetGo.name; EditorGUILayout.LabelField(string.Format("保存路径output path:{0}", Path.Combine(path, subPath))); path = EditorGUILayout.TextField(path); subPath = EditorGUILayout.TextField(subPath); stratege = (SaveStrategy)EditorGUILayout.EnumPopup("保存策略output type:", stratege); if (baking || GUILayout.Button("Bake")) { if (!AssetDatabase.IsValidFolder("Assets/" + path)) { AssetDatabase.CreateFolder("Assets", path); } if (obj != null) { baking = (objIndex < obj.Length); if (!baking) { obj = null; targetGo = null; editorWindow.Close(); EditorUtility.DisplayDialog("", "批量处理结束", "OK"); return; } } if (targetGo == null) { editorWindow.Close(); EditorUtility.DisplayDialog("err", "targetGo is null!", "OK"); return; } if (baker == null) { baker = new AnimMapBaker(); } baker.SetAnimData(targetGo); List <BakedData> list = baker.Bake(); if (list != null) { for (int i = 0; i < list.Count; i++) { BakedData data = list[i]; Save(ref data); } } objIndex += 1; } }
/// <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 static BakedData BakeClips(GameObject prototype, float frameRate = 30f) { var go = Object.Instantiate(prototype); go.transform.localPosition = Vector3.zero; go.transform.localRotation = Quaternion.identity; go.SetActive(true); var skinnedMeshRenderer = go.GetComponentInChildren <SkinnedMeshRenderer>(); var sampledBoneMatrices = SampleAnimationClips(go, skinnedMeshRenderer, frameRate, out var animationClips, out var numberOfKeyFrames, out var numberOfBones); var buffer = new Vector4[numberOfBones * numberOfKeyFrames * MATRIX_ROWS_COUNT]; var bakedDataBuilder = BakedData.Create() .SetFrameRate(frameRate) .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 (buffer[index + 0] != Vector4.zero) { Debug.LogError($"Index {index + 0} not empty"); } if (buffer[index + 1] != Vector4.zero) { Debug.LogError($"Index {index + 1} not empty"); } if (buffer[index + 2] != Vector4.zero) { Debug.LogError($"Index {index + 2} not empty"); } buffer[index + 0] = matrix.GetRow(0); buffer[index + 1] = matrix.GetRow(1); buffer[index + 2] = matrix.GetRow(2); } } var clip = animationClips[clipIndex]; var start = clipOffset; var clipData = ClipData.Create(clip.name, clip.length, clip.wrapMode, start, framesCount); bakedDataBuilder.AddClip(clipData); clipOffset += framesCount * numberOfBones * MATRIX_ROWS_COUNT; } bakedDataBuilder.SetBuffer(buffer); 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 data0 = buffer[index]; var row0 = (Color)matrix.GetRow(0); index++; var data1 = buffer[index]; var row1 = (Color)matrix.GetRow(1); index++; var data2 = buffer[index]; var row2 = (Color)matrix.GetRow(2); if (!Verify(row0, data0, clipIndex, keyframeIndex, boneIndex)) { break; } if (!Verify(row1, data1, clipIndex, keyframeIndex, boneIndex)) { break; } if (!Verify(row2, data2, clipIndex, keyframeIndex, boneIndex)) { break; } } } clipOffset += numberOfBones * framesCount * MATRIX_ROWS_COUNT; } var data = bakedDataBuilder.Build(); go.SetActive(false); Object.Destroy(go); return(data); }