public void Prepare(List <AnimationInfo> infoList, ExtraBoneInfo extraBoneInfo) { aniInfo = infoList; //extraBoneInfo = extraBoneInfo; List <Matrix4x4> bindPose = new List <Matrix4x4>(150); // to optimize, MergeBone don't need to call every time Transform[] bones = RuntimeHelper.MergeBone(lodInfo[0].skinnedMeshRenderer, bindPose); allTransforms = bones; if (extraBoneInfo != null) { List <Transform> list = new List <Transform>(); list.AddRange(bones); Transform[] transforms = gameObject.GetComponentsInChildren <Transform>(); for (int i = 0; i != extraBoneInfo.extraBone.Length; ++i) { for (int j = 0; j != transforms.Length; ++j) { if (extraBoneInfo.extraBone[i] == transforms[j].name) { list.Add(transforms[j]); } } bindPose.Add(extraBoneInfo.extraBindPose[i]); } allTransforms = list.ToArray(); } AnimationInstancingMgr.Instance.AddMeshVertex(prototype.name, lodInfo, allTransforms, bindPose, bonePerVertex); foreach (var lod in lodInfo) { foreach (var cache in lod.vertexCacheList) { cache.shadowcastingMode = shadowCastingMode; cache.receiveShadow = receiveShadow; cache.layer = layer; } } Destroy(GetComponent <Animator>()); //Destroy(GetComponentInChildren<SkinnedMeshRenderer>()); PlayAnimation(0); }
void BakeAnimation() { #if UNITY_ANDROID || UNITY_IPHONE Debug.LogError("You can't bake animations on IOS or Android. Please switch to PC."); return; #endif if (generatedPrefab != null) { GameObject obj = Instantiate(generatedPrefab); obj.transform.position = Vector3.zero; obj.transform.rotation = Quaternion.identity; Animator animator = obj.GetComponentInChildren <Animator>(); AnimationInstancing script = obj.GetComponent <AnimationInstancing>(); Debug.Assert(script); SkinnedMeshRenderer[] meshRender = obj.GetComponentsInChildren <SkinnedMeshRenderer>(); List <Matrix4x4> bindPose = new List <Matrix4x4>(150); Transform[] boneTransform = RuntimeHelper.MergeBone(meshRender, bindPose); Reset(); AddMeshVertex2Generate(meshRender, boneTransform, bindPose.ToArray()); Transform rootNode = meshRender[0].rootBone; for (int j = 0; j != meshRender.Length; ++j) { meshRender[j].enabled = true; } int frames = 0; var clips = GetClips(true); foreach (AnimationClip animClip in clips) { //float lastFrameTime = 0; int aniName = animClip.name.GetHashCode(); int bakeFrames = Mathf.CeilToInt(animClip.length * aniFps); AnimationInfo info = new AnimationInfo(); info.animationNameHash = aniName; info.animationIndex = frames; info.totalFrame = bakeFrames; //bool rotationRootMotion = false, positionRootMotion = false; //for (int i = 0; i < bakeFrames; i += 1) //{ // float bakeDelta = Mathf.Clamp01(((float)i / bakeFrames)); // float animationTime = bakeDelta * animClip.length; // animClip.SampleAnimation(obj, animationTime); // info.position[i] = rootNode.localPosition; // info.rotation[i] = rootNode.localRotation; // if (i > 0 && info.position[i] != info.position[i - 1]) // { // positionRootMotion = true; // } // if (i > 0 && info.rotation[i] != info.rotation[i - 1]) // { // rotationRootMotion = true; // } //} //info.rootMotion = positionRootMotion; Matrix4x4 rootMatrix1stFrame = Matrix4x4.identity; animator.applyRootMotion = true; animator.Play("TestState", 0); // animator.StartRecording(bakeFrames); // for (int i = 0; i < bakeFrames; i += 1) // { // animator.Update(1.0f / m_fps); // } // animator.StopRecording(); // // animator.StartPlayback(); // animator.playbackTime = 0; //AnimationInstancing script = m_prefab.GetComponent<AnimationInstancing>(); for (int i = 0; i < bakeFrames; i += 1) { //float bakeDelta = Mathf.Clamp01(((float)i / bakeFrames)); //float animationTime = bakeDelta * animClip.length; //float normalizedTime = animationTime / animClip.length; //UnityEditor.Animations.AnimatorController ac = animator.runtimeAnimatorController; //UnityEditorInternal.StateMachine sm = ac.GetLayerStateMachine(0); //AnimatorStateInfo nameInfo = animator.GetCurrentAnimatorStateInfo(0); // if (lastFrameTime == 0) // { // float nextBakeDelta = Mathf.Clamp01(((float)(i + 1) / bakeFrames)); // float nextAnimationTime = nextBakeDelta * animClip.length; // lastFrameTime = animationTime - nextAnimationTime; // } // animator.Update(animationTime - lastFrameTime); // lastFrameTime = animationTime; animator.Update(1.0f / bakeFrames); //animClip.SampleAnimation(obj, animationTime); //if (i == 0) //{ // rootMatrix1stFrame = boneTransform[0].localToWorldMatrix; //} for (int j = 0; j != meshRender.Length; ++j) { GenerateBoneMatrix(meshRender[j].name.GetHashCode(), aniName, i, rootMatrix1stFrame, info.rootMotion); } } aniInfo.Add(info); frames += bakeFrames; SetupAnimationTexture(aniInfo); } //AnimationInstancingMgr.Instance.ExportBoneTexture(m_prefab.name); SaveAnimationInfo(generatedPrefab.name); DestroyImmediate(obj); } }
void BakeWithAnimator() { #if UNITY_ANDROID || UNITY_IPHONE Debug.LogError("You can't bake animations on IOS or Android. Please switch to PC."); return; #endif if (generatedPrefab != null) { generatedObject = Instantiate(generatedPrefab); generatedObject.transform.position = Vector3.zero; generatedObject.transform.rotation = Quaternion.identity; Animator animator = generatedObject.GetComponentInChildren <Animator>(); AnimationInstancing script = generatedObject.GetComponent <AnimationInstancing>(); Debug.Assert(script); SkinnedMeshRenderer[] meshRender = generatedObject.GetComponentsInChildren <SkinnedMeshRenderer>(); List <Matrix4x4> bindPose = new List <Matrix4x4>(150); Transform[] boneTransform = RuntimeHelper.MergeBone(meshRender, bindPose); // calculate the bindpose of attached points if (generatedFbx) { List <Transform> listExtra = new List <Transform>(); Transform[] trans = generatedFbx.GetComponentsInChildren <Transform>(); Transform[] bakedTrans = generatedObject.GetComponentsInChildren <Transform>(); foreach (var obj in selectExtraBone) { if (!obj.Value) { continue; } for (int i = 0; i != trans.Length; ++i) { Transform tran = trans[i] as Transform; if (tran.name == obj.Key) { bindPose.Add(tran.localToWorldMatrix); listExtra.Add(bakedTrans[i]); } } } Transform[] totalTransform = new Transform[boneTransform.Length + listExtra.Count]; System.Array.Copy(boneTransform, totalTransform, boneTransform.Length); System.Array.Copy(listExtra.ToArray(), 0, totalTransform, boneTransform.Length, listExtra.Count); boneTransform = totalTransform; //boneTransform = boneTransform; extraBoneInfo = new ExtraBoneInfo(); extraBoneInfo.extraBone = new string[listExtra.Count]; extraBoneInfo.extraBindPose = new Matrix4x4[listExtra.Count]; for (int i = 0; i != listExtra.Count; ++i) { extraBoneInfo.extraBone[i] = listExtra[i].name; extraBoneInfo.extraBindPose[i] = bindPose[bindPose.Count - listExtra.Count + i]; } } Reset(); AddMeshVertex2Generate(meshRender, boneTransform, bindPose.ToArray()); Transform rootNode = meshRender[0].rootBone; for (int j = 0; j != meshRender.Length; ++j) { meshRender[j].enabled = true; } animator.applyRootMotion = true; totalFrame = 0; UnityEditor.Animations.AnimatorController controller = animator.runtimeAnimatorController as UnityEditor.Animations.AnimatorController; Debug.Assert(controller.layers.Length > 0); cacheTransition.Clear(); cacheAnimationEvent.Clear(); UnityEditor.Animations.AnimatorControllerLayer layer = controller.layers[0]; AnalyzeStateMachine(layer.stateMachine, animator, meshRender, 0, aniFps, 0); generateCount = generateInfo.Count; } }
private void OnGUI() { GUI.skin.label.richText = true; GUILayout.BeginHorizontal(); { GUILayout.FlexibleSpace(); } GUILayout.EndHorizontal(); GameObject prefab = EditorGUILayout.ObjectField("Asset to Generate", generatedPrefab, typeof(GameObject), true) as GameObject; if (prefab != generatedPrefab) { generateAnims.Clear(); customClips.Clear(); generatedPrefab = prefab; SkinnedMeshRenderer[] meshRender = generatedPrefab.GetComponentsInChildren <SkinnedMeshRenderer>(); List <Matrix4x4> bindPose = new List <Matrix4x4>(150); boneTransform = RuntimeHelper.MergeBone(meshRender, bindPose); } bool error = false; if (generatedPrefab) { exposeAttachments = EditorGUILayout.Toggle("Enable Attachments", exposeAttachments); if (exposeAttachments) { showAttachmentSetting = EditorGUILayout.Foldout(showAttachmentSetting, "Attachment setting"); if (showAttachmentSetting) { GameObject fbx = EditorGUILayout.ObjectField(" FBX", generatedFbx, typeof(GameObject), false) as GameObject; if (fbx != generatedFbx) { SkinnedMeshRenderer[] meshRender = generatedPrefab.GetComponentsInChildren <SkinnedMeshRenderer>(); List <Matrix4x4> bindPose = new List <Matrix4x4>(150); boneTransform = RuntimeHelper.MergeBone(meshRender, bindPose); generatedFbx = fbx; var allTrans = generatedPrefab.GetComponentsInChildren <Transform>().ToList(); allTrans.RemoveAll(q => boneTransform.Contains(q)); selectExtraBone.Clear(); for (int i = 0; i != allTrans.Count; ++i) { selectExtraBone.Add(allTrans[i].name, false); } } var temp = new Dictionary <string, bool>(); foreach (var obj in selectExtraBone) { temp[obj.Key] = obj.Value; } scrollPosition2 = GUILayout.BeginScrollView(scrollPosition2); foreach (var obj in temp) { bool value = EditorGUILayout.Toggle(string.Format(" {0}", obj.Key), obj.Value); selectExtraBone[obj.Key] = value; } GUILayout.EndScrollView(); } } else { generatedFbx = null; } aniFps = EditorGUILayout.IntSlider("FPS", aniFps, 1, 120); Animator animator = generatedPrefab.GetComponentInChildren <Animator>(); if (animator == null) { EditorGUILayout.LabelField("Error: The prefab should have a Animator Component."); return; } if (animator.runtimeAnimatorController == null) { EditorGUILayout.LabelField("Error: The prefab's Animator should have a Animator Controller."); return; } var clips = GetClips(animator); string[] clipNames = generateAnims.Keys.ToArray(); int totalFrames = 0; List <int> frames = new List <int>(); foreach (var clipName in clipNames) { if (!generateAnims[clipName]) { continue; } AnimationClip clip = clips.Find(delegate(AnimationClip c) { if (c != null) { return(c.name == clipName); } return(false); }); int framesToBake = clip ? (int)(clip.length * aniFps / 1.0f) : 0; totalFrames += framesToBake; frames.Add(framesToBake); } int textureCount = 1; int textureWidth = CalculateTextureSize(out textureCount, frames.ToArray(), boneTransform); error = textureCount == 0; if (textureCount == 0) { EditorGUILayout.LabelField("Error: There is certain animation's frames which is larger than a whole texture."); } else if (textureCount == 1) { EditorGUILayout.LabelField(string.Format("Animation Texture wiil be one {0} X {1} texture", textureWidth, textureWidth)); } else { EditorGUILayout.LabelField(string.Format("Animation Texture wiil be {2} 1024 X 1024 and one {0} X {1} textures", textureWidth, textureWidth, textureCount - 1)); } scrollPosition = GUILayout.BeginScrollView(scrollPosition); foreach (var clipName in clipNames) { AnimationClip clip = clips.Find(delegate(AnimationClip c) { if (c != null) { return(c.name == clipName); } return(false); }); int framesToBake = clip ? (int)(clip.length * aniFps / 1.0f) : 0; GUILayout.BeginHorizontal(); { generateAnims[clipName] = EditorGUILayout.Toggle(string.Format("({0}) {1} ", framesToBake, clipName), generateAnims[clipName]); GUI.enabled = generateAnims[clipName]; //frameSkips[clipName] = Mathf.Clamp(EditorGUILayout.IntField(frameSkips[clipName]), 1, fps); GUI.enabled = true; } GUILayout.EndHorizontal(); if (framesToBake > 5000) { GUI.skin.label.richText = true; EditorGUILayout.LabelField("<color=red>Long animations degrade performance, consider using a higher frame skip value.</color>", GUI.skin.label); } } GUILayout.EndScrollView(); } if (generatedPrefab && !error) { if (GUILayout.Button(string.Format("Generate"))) { //BakeAnimation(); BakeWithAnimator(); } } }