public void GenerateAnimations() { animationClips = new AnimationClip[sortedFrames.Length / 3]; int animationCount = 0; for (int i=0; i<animationClips.Length; i++) { if (animationNames[i] != "") { AnimationClip animationClip; if (isOneFrame[i]) { animationClip = GenerateAnimation(animationNames[i], frameRate, i * 3 + 1, 1); // use 2nd sprite } else { animationClip = GenerateAnimation(animationNames[i], frameRate, i * 3, 4); SerializedObject serializedClip = new SerializedObject(animationClip); AnimationClipSettings clipSettings = new AnimationClipSettings(serializedClip.FindProperty("m_AnimationClipSettings")); clipSettings.loopTime = true; serializedClip.ApplyModifiedProperties(); } animationClips[animationCount] = animationClip; animationCount++; } } }
AnimationClip createAnimationClip(params Sprite[] sprites) { AnimationClip clip = new AnimationClip { frameRate = 9 }; AnimationClipSettings setting = new AnimationClipSettings { loopTime = true }; AnimationUtility.SetAnimationClipSettings(clip, setting); ObjectReferenceKeyframe[] keyframes = new ObjectReferenceKeyframe[sprites.Length]; for (int i = 0; i < keyframes.Length; i++) { keyframes[i] = new ObjectReferenceKeyframe { value = sprites[i], time = i / clip.frameRate }; } EditorCurveBinding curvebinding = EditorCurveBinding.PPtrCurve("", typeof(SpriteRenderer), "m_Sprite"); AnimationUtility.SetObjectReferenceCurve(clip, curvebinding, keyframes); return clip; }
static AnimationClip BuildAnimationClip(DirectoryInfo dictorys) { string animationName = dictorys.Name; //查找所有图片,因为我找的测试动画是.jpg FileInfo []images = dictorys.GetFiles("*.jpg"); AnimationClip clip = new AnimationClip(); AnimationUtility.SetAnimationType(clip,ModelImporterAnimationType.Generic); EditorCurveBinding curveBinding = new EditorCurveBinding(); curveBinding.type = typeof(SpriteRenderer); curveBinding.path=""; curveBinding.propertyName = "m_Sprite"; ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[images.Length]; //动画长度是按秒为单位,1/10就表示1秒切10张图片,根据项目的情况可以自己调节 float frameTime = 1/10f; for(int i =0; i< images.Length; i++){ Sprite sprite = Resources.LoadAssetAtPath<Sprite>(DataPathToAssetPath(images[i].FullName)); keyFrames[i] = new ObjectReferenceKeyframe (); keyFrames[i].time = frameTime *i; keyFrames[i].value = sprite; } //动画帧率,30比较合适 clip.frameRate = 30; //有些动画我希望天生它就动画循环 if(animationName.IndexOf("idle") >=0 ) { //设置idle文件为循环动画 SerializedObject serializedClip = new SerializedObject(clip); AnimationClipSettings clipSettings = new AnimationClipSettings(serializedClip.FindProperty("m_AnimationClipSettings")); clipSettings.loopTime = true; serializedClip.ApplyModifiedProperties(); } string parentName = System.IO.Directory.GetParent(dictorys.FullName).Name; System.IO.Directory.CreateDirectory(AnimationPath +"/"+parentName); AnimationUtility.SetObjectReferenceCurve(clip,curveBinding,keyFrames); AssetDatabase.CreateAsset(clip,AnimationPath +"/"+parentName +"/" +animationName+".anim"); AssetDatabase.SaveAssets(); return clip; }
void CreateClip() { var obj = Selection.GetFiltered <Object>(SelectionMode.TopLevel); obj = Sort(obj); var time = 1 / frameRate * frameTime; ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[obj.Length + 1]; for (int i = 0; i <= obj.Length; i++) { Sprite sprite = AssetDatabase.LoadAssetAtPath <Sprite>(AssetDatabase.GetAssetPath(obj[i == obj.Length ? 0 : i])); keyFrames[i] = new ObjectReferenceKeyframe(); keyFrames[i].time = time * i; keyFrames[i].value = sprite; } AnimationClip clip = new AnimationClip(); clip.frameRate = frameRate; AnimationClipSettings clipSettings = AnimationUtility.GetAnimationClipSettings(clip); clipSettings.loopTime = true; AnimationUtility.SetAnimationClipSettings(clip, clipSettings); EditorCurveBinding curveBinding = new EditorCurveBinding(); curveBinding.type = typeof(SpriteRenderer); curveBinding.propertyName = "m_Sprite"; AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames); if (!Directory.Exists("Assets/" + folder)) { Directory.CreateDirectory("Assets/" + folder); } AssetDatabase.CreateAsset(clip, "Assets/" + folder + "/" + fileName + ".anim"); }
static AnimationClip BuildAnimationClip(DirectoryInfo dictorys, string name) { string animationName = dictorys.Name; //查找所有图片,因为我找的测试动画是.jpg FileInfo[] images = dictorys.GetFiles().ToList().Where(x => (x.Extension.ToLower() == ".png" || x.Extension.ToLower() == ".tga")).OrderBy(x => (TurnNumToInt(x.Name))).ToArray(); AnimationClip clip = new AnimationClip(); EditorCurveBinding curveBinding = new EditorCurveBinding(); curveBinding.type = typeof(SpriteRenderer); curveBinding.path = ""; curveBinding.propertyName = "m_Sprite"; ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[images.Length]; //动画长度是按秒为单位,1/10就表示1秒切10张图片,根据项目的情况可以自己调节 float frameTime = 1f / 12f; for (int i = 0; i < images.Length; i++) { Sprite sprite = AssetDatabase.LoadAssetAtPath <Sprite>(DataPathToAssetPath(images[i].FullName).Replace("\\", "/")); keyFrames[i] = new ObjectReferenceKeyframe(); keyFrames[i].time = frameTime * Mathf.Max(0, (i + 1 - Mathf.Pow(1.07f, i))); keyFrames[i].value = sprite; } //动画帧率,30比较合适 clip.frameRate = 30; SerializedObject serializedClip = new SerializedObject(clip); AnimationClipSettings clipSettings = new AnimationClipSettings(serializedClip.FindProperty("m_AnimationClipSettings")); clipSettings.loopTime = true; serializedClip.ApplyModifiedProperties(); AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames); return(clip); }
// Start baking an animation state, clip or timeline, also called for each next clip in the baking array public void BakeClip() { #if UNITY_EDITOR if (mode == Mode.AnimationClips && inheritClipSettings) { AnimationClipSettings originalSettings = AnimationUtility.GetAnimationClipSettings(animationClips[currentClipIndex]); addLoopFrame = originalSettings.loopTime; } else { if (mode == Mode.Realtime) { addLoopFrame = clipSettings.loopTime && clipSettings.loopBlend; } else { addLoopFrame = clipSettings.loopTime; } } StartBaking(); #endif }
//将图集生成动画文件 private static AnimationClip BuildAnimationClip(DirectoryInfo dictoryAnimations) { string animationName = dictoryAnimations.Name; FileInfo[] images = dictoryAnimations.GetFiles("*." + imageFormat); AnimationClip clip = new AnimationClip(); AnimationUtility.SetAnimationType(clip, ModelImporterAnimationType.Generic); //设置动画类型 EditorCurveBinding curveBinding = new EditorCurveBinding(); curveBinding.type = typeof (SpriteRenderer); curveBinding.path = ""; curveBinding.propertyName = "m_Sprite"; ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[images.Length]; for (int i = 0; i < images.Length; i++) { Sprite sprite = Resources.LoadAssetAtPath<Sprite>(DataPathToAssetPath(images[i].FullName)); keyFrames[i] = new ObjectReferenceKeyframe(); keyFrames[i].time = frameTime*i; keyFrames[i].value = sprite; } clip.frameRate = frameRate; if (animationName.IndexOf("idle") >= 0) { //设置idle动画为循环动画 SerializedObject serializedClip = new SerializedObject(clip); AnimationClipSettings clipSettings = new AnimationClipSettings(serializedClip.FindProperty("m_AnimationClipSettings")); clipSettings.loopTime = true; serializedClip.ApplyModifiedProperties(); } string parentName = System.IO.Directory.GetParent((dictoryAnimations.FullName)).Name; System.IO.Directory.CreateDirectory(animationPath + "/" + parentName); AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames); AssetDatabase.CreateAsset(clip, animationPath + "/" + parentName + "/" + animationName + ".anim"); AssetDatabase.SaveAssets(); return clip; }
private void UpdateClipSettings(AnimationClip clip, bool isNewClip) { clip.wrapMode = WrapMode.Loop; AnimationUtility.SetAnimationType(clip, ModelImporterAnimationType.Generic); AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(clip); settings.loopTime = true; settings.startTime = 0f; // If animation is a single keyframe then make sure stop time is a small value rather than 0, // as Unity will otherwise default to an animation length of 1 second settings.stopTime = Mathf.Max(clip.length, 0.01f); SpineUtilities.SetAnimationSettings(clip, settings); // Add animation clip to layer 0 of the animator controller UnityEditorInternal.AnimatorController controller = transform.GetComponent <Animator>().runtimeAnimatorController as UnityEditorInternal.AnimatorController; if (controller && isNewClip) { UnityEditorInternal.AnimatorController.AddAnimationClipToController(controller, clip); } }
private static void CheckSingleNode(string path) { string lowerPath = path.ToLower(); if (lowerPath.IndexOf("idle") < 0 && lowerPath.IndexOf("run") < 0 && lowerPath.IndexOf("sleep") < 0 && lowerPath.IndexOf("coma") < 0) { return; } path = path.Replace('\\', '/'); AnimationClip controller = AssetDatabase.LoadAssetAtPath <AnimationClip>(path); if (null == controller) { return; } AnimationClipSettings clipsetting = AnimationUtility.GetAnimationClipSettings(controller); if (!clipsetting.loopTime) { Debug.Log(string.Concat("Message:", path, "-->:", "修改设置")); } clipsetting.loopTime = true; AnimationUtility.SetAnimationClipSettings(controller, clipsetting); }
public void SetUpTrackProperties(AnimatedObject aObj, Vector3 trackPosition, Timeline t, int i, Material unselectedCol, Material selectedCol) { animatedObject = aObj; timeline = t; aObj.beizerPathGroup.beizerPathData.animTrack = this; transform.parent = timeline.transform; transform.localPosition = trackPosition; clip = new AnimationClip(); clip.name = $"FunClip {i}"; clip.wrapMode = WrapMode.Loop; Debug.Log("wrapMode " + clip.wrapMode); unselectedColor = unselectedCol; selectedColor = selectedCol; AnimationClipSettings tSettings = AnimationUtility.GetAnimationClipSettings(clip); Debug.Log(tSettings.loopTime); tSettings.loopTime = true; Debug.Log(tSettings.loopTime); AnimationUtility.SetAnimationClipSettings(clip, tSettings); AssetDatabase.CreateAsset(clip, $"Assets/clip_{i}.anim"); animCurve = ScriptableObject.CreateInstance <AnimCurve>(); animCurve.clip = clip; animCurve.animTrack = this; animCurve.SetupAnimationCurves(); timeline.trackSectionData.ConnectTracksToPlayableGraph(clip, animatedObject.GetComponent <Animator>()); SubscribeToAnimationEvents(); Debug.Log(animCurve); }
public AnimationClipInfoProperties(AnimationClip animationClip, AnimationClipSettings animationClipSettings) { this.animationClip = animationClip; this.animationClipSettings = animationClipSettings; }
private void CreateCharacter() { var obj = new GameObject("Character"); var animator = obj.AddComponent <Animator>(); var renderer = obj.AddComponent <SpriteRenderer>(); // ぼやけを除去 this.m_Image.filterMode = FilterMode.Point; // 15フレームに一回アニメーションする float frameLength = 15f / 60f; // 画像は横にアニメーションする int frameCount = this.m_Image.width / this.m_CropWidth; // 画像は縦に種類が並んでいる int stateCount = this.m_Image.height / this.m_CropHeight; bool extendedCharaChipSet = false; // ただし、8方向のチップセットが存在するので、それに対処する if (frameCount == 6 || frameCount == 10) { frameCount >>= 1; stateCount <<= 1; extendedCharaChipSet = true; } // スプライト配列の作成 Sprite[,] sprites = new Sprite[stateCount, frameCount]; // Blend Tree 設定用のVector2配列の準備 Vector2[] positions = { new Vector2(0, 1), new Vector2(1, 0), new Vector2(-1, 0), new Vector2(0, -1), new Vector2(1, 1), new Vector2(-1, 1), new Vector2(1, -1), new Vector2(-1, -1), }; // スプライトの切り出し Texture2D[,] textures = new Texture2D[stateCount, frameCount]; for (int y = 0; y < stateCount; y++) { for (int x = 0; x < frameCount; x++) { //指定された幅高さでテスクチャからスプライトを切り出す var rect = new Rect(x * this.m_CropWidth, y * this.m_CropHeight, this.m_CropWidth, this.m_CropHeight); var texture = new Texture2D(m_CropWidth, m_CropHeight); var colors = m_Image.GetPixels((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height); texture.SetPixels(colors); var bin = texture.EncodeToPNG(); File.WriteAllBytes(m_Folder + $"{m_Image.name + "_" + y + x}.png", bin); AssetDatabase.Refresh(); //var sprite = Sprite.Create(this.m_Image, rect, new Vector2(0.5f, 0.5f), this.m_CropHeight); /*var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f), m_CropHeight); * sprite.name = this.m_Image.name + "_" + y + x; * sprite.texture.filterMode = FilterMode.Point; * sprites[y, x] = sprite;*/ //AssetDatabase.CreateAsset(texture, m_Folder + $"{sprite.name}.png"); } } for (int y = 0; y < stateCount; y++) { for (int x = 0; x < frameCount; x++) { var texture = AssetDatabase.LoadAssetAtPath <Texture2D>(m_Folder + $"{m_Image.name + "_" + y + x}.png"); var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f), m_CropHeight); sprite.name = this.m_Image.name + "_" + y + x; sprite.texture.filterMode = FilterMode.Point; sprites[y, x] = sprite; } } // アニメータコントローラの作成 AnimatorController animatorController = AnimatorController.CreateAnimatorControllerAtPath(m_Folder + m_FileName); // 名前はテクスチャ名にする animatorController.name = this.m_Image.name; //向きと状態指定用のパラメータを追加 animatorController.AddParameter("DirectionX", AnimatorControllerParameterType.Float); animatorController.AddParameter("DirectionY", AnimatorControllerParameterType.Float); animatorController.AddParameter("Walking", AnimatorControllerParameterType.Bool); // アニメータコントローラにベースレイヤを追加 //animatorController.AddLayer("Base"); // 止まり状態を追加する BlendTree waitBlendTree; AnimatorState waitState = animatorController.CreateBlendTreeInController("Wait", out waitBlendTree); waitBlendTree.name = "Blend Tree"; // 止まり状態はアニメーションしないが // 方向によってスプライトが変化する waitBlendTree.blendType = BlendTreeType.SimpleDirectional2D; waitBlendTree.blendParameter = "DirectionX"; waitBlendTree.blendParameterY = "DirectionY"; // 状態の数だけループ for (int i = 0; i < stateCount; i++) { // アニメーションしないので、キーフレームを1つだけ用意する ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[1]; keyFrames[0] = new ObjectReferenceKeyframe { time = 0.0f,// 止まりのスプライトを指定 value = sprites[i, 1] }; // アニメーションクリップの作成 AnimationClip clip = new AnimationClip { // 名前は歩きとかぶるので、wait_状態のインデックスにする name = "Wait_" + i, // はみ出た部分は消す wrapMode = WrapMode.Clamp }; // カーブの作成 EditorCurveBinding curveBinding = new EditorCurveBinding { //ファイルは存在しない path = string.Empty, //スプライトをアニメーションするのでtypeにSpriteRenderer // propertyNameにはm_Spriteを指定 type = typeof(SpriteRenderer), propertyName = "m_Sprite" }; //クリップとカーブにキーフレームをバインド AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames); //状態を止まり状態のブレンドツリーに追加 waitBlendTree.AddChild(clip, positions[i]); // AnimationClipをAssetとして保存 AssetDatabase.CreateAsset(clip, m_Folder + $"{Path.GetFileNameWithoutExtension(m_FileName)}_{clip.name}.anim"); } // 歩き状態を追加する BlendTree walkBlendTree; AnimatorState walkState = animatorController.CreateBlendTreeInController("Walk", out walkBlendTree); walkBlendTree.name = "Blend Tree"; // 歩き状態は歩く方向によってアニメーションが変化する walkBlendTree.blendType = BlendTreeType.SimpleDirectional2D; walkBlendTree.blendParameter = "DirectionX"; walkBlendTree.blendParameterY = "DirectionY"; // 状態の数だけループ for (int y = 0; y < stateCount; y++) { //キーフレーム配列を作成 // 右足、止まり、左足、止まり、右足とアニメーションする // ループするので、最後に右足を入れないと左足の後の止まりが短く不自然になる ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[frameCount + 2]; // 8方向拡張対応 int offsetX = 0, offsetY = 0; if (extendedCharaChipSet && y >= (stateCount >> 1)) { offsetX = frameCount; offsetY = -(stateCount >> 1); } // 普通のアニメーションの作成 for (int x = 0; x < frameCount; x++) { // キーフレームの追加 keyFrames[x] = new ObjectReferenceKeyframe { time = x * frameLength, value = sprites[y, x] }; } // 2枚目->1枚目とアニメーションする for (int x = 1; x >= 0; x--) { int index = frameCount + 1 - x; keyFrames[index] = new ObjectReferenceKeyframe { time = index * frameLength, value = sprites[y, x] }; } // アニメーションクリップの作成 AnimationClip clip = new AnimationClip { // 名前は状態のインデックスにする name = $"Walk_{y.ToString()}", // はみ出た部分は消す wrapMode = WrapMode.Clamp }; // カーブの作成 EditorCurveBinding curveBinding = new EditorCurveBinding { // ファイルは存在しない path = string.Empty, // スプライトをアニメーションするのでtypeにSpriteRenderer // propertyNameにはm_Spriteを指定 type = typeof(SpriteRenderer), propertyName = "m_Sprite" }; // クリップとカーブにキーフレームをバインド AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames); // LoopTimeが直接設定出来ないので一旦シリアライズする SerializedObject serializedClip = new SerializedObject(clip); // アニメーションクリップ設定の取り出し AnimationClipSettings animationClipSettings = new AnimationClipSettings(serializedClip.FindProperty("m_AnimationClipSettings")) { // LoopTimeを有効にする LoopTime = true }; // 設定を書き戻す serializedClip.ApplyModifiedProperties(); // 状態を歩き状態のブレンドツリーに追加 walkBlendTree.AddChild(clip, positions[y]); // AnimationClipをAssetとして保存 AssetDatabase.CreateAsset(clip, m_Folder + $"{Path.GetFileNameWithoutExtension(m_FileName)}_{clip.name}.anim"); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); // 止まり->歩きのトランジションを作成 AnimatorStateTransition waitToWalk = waitState.AddTransition(walkState); // Walkingフラグがtrueの時 waitToWalk.AddCondition(AnimatorConditionMode.If, 0, "Walking"); // 歩き->止まりのトランジションを作成 AnimatorStateTransition walkToWait = walkState.AddTransition(waitState); // Walkingフラグがfalseの時 walkToWait.AddCondition(AnimatorConditionMode.IfNot, 0, "Walking"); // アニメータコントローラに設定 animator.runtimeAnimatorController = (animatorController as RuntimeAnimatorController); // とりあえず0,0のスプライトをデフォルトにセット renderer.sprite = sprites[0, 0]; }
//生成动画 AseAnimationSettings GenerateAnimation(AssetImportContext ctx, string name, AseFrame[] frames, int startFrame = 0, int endFrame = 0) { AseAnimationSettings animationSetting = GetAnimationSetting(name); if (generateAnimation) { AnimationClip clip = new AnimationClip(); clip.name = name; clip.frameRate = 25; if (endFrame == 0) { endFrame = frames.Length - 1; } EditorCurveBinding spriteBinding = new EditorCurveBinding(); spriteBinding.type = typeof(SpriteRenderer); spriteBinding.path = ""; spriteBinding.propertyName = "m_Sprite"; int length = endFrame - startFrame + 1; ObjectReferenceKeyframe[] spriteKeyFrames = new ObjectReferenceKeyframe[length + 1]; float time = 0; for (int i = startFrame; i <= endFrame; i++) { ObjectReferenceKeyframe frame = new ObjectReferenceKeyframe(); frame.time = time; frame.value = frames[i].sprite; time += frames[i].duration; spriteKeyFrames[i - startFrame] = frame; } //单独设置最后一帧 float frameTime = 1f / clip.frameRate; ObjectReferenceKeyframe lastFrame = new ObjectReferenceKeyframe(); lastFrame.time = time - frameTime; lastFrame.value = frames[endFrame].sprite; spriteKeyFrames[spriteKeyFrames.Length - 1] = lastFrame; AnimationUtility.SetObjectReferenceCurve(clip, spriteBinding, spriteKeyFrames); AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(clip); //循环设置 if (animationSetting.loop) { settings.loopTime = true; clip.wrapMode = WrapMode.Loop; } else { settings.loopTime = false; clip.wrapMode = WrapMode.Once; } AnimationUtility.SetAnimationClipSettings(clip, settings); ctx.AddObjectToAsset(name, clip); //string filePath = string.Format("{0}/{1}.anim", GetFileDic(ctx.assetPath), name); //AssetDatabase.CreateAsset(clip, filePath); //clip = AssetDatabase.LoadAssetAtPath(filePath, typeof(AnimationClip)) as AnimationClip; //Debug.Log(AssetDatabase.CopyAsset(); //AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(clip), filePath); } return(animationSetting); }
static AnimationClip BuildAnimationClip(Sprite[] images, string name) { //获取的是 单个动作的名称 string animationName = name; //查找所有图片 AnimationClip clip = new AnimationClip(); AnimationUtility.SetAnimationType(clip, ModelImporterAnimationType.Generic); EditorCurveBinding curveBinding = new EditorCurveBinding(); curveBinding.type = typeof(SpriteRenderer); curveBinding.path = ""; curveBinding.propertyName = "m_Sprite"; ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[images.Length]; //动画长度是按秒为单位,1/10就表示1秒切10张图片 float frameTime = 1 / 10f; for (int i = 0; i < images.Length; i++) { //根据名字 读取到sprite Sprite sprite = images[i]; // sprite.pixelsPerUnit keyFrames[i] = new ObjectReferenceKeyframe(); keyFrames[i].time = frameTime * i; keyFrames[i].value = sprite; } if (keyFrames.Length == 1) { keyFrames = new ObjectReferenceKeyframe[5]; Sprite sprite = images[0]; for (int i = 0; i < 5; i++) { keyFrames[i] = new ObjectReferenceKeyframe(); keyFrames[i].time = frameTime * i; keyFrames[i].value = sprite; } } //动画帧率,30比较合适 clip.frameRate = 30; //动画名字里包含Idle的一般设置为循环 if (animationName.ToLower().IndexOf("idle", StringComparison.Ordinal) >= 0) { //设置idle文件为循环动画 SerializedObject serializedClip = new SerializedObject(clip); AnimationClipSettings clipSettings = new AnimationClipSettings(serializedClip.FindProperty("m_AnimationClipSettings")) { loopTime = true }; serializedClip.ApplyModifiedProperties(); } string parentName = name; Directory.CreateDirectory(AnimationPath + "/" + parentName); AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames); AssetDatabase.CreateAsset(clip, AnimationPath + "/" + parentName + "/" + animationName + ".anim"); AssetDatabase.SaveAssets(); return(clip); }
/// <summary> /// Clip生成実体 /// </summary> /// <param name="sprites">各フレームに割り当てるSpriteの配列</param> AnimationClip CreateAnimationClip(params Sprite[] sprites) { /// Copyright (c) 2015 kyusyukeigo /// Released under the MIT license /// https://github.com/anchan828/unite2015tokyo/blob/master/LICENSE var animationClip = new AnimationClip { frameRate = 12 }; var animationClipSettings = new AnimationClipSettings { loopTime = true }; AnimationUtility.SetAnimationClipSettings(animationClip, animationClipSettings); var objectReferenceKeyframes = new ObjectReferenceKeyframe[sprites.Length]; for (var i = 0; i < objectReferenceKeyframes.Length; i++) { objectReferenceKeyframes[i] = new ObjectReferenceKeyframe { value = sprites[i], time = i / animationClip.frameRate }; } var editorCurveBinding = EditorCurveBinding.PPtrCurve("", typeof(SpriteRenderer), "m_Sprite"); AnimationUtility.SetObjectReferenceCurve(animationClip, editorCurveBinding, objectReferenceKeyframes); return animationClip; }
void OnGUI() { EditorGUILayout.LabelField("一个角色的切好的Sprite(任选一个)"); spritesheet = EditorGUILayout.ObjectField(spritesheet, typeof(Sprite), false) as Sprite; EditorGUILayout.LabelField("每个Walk动画的帧数"); iFramesPerLoop = EditorGUILayout.IntField(iFramesPerLoop); EditorGUILayout.LabelField("Sprite中总共动画个数"); iTotalLoops = EditorGUILayout.IntField(iTotalLoops); bMirrorLR234 = EditorGUILayout.ToggleLeft("第2,3,4个动画生成左右对称的两个动画", bMirrorLR234); bIdleForLoop = EditorGUILayout.ToggleLeft("给每个动画创建一个Idle动画", bIdleForLoop); EditorGUILayout.LabelField("Idle动画单帧位于每个动画中的位置(从1开始)"); iIdleFrameForLoop = EditorGUILayout.IntField(iIdleFrameForLoop); EditorGUILayout.LabelField("每秒帧数(Samples)"); iSamples = EditorGUILayout.IntField(iSamples); if (GUILayout.Button("载入生成")) { string sheetPath = AssetDatabase.GetAssetPath(spritesheet); //Assets/Resources/Sprites/Character/chara_01.png characterName = Path.GetFileNameWithoutExtension(sheetPath); //chara_01 directory = Path.GetDirectoryName(sheetPath); //Assets/Resources/Sprites/Character/ sprites = AssetDatabase.LoadAllAssetsAtPath(sheetPath).OfType<Sprite>().ToArray(); if (!bMirrorLR234) { //原本的代码 for (int i = 0; i < iTotalLoops; i++) { AnimationClip clip = new AnimationClip(); clip.frameRate = iFramesPerLoop; EditorCurveBinding curveBinding = new EditorCurveBinding(); curveBinding.path = ""; curveBinding.propertyName = "m_Sprite"; curveBinding.type = typeof(SpriteRenderer); ObjectReferenceKeyframe[] keys = new ObjectReferenceKeyframe[iFramesPerLoop]; for (int j = 0; j < iFramesPerLoop; j++) { keys[j] = new ObjectReferenceKeyframe(); keys[j].time = (1.0f / iFramesPerLoop) * j; keys[j].value = sprites[iFramesPerLoop * i + j]; } AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keys); AssetDatabase.CreateAsset(clip, directory + "/" + characterName + "_" + clipNames[i] + ".anim"); } } else { //234要生成镜像的代码 for (int i = 0; i < iTotalLoops + 3; i++) { int targetKey; targetKey = (i + 1) / 2; //0 1 2 3 4 5 6 7 //covert to //0 1 1 2 2 3 3 4 AnimationClip clip = new AnimationClip(); clip.frameRate = iSamples; EditorCurveBinding curveBinding = new EditorCurveBinding(); curveBinding.path = ""; curveBinding.propertyName = "m_Sprite"; curveBinding.type = typeof(SpriteRenderer); ObjectReferenceKeyframe[] keys = new ObjectReferenceKeyframe[iFramesPerLoop + 1]; for (int j = 0; j < iFramesPerLoop; j++) { keys[j] = new ObjectReferenceKeyframe(); keys[j].time = (1.0f / iSamples) * j; keys[j].value = sprites[iFramesPerLoop * targetKey + j]; } keys[3] = new ObjectReferenceKeyframe(); keys[3].time = (1.0f / iSamples) * 3; keys[3].value = sprites[iFramesPerLoop * targetKey + 1]; switch (i) { case 2: case 4: case 6: EditorCurveBinding cb2 = new EditorCurveBinding(); cb2.path = ""; cb2.propertyName = "m_FlipX"; cb2.type = typeof(SpriteRenderer); AnimationCurve ac = new AnimationCurve(); ac.AddKey(0f, 1f); AnimationUtility.SetEditorCurve(clip, cb2, ac); Debug.Log(i); break; } AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keys); AssetDatabase.CreateAsset(clip, directory + "/" + characterName + "_" + clipNames[i] + ".anim"); } if (bIdleForLoop) { for (int i = 0; i < iTotalLoops + 3; i++) { int targetKey; targetKey = (i + 1) / 2; //0 1 2 3 4 5 6 7 //covert to //0 1 1 2 2 3 3 4 AnimationClip clip = new AnimationClip(); clip.frameRate = iSamples; EditorCurveBinding curveBinding = new EditorCurveBinding(); curveBinding.path = ""; curveBinding.propertyName = "m_Sprite"; curveBinding.type = typeof(SpriteRenderer); ObjectReferenceKeyframe[] keys = new ObjectReferenceKeyframe[1]; keys[0] = new ObjectReferenceKeyframe(); keys[0].time = 0f; keys[0].value = sprites[iFramesPerLoop * targetKey + 1]; switch (i) { case 2: case 4: case 6: EditorCurveBinding cb2 = new EditorCurveBinding(); cb2.path = ""; cb2.propertyName = "m_FlipX"; cb2.type = typeof(SpriteRenderer); AnimationCurve ac = new AnimationCurve(); ac.AddKey(0f, 1f); AnimationUtility.SetEditorCurve(clip, cb2, ac); Debug.Log(i); break; } AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keys); AssetDatabase.CreateAsset(clip, directory + "/" + characterName + "_" + clipNamesIdle[i] + "_Idle.anim"); } } } string[] folders = new string[1]; folders[0] = directory; string[] clipPaths = AssetDatabase.FindAssets(characterName, folders); List<AnimationClip> clips = new List<AnimationClip>(); for (int i = 0; i < clipPaths.Length; i++) { AnimationClip c = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(clipPaths[i]), typeof(AnimationClip)) as AnimationClip; if (c != null) clips.Add(c); } for (int i = 0; i < clips.Count; i++) { SerializedObject serializedClip = new SerializedObject(clips[i]); AnimationClipSettings clipSettings = new AnimationClipSettings(serializedClip.FindProperty("m_AnimationClipSettings")); clipSettings.loopTime = true; serializedClip.ApplyModifiedProperties(); } AnimatorController controller = AnimatorController.CreateAnimatorControllerAtPath(directory + "/" + characterName + "_AnimatorController.controller"); controller.AddParameter("X", AnimatorControllerParameterType.Float); controller.AddParameter("Y", AnimatorControllerParameterType.Float); BlendTree tree; controller.CreateBlendTreeInController("Walk", out tree, 0); tree.blendType = BlendTreeType.SimpleDirectional2D; tree.blendParameter = "X"; tree.blendParameterY = "Y"; tree.useAutomaticThresholds = false; int cc = (bIdleForLoop ? clips.Count / 2 : clips.Count); for (int i = 0; i < cc; i++) { double d = i * Mathf.PI * 2 / cc; float x, y; y = (float)System.Math.Cos(d); x = (float)System.Math.Sin(d); tree.AddChild(clips[i], new Vector2(x, y)); } GameObject go = GameObject.Find(characterName); if (go == null) { go = new GameObject(characterName); go.AddComponent<SpriteRenderer>().sprite = sprites[0]; go.AddComponent<Animator>().runtimeAnimatorController = controller; } else { SpriteRenderer sr = go.GetComponent<SpriteRenderer>(); if (sr == null) go.AddComponent<SpriteRenderer>().sprite = sprites[0]; else sr.sprite = sprites[0]; Animator anim = go.GetComponent<Animator>(); if (anim == null) go.AddComponent<Animator>().runtimeAnimatorController = controller; else anim.runtimeAnimatorController = controller; } PrefabUtility.CreatePrefab(directory + "/" + characterName + ".prefab", go); } }
public static void ReloadMecanimController(ActorBaseComponent actorComponent, UnityEditor.Animations.AnimatorController animatorController) { Nima.Actor actor = actorComponent.Asset.Actor; string path = AssetDatabase.GetAssetPath(animatorController); UnityEngine.Object[] assets = AssetDatabase.LoadAllAssetsAtPath(path); List <Nima.Animation.ActorAnimation> alreadyUsedAnimations = new List <Nima.Animation.ActorAnimation>(); foreach (UnityEngine.Object asset in assets) { AnimationClip clip = asset as AnimationClip; if (clip == null) { continue; } bool exists = false; foreach (Nima.Animation.ActorAnimation actorAnimation in actor.Animations) { if (actorAnimation.Name == clip.name) { exists = true; alreadyUsedAnimations.Add(actorAnimation); clip.SetCurve("", typeof(GameObject), "null", AnimationCurve.Linear(0, 0, actorAnimation.Duration, 0)); AnimationClipSettings clipSettings = AnimationUtility.GetAnimationClipSettings(clip); clipSettings.stopTime = actorAnimation.Duration; clipSettings.loopTime = actorAnimation.IsLooping; AnimationUtility.SetAnimationClipSettings(clip, clipSettings); EditorUtility.SetDirty(clip); break; } } if (!exists) { AnimationClip.DestroyImmediate(clip, true); } } foreach (Nima.Animation.ActorAnimation actorAnimation in actor.Animations) { int idx = alreadyUsedAnimations.IndexOf(actorAnimation); if (idx == -1) { AnimationClip animationClip = new AnimationClip(); animationClip.name = actorAnimation.Name; animationClip.SetCurve("", typeof(GameObject), "null", AnimationCurve.Linear(0, 0, actorAnimation.Duration, 0)); AnimationClipSettings clipSettings = AnimationUtility.GetAnimationClipSettings(animationClip); clipSettings.stopTime = actorAnimation.Duration; clipSettings.loopTime = actorAnimation.IsLooping; AnimationUtility.SetAnimationClipSettings(animationClip, clipSettings); AssetDatabase.AddObjectToAsset(animationClip, animatorController); EditorUtility.SetDirty(animationClip); } } EditorUtility.SetDirty(animatorController); AssetDatabase.Refresh(); AssetDatabase.SaveAssets(); }
public string Process() { this.rawClip = animatorState.motion as AnimationClip; if (!rawClip) { return(null); } this.stateFlag = findStateFlag(animatorState); //查找标记,检查是否可以跳过 if (stateFlag && stateFlag.skipCompressed) { return(null); } var size = UnityEngine.Profiler.GetRuntimeMemorySize(rawClip); //小于16K 不压缩 if (size < 1024 * 16) { return(null); } string rawClipPath = AssetDatabase.GetAssetPath(rawClip); if (string.IsNullOrEmpty(rawClipPath)) { return(null); } string anim_gen_dir = Path.GetDirectoryName(rawClipPath) + "/_anim_gen_"; string dataDir = anim_gen_dir + "/datas"; string stubDir = anim_gen_dir + "/stubs"; Directory.CreateDirectory(anim_gen_dir); Directory.CreateDirectory(dataDir); Directory.CreateDirectory(stubDir); this.shareData = getShareData(anim_gen_dir); this.stubClip = new AnimationClip(); AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(rawClip); stubClip.SetCurve("", typeof(CompressedAnimationDirver), "stubAnimParam", AnimationCurve.Linear(0, 0, rawClip.length, 1)); stubClip.name = rawClip.name + "_stub"; this.clipData = CompressClipData(); AnimationUtility.SetAnimationClipSettings(stubClip, settings); //*注意:这里是为了兼容通过AnimationClipSettings设置Loop而Wrap没设置 if (settings.loopTime) { clipData.wrapMode = (byte)WrapMode.Loop; stubClip.wrapMode = WrapMode.Loop; } else { stubClip.wrapMode = rawClip.wrapMode; } animatorState.motion = stubClip; AssetDatabase.CreateAsset(stubClip, stubDir + "/" + stubClip.name + ".anim"); string dataPath = dataDir + "/" + clipData.name + ".asset"; AssetDatabase.CreateAsset(clipData, dataPath); var stateProxy = animatorState.AddStateMachineBehaviour <CompressionAnimatorStateProxy>(); stateProxy.data = clipData; return(dataPath); }
public override IEnumerable <Object> FetchDependencies(ISerializedFile file, bool isLog = false) { foreach (Object asset in base.FetchDependencies(file, isLog)) { yield return(asset); } if (IsReadClassIDToTrack(file.Version, file.Flags)) { foreach (KeyValuePair <int, PPtr <BaseAnimationTrack> > kvp in ClassIDToTrack) { yield return(kvp.Value.FetchDependency(file, isLog, () => ValidName, ClassIDToTrackName)); } foreach (ChildTrack track in ChildTracks) { foreach (Object asset in track.FetchDependencies(file, isLog)) { yield return(asset); } } } if (IsReadCurves(file.Version)) { foreach (FloatCurve curve in FloatCurves) { foreach (Object asset in curve.FetchDependencies(file, isLog)) { yield return(asset); } } } if (IsReadPPtrCurves(file.Version)) { foreach (PPtrCurve curve in PPtrCurves) { foreach (Object asset in curve.FetchDependencies(file, isLog)) { yield return(asset); } } } if (IsReadClipBindingConstant(file.Version)) { foreach (Object asset in ClipBindingConstant.FetchDependencies(file, isLog)) { yield return(asset); } } #if UNIVERSAL if (IsReadAnimationClipSettings(file.Version, file.Flags)) { foreach (Object asset in AnimationClipSettings.FetchDependencies(file, isLog)) { yield return(asset); } } if (IsReadEditorCurves(file.Version, file.Flags)) { foreach (FloatCurve editorCurve in EditorCurves) { foreach (Object asset in editorCurve.FetchDependencies(file, isLog)) { yield return(asset); } } foreach (FloatCurve eulerEditorCurve in EulerEditorCurves) { foreach (Object asset in eulerEditorCurve.FetchDependencies(file, isLog)) { yield return(asset); } } } #endif if (IsReadEvents(file.Version)) { foreach (AnimationEvent @event in Events) { foreach (Object asset in @event.FetchDependencies(file, isLog)) { yield return(asset); } } } }
public static AnimationClip CreateAnimationClip(FPlayAnimationEvent animEvent) { FAnimationTrack track = (FAnimationTrack)animEvent.Track; string animName = ((FAnimationTrack)animEvent.Track).LayerName + "_" + animEvent.GetId().ToString(); AnimationClip clip = AnimatorController.AllocateAnimatorClip(animName); clip.frameRate = animEvent.Sequence.FrameRate; Transform ownerTransform = animEvent.Owner; Vector3 pos = ownerTransform.localPosition; Vector3 rot = ownerTransform.localRotation.eulerAngles; //ownerTransform.localEulerAngles; Keyframe[] xPosKeys = new Keyframe[] { new Keyframe(0, pos.x), new Keyframe(animEvent.LengthTime, pos.x) }; Keyframe[] yPosKeys = new Keyframe[] { new Keyframe(0, pos.y), new Keyframe(animEvent.LengthTime, pos.y) }; Keyframe[] zPosKeys = new Keyframe[] { new Keyframe(0, pos.z), new Keyframe(animEvent.LengthTime, pos.z) }; Keyframe[] xRotKeys = new Keyframe[] { new Keyframe(0, rot.x), new Keyframe(animEvent.LengthTime, rot.x) }; Keyframe[] yRotKeys = new Keyframe[] { new Keyframe(0, rot.y), new Keyframe(animEvent.LengthTime, rot.y) }; Keyframe[] zRotKeys = new Keyframe[] { new Keyframe(0, rot.z), new Keyframe(animEvent.LengthTime, rot.z) }; // set the tangent mode int tangentMode = 10; // 10 is unity auto tangent mode for (int i = 0; i != xPosKeys.Length; ++i) { xPosKeys[i].tangentMode = tangentMode; yPosKeys[i].tangentMode = tangentMode; zPosKeys[i].tangentMode = tangentMode; xRotKeys[i].tangentMode = tangentMode; yRotKeys[i].tangentMode = tangentMode; zRotKeys[i].tangentMode = tangentMode; } AnimationCurve xPos = new AnimationCurve(xPosKeys); AnimationCurve yPos = new AnimationCurve(yPosKeys); AnimationCurve zPos = new AnimationCurve(zPosKeys); AnimationCurve xRot = new AnimationCurve(xRotKeys); AnimationCurve yRot = new AnimationCurve(yRotKeys); AnimationCurve zRot = new AnimationCurve(zRotKeys); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "m_LocalPosition.x"), xPos); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "m_LocalPosition.y"), yPos); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "m_LocalPosition.z"), zPos); // workaround unity bug of spilling errors if you just set localEulerAngles Quaternion quat = ownerTransform.localRotation; Keyframe[] xQuatKeys = new Keyframe[] { new Keyframe(0, quat.x), new Keyframe(animEvent.LengthTime, quat.x) }; Keyframe[] yQuatKeys = new Keyframe[] { new Keyframe(0, quat.y), new Keyframe(animEvent.LengthTime, quat.y) }; Keyframe[] zQuatKeys = new Keyframe[] { new Keyframe(0, quat.z), new Keyframe(animEvent.LengthTime, quat.z) }; Keyframe[] wQuatKeys = new Keyframe[] { new Keyframe(0, quat.w), new Keyframe(animEvent.LengthTime, quat.w) }; AnimationCurve xQuat = new AnimationCurve(xQuatKeys); AnimationCurve yQuat = new AnimationCurve(yQuatKeys); AnimationCurve zQuat = new AnimationCurve(zQuatKeys); AnimationCurve wQuat = new AnimationCurve(wQuatKeys); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "m_LocalRotation.x"), xQuat); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "m_LocalRotation.y"), yQuat); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "m_LocalRotation.z"), zQuat); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "m_LocalRotation.w"), wQuat); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "localEulerAngles.x"), xRot); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "localEulerAngles.y"), yRot); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "localEulerAngles.z"), zRot); clip.EnsureQuaternionContinuity(); AssetDatabase.AddObjectToAsset(clip, track.AnimatorController); AnimationClipSettings clipSettings = AnimationUtility.GetAnimationClipSettings(clip); clipSettings.loopTime = false; AnimationUtility.SetAnimationClipSettings(clip, clipSettings); AssetDatabase.SaveAssets(); FAnimationEventInspector.SetAnimationClip(animEvent, clip); return(clip); }
public static void ProcessCharacter() { // Get the file paths of the data string plist_path = EditorUtility.OpenFilePanel("Open character's config data:", "Assets", "plist"); string json_path = EditorUtility.OpenFilePanel("Open character's skeletal/animation data:", "Assets", "ExportJson"); Texture2D sprite; if (Selection.objects.Length != 1) { sprite = null; } else { sprite = Selection.activeObject as Texture2D; } if (sprite == null) { Debug.LogError("ERROR: Sprite sheet is not selected."); return; } if (plist_path == "" || json_path == "") { Debug.LogError("ERROR: Plist and/or JSON are null."); return; } // Read sprite data from the plist List <SpriteData> cutting_data = ReadPlist(plist_path); // Cut sprite data List <SpriteMetaData> sheet = CutSprite(sprite, cutting_data); // Prepare sprite atlas string atlas_source = AssetDatabase.GetAssetPath(sprite); atlas_source = atlas_source.Substring(atlas_source.LastIndexOf("/") + 1, (atlas_source.LastIndexOf(".") - atlas_source.LastIndexOf("/")) - 1); SpriteAtlas atlas = new SpriteAtlas(atlas_source); // Read data from Json file into Json string string json_content = File.ReadAllText(json_path); // Deserialize Json string into usable object data RootObject obj = JsonUtility.FromJson <RootObject>(json_content); // Create base object for armature GameObject root = new GameObject(obj.armature_data[0].name); root.tag = "Armature"; // Prepare the skeleton //List<GameObject> bones = new List<GameObject>(); List <SpriteBone> bones = new List <SpriteBone>(); // For each bone in the skeleton foreach (BoneData node in obj.armature_data[0].bone_data) { // Create a new game object, tag is set to bone GameObject g = new GameObject(node.name); g.tag = "Bone"; // If parent node is null, parent the object to the root if (node.parent == "") { g.transform.SetParent(root.transform); } else { // Get a reference to all child transforms Transform[] allChildren = root.GetComponentsInChildren <Transform>(); // For each transform foreach (Transform child in allChildren) { // Check if transform name matches parent. If so, parent the object to that transform if (child.gameObject.name == node.parent) { g.transform.SetParent(child); } } } // POSITION IS RELATIVE TO PARENT // Set the position and scale // Mathf.Rad2Deg g.transform.localPosition = new Vector2((float)node.x / scale_factor, (float)node.y / scale_factor); g.transform.localScale = new Vector3((float)node.cX, (float)node.cY, 1.0f); g.transform.localEulerAngles = new Vector3(0.0f, 0.0f, (float)(node.kY * Mathf.Rad2Deg)); int index = 0; int displayIndex = node.dI; /*if (displayIndex < 0) * displayIndex = 0;*/ // Initialize skeleton SpriteBone sb = new SpriteBone(); sb.bone = g; // Sprites need to be their own gameobjects foreach (DisplayData d in node.display_data) { // Create object GameObject s = new GameObject(d.name); s.transform.SetParent(g.transform); s.tag = "Display Data"; SkinData d_data = d.skin_data[0]; SpriteData sd = FindSpriteData(cutting_data, d.name); // Set sprite transforms if (sd != null) { s.transform.localPosition = new Vector3(((float)d_data.x) / scale_factor, ((float)d_data.y) / scale_factor); s.transform.localScale = new Vector3((float)d_data.cX, (float)d_data.cY, 1.0f); s.transform.localEulerAngles = new Vector3(0.0f, 0.0f, (float)(d_data.kY * Mathf.Rad2Deg)); // Set sprite offset GameObject o = new GameObject(index.ToString()); o.transform.SetParent(s.transform); o.tag = "Sprite"; // Set up sprite components o.AddComponent <SpriteRenderer>(); //o.GetComponent<SpriteRenderer>().sortingOrder = node.z; Sprite body_piece = atlas.getSprite(d.name); o.GetComponent <SpriteRenderer>().sprite = body_piece; // Apply sprite offset o.transform.localPosition = new Vector3(sd.offsetX / scale_factor, sd.offsetY / scale_factor, -node.z / scale_factor); o.transform.localEulerAngles = Vector3.zero; sb.displayData.Add(o); // Determine visibility if (displayIndex != index) { o.SetActive(false); } } index++; } // Add bone to the list bones.Add(sb); } // Add an animator to the root root.AddComponent <Animator>(); // Create an animator controller (ADDENDUM: MAY NOT BE NEEDED) // Loop through all animations in the JSON foreach (MovData md in obj.animation_data[0].mov_data) { // Create and name an animation clip AnimationClip anim = new AnimationClip(); anim.name = md.name; // Name and frame index of inverted bones // Change to dictionary <string, Dictionary<int, bool>> Dictionary <string, Dictionary <int, bool> > toInvert = new Dictionary <string, Dictionary <int, bool> >(); foreach (MovBoneData mbd in md.mov_bone_data) { Dictionary <int, bool> boneInv = new Dictionary <int, bool>(); int numAdded = 0; foreach (FrameData fd in mbd.frame_data) { if (fd.cX < 0 || fd.cY < 0) { boneInv.Add(fd.fi, true); numAdded++; } else { if (!boneInv.ContainsKey(fd.fi)) { boneInv.Add(fd.fi, false); } } } if (boneInv.Count > 0 && numAdded > 0) { toInvert.Add(mbd.name, boneInv); } } // Loop through all bone data foreach (MovBoneData mbd in md.mov_bone_data) { // Name of bone that needs its transform inverted //List<string> toInvert = new List<string>(); // Find the game object matching the bone SpriteBone bone = null; foreach (SpriteBone sb in bones) { if (sb.bone.name.Equals(mbd.name)) { bone = sb; } } // Prepare animation curves for animated properties AnimationCurve curve_x = new AnimationCurve(); AnimationCurve curve_y = new AnimationCurve(); AnimationCurve curve_cx = new AnimationCurve(); AnimationCurve curve_cy = new AnimationCurve(); AnimationCurve curve_ky = new AnimationCurve(); AnimationCurve[] curve_z = new AnimationCurve[bone.displayData.Count]; AnimationCurve[] curve_di = new AnimationCurve[bone.displayData.Count]; AnimationCurve[] curve_fx = new AnimationCurve[bone.displayData.Count]; AnimationCurve[] curve_fy = new AnimationCurve[bone.displayData.Count]; // Required to retain offsets AnimationCurve[] curve_zx = new AnimationCurve[bone.displayData.Count]; AnimationCurve[] curve_zy = new AnimationCurve[bone.displayData.Count]; for (int i = 0; i < bone.displayData.Count; i++) { curve_z[i] = new AnimationCurve(); curve_zx[i] = new AnimationCurve(); curve_zy[i] = new AnimationCurve(); curve_di[i] = new AnimationCurve(); curve_fx[i] = new AnimationCurve(); curve_fy[i] = new AnimationCurve(); } int previous_z = 0; // Loop through all keyframes for that bone foreach (FrameData fd in mbd.frame_data) { // Set keyframe values for position, rotation, and scale. Note that all of these are relative Keyframe px = new Keyframe((fd.fi / sample_rate), (bone.bone.transform.localPosition.x + ((float)fd.x / scale_factor))); px.tangentMode = 0; px.inTangent = 0.0f; px.outTangent = 0.0f; Keyframe py = new Keyframe((fd.fi / sample_rate), (bone.bone.transform.localPosition.y + ((float)fd.y / scale_factor))); py.tangentMode = 0; py.inTangent = 0.0f; py.outTangent = 0.0f; curve_x.AddKey(px); curve_y.AddKey(py); // Scale keyframes Keyframe kx = new Keyframe((fd.fi / sample_rate), ((float)fd.cX)); kx.tangentMode = 0; kx.inTangent = 0.0f; kx.outTangent = 0.0f; Keyframe ky = new Keyframe((fd.fi / sample_rate), ((float)fd.cY)); ky.tangentMode = 0; ky.inTangent = 0.0f; ky.outTangent = 0.0f; curve_cx.AddKey(kx); curve_cy.AddKey(ky); // This is the ONLY bug remaining. When something's supposed to be inverted, the inversion is never reset. // Inversion is also not 100%. For example, Suzy's right arm is not inverted in her idle animation // Correct inversion error Transform t = bone.bone.transform; float direction = 1.0f; while (t.transform.parent != null) { t = t.transform.parent; if (toInvert.ContainsKey(t.gameObject.name)) { // This needs to get the previous frame index if none exist if (InvertAtIndex(toInvert, fd.fi, t.gameObject.name)) { direction = -1.0f; Debug.Log("Success! - " + md.name + ": " + t.gameObject.name + " " + mbd.name); } } } // Invert rotation Keyframe ry = new Keyframe((fd.fi / sample_rate), direction * (bone.bone.transform.localEulerAngles.z + ((float)(fd.kY * Mathf.Rad2Deg)))); ry.tangentMode = 0; ry.inTangent = 0.0f; ry.outTangent = 0.0f; curve_ky.AddKey(ry); // Determine display index int displayIndex = fd.dI; for (int i = 0; i < bone.displayData.Count; i++) { // If the frame index is not one, a second keyframe will need to be set to disable "sliding" if (fd.fi > 1) { Keyframe p_zx = new Keyframe(((fd.fi - 1) / sample_rate), bone.displayData[i].transform.localPosition.x); p_zx.tangentMode = 0; p_zx.inTangent = 0.0f; p_zx.outTangent = 0.0f; Keyframe p_zy = new Keyframe(((fd.fi - 1) / sample_rate), bone.displayData[i].transform.localPosition.y); p_zy.tangentMode = 0; p_zy.inTangent = 0.0f; p_zy.outTangent = 0.0f; Keyframe p_zz = new Keyframe(((fd.fi - 1) / sample_rate), bone.displayData[i].transform.localPosition.z + (-previous_z / scale_factor)); p_zz.tangentMode = 0; p_zz.inTangent = 0.0f; p_zz.outTangent = 0.0f; curve_z[i].AddKey(p_zz); curve_zx[i].AddKey(p_zx); curve_zy[i].AddKey(p_zy); } Keyframe zx = new Keyframe((fd.fi / sample_rate), bone.displayData[i].transform.localPosition.x); zx.tangentMode = 0; zx.inTangent = 0.0f; zx.outTangent = 0.0f; Keyframe zy = new Keyframe((fd.fi / sample_rate), bone.displayData[i].transform.localPosition.y); zy.tangentMode = 0; zy.inTangent = 0.0f; zy.outTangent = 0.0f; Keyframe zz = new Keyframe((fd.fi / sample_rate), bone.displayData[i].transform.localPosition.z + (-fd.z / scale_factor)); zz.tangentMode = 0; zz.inTangent = 0.0f; zz.outTangent = 0.0f; curve_z[i].AddKey(zz); previous_z = fd.z; curve_zx[i].AddKey(zx); curve_zy[i].AddKey(zy); // Check if the current index equals the display index if (bone.displayData[i].name.Equals(displayIndex.ToString())) { Keyframe k = new Keyframe((fd.fi / sample_rate), 1.0f); k.tangentMode = 103; k.inTangent = float.PositiveInfinity; k.outTangent = float.PositiveInfinity; curve_di[i].AddKey(k); } else { Keyframe k = new Keyframe((fd.fi / sample_rate), 0.0f); k.tangentMode = 103; k.inTangent = float.PositiveInfinity; k.outTangent = float.PositiveInfinity; curve_di[i].AddKey(k); } } } // Get full name of bone string bone_name = GetCompletePath(bone.bone.transform); // Apply transform keyframes to animation clip anim.SetCurve(bone_name, typeof(Transform), "localPosition.x", curve_x); anim.SetCurve(bone_name, typeof(Transform), "localPosition.y", curve_y); anim.SetCurve(bone_name, typeof(Transform), "localScale.x", curve_cx); anim.SetCurve(bone_name, typeof(Transform), "localScale.y", curve_cy); anim.SetCurve(bone_name, typeof(Transform), "localEulerAngles.z", curve_ky); // Get full name of sprites string[] sprite_names = new string[bone.displayData.Count]; for (int i = 0; i < sprite_names.Length; i++) { sprite_names[i] = GetCompletePath(bone.displayData[i].transform); // Apply sprite keyframes to animation clip anim.SetCurve(sprite_names[i], typeof(Transform), "localPosition.x", curve_zx[i]); anim.SetCurve(sprite_names[i], typeof(Transform), "localPosition.y", curve_zy[i]); anim.SetCurve(sprite_names[i], typeof(Transform), "localPosition.z", curve_z[i]); anim.SetCurve(sprite_names[i], typeof(GameObject), "m_IsActive", curve_di[i]); } } // Apply loop AnimationClipSettings animClipSett = new AnimationClipSettings(); animClipSett.loopTime = md.lp; AnimationUtility.SetAnimationClipSettings(anim, animClipSett); string filePath = "assets/animations/" + sprite.name + "/"; // Create the anim clip if (!Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); } AssetDatabase.CreateAsset(anim, filePath + anim.name + ".anim"); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } }
private static void Compress(AnimationClip src, AnimationClip target, bool reducePrecision) { AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(src); EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(src); AnimationUtility.SetAnimationClipSettings(target, settings); float curIdx = 0; foreach (var b in bindings) { curIdx += 1f; EditorUtility.DisplayProgressBar("动画压缩", b.path, curIdx / bindings.Length); bool isPositionCurve = b.propertyName.IndexOf("Position") > -1; bool isScaleCurve = b.propertyName.IndexOf("Scale") > -1; bool isFixedPositionAndScaleNode = false; bool isFixedScaleNode = false; bool isFixedPositionNode = false; foreach (var e in _fixedPositionAndScaleNode) { if (b.path.EndsWith(e)) { isFixedPositionAndScaleNode = true; break; } } if (!isFixedPositionAndScaleNode) { foreach (var e in _fixedScaleNode) { if (b.path.EndsWith(e)) { isFixedScaleNode = true; break; } } if (!isFixedScaleNode) { foreach (var e in _fixedPositionNode) { if (b.path.EndsWith(e)) { isFixedPositionNode = true; break; } } } } if (isFixedPositionAndScaleNode) { if (isPositionCurve || isScaleCurve) { continue; } } else if (isFixedScaleNode) { if (isScaleCurve) { continue; } } else if (isFixedPositionNode) { if (isPositionCurve) { continue; } } var c = AnimationUtility.GetEditorCurve(src, b); if (reducePrecision) { ReduceFloatPrecision(c); } AnimationUtility.SetEditorCurve(target, b, c); } }
static AnimationClip BuildAnimationClip(DirectoryInfo dictorys, string name) { string animationName = dictorys.Name; //查找所有图片,因为我找的测试动画是.jpg FileInfo[] images = dictorys.GetFiles().ToList().Where(x => (x.Extension.ToLower() == ".png" || x.Extension.ToLower() == ".tga")).OrderBy(x => (TurnNumToInt(x.Name))).ToArray(); AnimationClip clip = new AnimationClip(); if (images.Length == 0) { return(clip); } EditorCurveBinding curveBinding = new EditorCurveBinding(); curveBinding.type = typeof(SpriteRenderer); curveBinding.path = ""; curveBinding.propertyName = "m_Sprite"; ObjectReferenceKeyframe[] keyFrames; Sprite sprite; //动画长度是按秒为单位,1/10就表示1秒切10张图片,根据项目的情况可以自己调节 float frameTime = 1f / 8f; // 最后补一个第一帧 // 补帧一个第一帧 if (!name.Contains("DIE") && !name.Contains("SP1") && !name.Contains("SP2")) { keyFrames = new ObjectReferenceKeyframe[images.Length + 1]; sprite = AssetDatabase.LoadAssetAtPath <Sprite>(DataPathToAssetPath(images[0].FullName).Replace("\\", "/")); keyFrames[images.Length] = new ObjectReferenceKeyframe(); keyFrames[images.Length].time = frameTime * Mathf.Max(0, (images.Length + 1 - Mathf.Pow(1.07f, images.Length))); keyFrames[images.Length].value = sprite; } else { keyFrames = new ObjectReferenceKeyframe[images.Length]; } for (int i = 0; i < images.Length; i++) { sprite = AssetDatabase.LoadAssetAtPath <Sprite>(DataPathToAssetPath(images[i].FullName).Replace("\\", "/")); keyFrames[i] = new ObjectReferenceKeyframe(); keyFrames[i].time = frameTime * Mathf.Max(0, (i + 1 - Mathf.Pow(1.07f, i))); keyFrames[i].value = sprite; } //动画帧率,30比较合适 clip.frameRate = 30; //if( fullname.Contains( "Airman" ) ) //{ // if( !name.Contains( "Dth" ) ) // { // EditorCurveBinding curve = new EditorCurveBinding(); // curve.type = typeof( Transform ); // curve.path = ""; // curve.propertyName = "m_LocalPosition.y"; // AnimationCurve curveAnime = new AnimationCurve(); // curveAnime.AddKey( 0f, 2f ); // AnimationUtility.SetEditorCurve( clip, curve, curveAnime ); // } // else // { // EditorCurveBinding curve = new EditorCurveBinding(); // curve.type = typeof( Transform ); // curve.path = ""; // curve.propertyName = "m_LocalPosition.y"; // float lastKey = keyFrames[images.Length - 1].time + frameTime * Mathf.Max( 0, ( 6 + 1 - Mathf.Pow( 1.07f, 6 ) ) ); // AnimationCurve curveAnime = new AnimationCurve(); // curveAnime.AddKey( 0f, 2f ); // curveAnime.AddKey( keyFrames[images.Length - 1].time/2f, 2.5f ); // curveAnime.AddKey( lastKey, 0f ); // AnimationUtility.SetEditorCurve( clip, curve, curveAnime ); // AnimationEvent evt = new AnimationEvent(); // evt.time = keyFrames[keyFrames.Length - 1].time; // evt.functionName = "OnDie"; // AnimationUtility.SetAnimationEvents( clip, new AnimationEvent[] { evt } ); // } //} // 方向,5,7,翻转 if (name.Substring(name.Length - 1) == "1" || name.Substring(name.Length - 1) == "2" || name.Substring(name.Length - 1) == "3") { EditorCurveBinding curve = new EditorCurveBinding(); curve.type = typeof(Transform); curve.path = ""; curve.propertyName = "m_LocalScale.x"; AnimationCurve curveAnime = new AnimationCurve(); curveAnime.AddKey(0f, -1f); AnimationUtility.SetEditorCurve(clip, curve, curveAnime); curve = new EditorCurveBinding(); curve.type = typeof(Transform); curve.path = ""; curve.propertyName = "m_LocalScale.y"; curveAnime = new AnimationCurve(); curveAnime.AddKey(0f, 1f); AnimationUtility.SetEditorCurve(clip, curve, curveAnime); curve = new EditorCurveBinding(); curve.type = typeof(Transform); curve.path = ""; curve.propertyName = "m_LocalScale.z"; curveAnime = new AnimationCurve(); curveAnime.AddKey(0f, 1f); AnimationUtility.SetEditorCurve(clip, curve, curveAnime); } else { EditorCurveBinding curve = new EditorCurveBinding(); curve.type = typeof(Transform); curve.path = ""; curve.propertyName = "m_LocalScale.x"; AnimationCurve curveAnime = new AnimationCurve(); curveAnime.AddKey(0f, 1f); AnimationUtility.SetEditorCurve(clip, curve, curveAnime); curve = new EditorCurveBinding(); curve.type = typeof(Transform); curve.path = ""; curve.propertyName = "m_LocalScale.y"; curveAnime = new AnimationCurve(); curveAnime.AddKey(0f, 1f); AnimationUtility.SetEditorCurve(clip, curve, curveAnime); curve = new EditorCurveBinding(); curve.type = typeof(Transform); curve.path = ""; curve.propertyName = "m_LocalScale.z"; curveAnime = new AnimationCurve(); curveAnime.AddKey(0f, 1f); AnimationUtility.SetEditorCurve(clip, curve, curveAnime); } SerializedObject serializedClip = new SerializedObject(clip); AnimationClipSettings clipSettings = new AnimationClipSettings(serializedClip.FindProperty("m_AnimationClipSettings")); if (name.Contains("ATTACK")) { clipSettings.loopTime = true; serializedClip.ApplyModifiedProperties(); // 龙的攻击从第一帧开始 AnimationEvent evt = new AnimationEvent(); if (name.Contains("Monster11")) { evt.time = 0; } else { // evt.time = keyFrames [images.Length - 1].time - frameTime * Mathf.Max (0, (2 + 1 - Mathf.Pow (1.07f, 2))); evt.time = keyFrames [images.Length - 1].time + 0.5f; } evt.functionName = "OnAttack"; AnimationUtility.SetAnimationEvents(clip, new AnimationEvent[] { evt }); } else if (name.Contains("DIE")) { clipSettings.loopTime = false; serializedClip.ApplyModifiedProperties(); AnimationEvent evt = new AnimationEvent(); evt.time = keyFrames[keyFrames.Length - 1].time; evt.functionName = "OnDie"; AnimationUtility.SetAnimationEvents(clip, new AnimationEvent[] { evt }); } else if (name.Contains("SP1")) { clipSettings.loopTime = true; serializedClip.ApplyModifiedProperties(); AnimationEvent evt = new AnimationEvent(); evt.time = keyFrames[keyFrames.Length - 1].time; evt.functionName = "OnSP1"; AnimationUtility.SetAnimationEvents(clip, new AnimationEvent[] { evt }); } else if (name.Contains("SP2")) { clipSettings.loopTime = true; serializedClip.ApplyModifiedProperties(); AnimationEvent evt = new AnimationEvent(); evt.time = keyFrames[keyFrames.Length - 1].time; evt.functionName = "OnSP2"; AnimationUtility.SetAnimationEvents(clip, new AnimationEvent[] { evt }); } else { clipSettings.loopTime = true; serializedClip.ApplyModifiedProperties(); } AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames); return(clip); }
// GUI Layout for 2D Animation creation function void OnGUI() { if (selectedObject != null) { //Display the object's name that the animations will be created from EditorGUILayout.LabelField("Animations for " + selectedObject.name); Object[] sprites = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(selectedObject)); int spriteCount = sprites.Length; //Display the number of sprites in the sheet EditorGUILayout.LabelField("Number of Sprites: " + spriteCount); //create a space EditorGUILayout.Separator(); //Get the name for the animation controller controllerName = EditorGUILayout.TextField("Controller Name", controllerName); //Determine how many animations there will be numAnimations = EditorGUILayout.IntField("How many animations?", numAnimations); //Loop through each theoretical animation for (int i = 0; i < numAnimations; i++) { //Determine a name for the animation animationNames [i] = EditorGUILayout.TextField("Animation Name", animationNames [i]); //Start a section where the items will be displayed horizontally instead of vertically. EditorGUILayout.BeginHorizontal(); //Determine the start frame for the animation startFrames [i] = EditorGUILayout.IntField("Start Frame", startFrames [i]); //Determine the end frame for the animation endFrames [i] = EditorGUILayout.IntField("End Frame", endFrames [i]); //End the section where the previous items are displayed horizontally instead of vertically EditorGUILayout.EndHorizontal(); //Start a section where the following items will be displayed horizontally instead of vertically. EditorGUILayout.BeginHorizontal(); //Determine the frame rate for the animation clipFrameRate [i] = EditorGUILayout.FloatField("Frame Rate", clipFrameRate [i]); //Determine the space between each keyframe clipTimeBetween [i] = EditorGUILayout.FloatField("Frame Spacing", clipTimeBetween [i]); //End the section where the previous items are displayed horizontally instead of vertically EditorGUILayout.EndHorizontal(); //Start a section where the following items will be displayed horizontally instead of vertically. EditorGUILayout.BeginHorizontal(); //Create a checkbox to determine if this animation should loop loop [i] = EditorGUILayout.Toggle("Loop", loop [i]); //Create a checkbox to determine if this animation should ping-pong pingPong [i] = EditorGUILayout.Toggle("Ping Pong", pingPong [i]); //End the section where the previous items are displayed horizontally instead of vertically EditorGUILayout.EndHorizontal(); //Create a space EditorGUILayout.Separator(); } //Create a button with the label "Create" if (GUILayout.Button("Create")) { //if the button has been pressed //create an animator controller UnityEditor.Animations.AnimatorController controller = UnityEditor.Animations.AnimatorController.CreateAnimatorControllerAtPath("Assets/" + controllerName + ".controller"); for (int j = 0; j < numAnimations; j++) { //if the end frame of an iteration is greater than the total number of frames, a prompt is generated to see //if the user wishes to change it to the last available frame. Otherwise the iteration is skipped if (endFrames[j] > spriteCount) { if (EditorUtility.DisplayDialog("Caution", "End Frame of animation" + j + " exceeds last frame available.\n" + "Change to last frame?", "Yes", "No")) { endFrames[j] = spriteCount; } else { continue; } } //create animation clip AnimationClip tempClip = CreateClip(selectedObject, animationNames [j], startFrames [j], endFrames [j], clipFrameRate [j], clipTimeBetween [j], pingPong [j]); //determine if the clip should loop if (loop [j]) { //set the loop on the clip to true AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(tempClip); settings.loopTime = true; settings.loopBlend = true; AnimationUtility.SetAnimationClipSettings(tempClip, settings); } controller.AddMotion(tempClip); } CreatePrefab(controller); } } }
static void SetAnimationSettings (AnimationClip clip, AnimationClipSettings settings) { AnimationUtility.SetAnimationClipSettings(clip, settings); }
private GeneratedClip[] CreateAnimationClips(Settings settings, AsepriteFileInfo aseInfo, List <Sprite> sprites) { SpriteSheetData sheetData = aseInfo.spriteSheetData; var clipInfoLookup = new Dictionary <string, List <(Sprite sprite, int duration)> >(); foreach (SpriteSheetData.FrameTag frameTag in sheetData.meta.frameTags) { var framesInfo = new List <(Sprite sprite, int duration)>(); for (int i = frameTag.from; i <= frameTag.to; i++) { SpriteSheetData.Frame frame = sheetData.frames[i]; Sprite sprite = sprites.Find((s) => { return(frame.filename.Equals(s.name)); }); if (ReferenceEquals(sprite, null)) { continue; } int duration = frame.duration; framesInfo.Add((sprite, duration)); } string clipName = $"aseprite_{aseInfo.title}_{frameTag.name}"; clipInfoLookup.Add(clipName, framesInfo); } var clips = new List <AnimationClip>(clipInfoLookup.Count); foreach (var kvp in clipInfoLookup) { string clipName = kvp.Key; List <(Sprite sprite, int duration)> clipInfo = kvp.Value; AnimationClip clip = new AnimationClip(); clip.wrapMode = WrapMode.Loop; clip.name = clipName; int[] frameTimesInMilliseconds = new int[clipInfo.Count]; for (int iFrame = 0; iFrame < frameTimesInMilliseconds.Length; iFrame++) { frameTimesInMilliseconds[iFrame] = clipInfo[iFrame].duration; } clip.frameRate = ClipSettings.CalculateAutoFrameRate(settings.MaxSampleRate, frameTimesInMilliseconds); AnimationClipSettings currentClipSettings = AnimationUtility.GetAnimationClipSettings(clip); currentClipSettings.loopTime = true; AnimationUtility.SetAnimationClipSettings(clip, currentClipSettings); var spriteBinding = new EditorCurveBinding(); spriteBinding.type = typeof(SpriteRenderer); spriteBinding.path = clipSettings.spriteRendererPath; spriteBinding.propertyName = "m_Sprite"; int clipLength = clipInfo.Count; var keyframes = new List <ObjectReferenceKeyframe>(clipLength + 1); float currentDuration = 0f; for (int i = 0; i < clipLength; i++) { var keyframe = new ObjectReferenceKeyframe(); keyframe.value = clipInfo[i].sprite; keyframe.time = currentDuration; keyframes.Add(keyframe); // Divide frame duration by 1000 because it is specified by Aseprite in milliseconds. float keyDuration = clipInfo[i].duration / 1000f; currentDuration += keyDuration; // TODO: Miscreant: Do these calculations before any sec/msec conversions for more precision // Tack on a duplicate of the last keyframe to ensure the last frame gets its full duration if (i == clipLength - 1 && keyDuration > (1.0f / clip.frameRate)) { keyframe = new ObjectReferenceKeyframe(); // The last frame will persist for one full sample, so subtract that from the current time keyframe.time = currentDuration - (1.0f / clip.frameRate); keyframe.value = clipInfo[i].sprite; keyframes.Add(keyframe); } } AnimationUtility.SetObjectReferenceCurve( clip, spriteBinding, keyframes.ToArray() ); clips.Add(clip); } return(FinalizeAnimationClips(aseInfo, clips)); }
static void SetAnimationSettings (AnimationClip clip, AnimationClipSettings settings) { #if UNITY_5 AnimationUtility.SetAnimationClipSettings(clip, settings); #else MethodInfo methodInfo = typeof(AnimationUtility).GetMethod("SetAnimationClipSettings", BindingFlags.Static | BindingFlags.NonPublic); methodInfo.Invoke(null, new object[] { clip, settings }); EditorUtility.SetDirty(clip); #endif }
public static AnimationClip BuildAnimationClip(DirectoryInfo dictorys, bool hasAngle = false, bool hasType = false) { string animationName = dictorys.Name; string parentName = Directory.GetParent(dictorys.FullName).Name; if (hasAngle) { animationName = Directory.GetParent(dictorys.FullName).Name + "_" + dictorys.Name; parentName = Directory.GetParent(Directory.GetParent(dictorys.FullName).FullName).Name; } if (hasType) { parentName = Directory.GetParent(Directory.GetParent(Directory.GetParent(dictorys.FullName).FullName).FullName).Name; parentName += "/" + Directory.GetParent(Directory.GetParent(dictorys.FullName).FullName).Name; } //查找所有图片,因为我找的测试动画是.jpg FileInfo [] images = dictorys.GetFiles("*.png"); AnimationClip clip = new AnimationClip(); // AnimationUtility.SetAnimationType(clip,ModelImporterAnimationType.Generic); EditorCurveBinding curveBinding = new EditorCurveBinding(); curveBinding.type = typeof(Image); curveBinding.path = ""; curveBinding.propertyName = "m_Sprite"; ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[images.Length]; //动画长度是按秒为单位,1/10就表示1秒切10张图片,根据项目的情况可以自己调节 float frameTime = 1 / 10f; for (int i = 0; i < images.Length; i++) { Sprite sprite = AssetDatabase.LoadAssetAtPath <Sprite>(DataPathToAssetPath(images[i].FullName)); keyFrames[i] = new ObjectReferenceKeyframe(); keyFrames[i].time = frameTime * i; keyFrames[i].value = sprite; } //动画帧率,30比较合适 clip.frameRate = 30; //有些动画我希望天生它就动画循环 if (animationName.IndexOf("idle") >= 0 || animationName.IndexOf("run") >= 0) { //设置idle文件为循环动画 SerializedObject serializedClip = new SerializedObject(clip); AnimationClipSettings clipSettings = new AnimationClipSettings(serializedClip.FindProperty("m_AnimationClipSettings")); clipSettings.loopTime = true; serializedClip.ApplyModifiedProperties(); } string path = AnimationPath + "/" + parentName + "/" + animationName + ".anim"; CheckPath(path, true); AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames); AssetDatabase.CreateAsset(clip, path); AssetDatabase.SaveAssets(); return(clip); }
public override void Read(AssetReader reader) { base.Read(reader); if (IsReadClassIDToTrack(reader.Version, reader.Flags)) { m_classIDToTrack = new Dictionary <int, PPtr <BaseAnimationTrack> >(); m_classIDToTrack.Read(reader); m_childTracks = reader.ReadAssetArray <ChildTrack>(); } if (IsReadAnimationType(reader.Version)) { AnimationType = (AnimationType)reader.ReadInt32(); } if (IsReadLegacy(reader.Version)) { Legacy = reader.ReadBoolean(); } if (IsReadCompressed(reader.Version)) { Compressed = reader.ReadBoolean(); } if (IsReadUseHightQualityCurve(reader.Version)) { UseHightQualityCurve = reader.ReadBoolean(); } if (IsAlignCompressed(reader.Version)) { reader.AlignStream(AlignType.Align4); } if (IsReadCurves(reader.Version)) { m_rotationCurves = reader.ReadAssetArray <QuaternionCurve>(); } if (IsReadCompressedRotationCurves(reader.Version)) { m_compressedRotationCurves = reader.ReadAssetArray <CompressedAnimationCurve>(); } if (IsReadEulerCurves(reader.Version)) { m_eulerCurves = reader.ReadAssetArray <Vector3Curve>(); } if (IsReadCurves(reader.Version)) { m_positionCurves = reader.ReadAssetArray <Vector3Curve>(); m_scaleCurves = reader.ReadAssetArray <Vector3Curve>(); m_floatCurves = reader.ReadAssetArray <FloatCurve>(); } if (IsReadPPtrCurves(reader.Version)) { m_PPtrCurves = reader.ReadAssetArray <PPtrCurve>(); } if (IsReadSampleRate(reader.Version)) { SampleRate = reader.ReadSingle(); } if (IsReadWrapMode(reader.Version)) { WrapMode = (WrapMode)reader.ReadInt32(); } if (IsReadBounds(reader.Version)) { Bounds.Read(reader); } if (IsReadMuscleClip(reader.Version, reader.Flags)) { MuscleClipSize = reader.ReadUInt32(); MuscleClip = new ClipMuscleConstant(); MuscleClip.Read(reader); } if (IsReadClipBindingConstant(reader.Version)) { ClipBindingConstant.Read(reader); } #if UNIVERSAL if (IsReadAnimationClipSettings(reader.Version, reader.Flags)) { AnimationClipSettings = new AnimationClipSettings(); AnimationClipSettings.Read(reader); } if (IsReadEditorCurves(reader.Version, reader.Flags)) { m_editorCurves = reader.ReadAssetArray <FloatCurve>(); m_eulerEditorCurves = reader.ReadAssetArray <FloatCurve>(); } #endif if (IsReadHasGenericRootTransform(reader.Version, reader.Flags)) { HasGenericRootTransform = reader.ReadBoolean(); } if (IsReadHasMotionFloatCurves(reader.Version, reader.Flags)) { HasMotionFloatCurves = reader.ReadBoolean(); } #if UNIVERSAL if (IsReadGenerateMotionCurves(reader.Version, reader.Flags)) { GenerateMotionCurves = reader.ReadBoolean(); } #endif if (IsReadHasGenericRootTransform(reader.Version, reader.Flags)) { reader.AlignStream(AlignType.Align4); } if (IsReadEvents(reader.Version)) { m_events = reader.ReadAssetArray <AnimationEvent>(); } if (IsAlign(reader.Version)) { reader.AlignStream(AlignType.Align4); } #if UNIVERSAL if (IsReadRuntimeEvents(reader.Version, reader.Flags)) { m_runetimeEvents = reader.ReadAssetArray <AnimationEvent>(); } #endif }
public static AnimationClip BuildAnimationClip(string imageDirect, string animPath) { string animationName = Path.GetFileNameWithoutExtension(imageDirect); string textureName = imageDirect.Replace(".plist", ".png").Replace(Application.dataPath, "Assets"); var importer = AssetImporter.GetAtPath(textureName) as TextureImporter; var imgResources = AssetDatabase.LoadAllAssetsAtPath(textureName); List <Sprite> sprites = new List <Sprite>(); foreach (var sprite in imgResources) { if (sprite is Sprite) { sprites.Add(sprite as Sprite); } } AnimationClip clip = new AnimationClip(); //AnimationUtility.SetAnimationType(clip, ModelImporterAnimationType.Generic); EditorCurveBinding spriteBinding = new EditorCurveBinding(); spriteBinding.type = typeof(SpriteRenderer); spriteBinding.path = ""; spriteBinding.propertyName = "m_Sprite"; ObjectReferenceKeyframe[] spriteFrames = new ObjectReferenceKeyframe[sprites.Count]; AnimationCurve curve = new AnimationCurve(); //动画长度是按秒为单位,1/10就表示1秒切10张图片,根据项目的情况可以自己调节 float frameTime = 1 / 10f; for (int i = 0; i < sprites.Count; i++) { spriteFrames[i] = new ObjectReferenceKeyframe(); spriteFrames[i].time = frameTime * i; spriteFrames[i].value = sprites[i]; var flipFrames = new Keyframe(); flipFrames.time = frameTime * i; if (sprites[i].pivot.x > sprites[i].pivot.y) { flipFrames.value = 0; } else { flipFrames.value = 90; } flipFrames.inTangent = 0; flipFrames.outTangent = 0; curve.AddKey(flipFrames); } //动画帧率,30比较合适 clip.frameRate = 30; //有些动画我希望天生它就动画循环 if (animationName.IndexOf("idle") >= 0) { //设置idle文件为循环动画 SerializedObject serializedClip = new SerializedObject(clip); AnimationClipSettings clipSettings = new AnimationClipSettings(); clipSettings.loopTime = true; serializedClip.ApplyModifiedProperties(); } AnimationUtility.SetObjectReferenceCurve(clip, spriteBinding, spriteFrames); clip.SetCurve("", typeof(Transform), "localEulerAnglesRaw.z", curve); AssetDatabase.CreateAsset(clip, textureName.Replace(".png", ".anim")); AssetDatabase.SaveAssets(); return(clip); }
private List <AnimationClip> GenerateAnimations(AseFile aseFile, List <Sprite> sprites) { List <AnimationClip> res = new List <AnimationClip>(); var animations = aseFile.GetAnimations(); if (animations.Length <= 0) { return(res); } var metadatas = aseFile.GetMetaData(Settings.spritePivot, Settings.pixelsPerUnit); int index = 0; foreach (var animation in animations) { var path = directoryName + "/" + fileName + "_" + animation.TagName + ".anim"; AnimationClip clip = AssetDatabase.LoadAssetAtPath <AnimationClip>(path); if (clip == null) { clip = new AnimationClip(); AssetDatabase.CreateAsset(clip, path); clip.wrapMode = GetDefaultWrapMode(animation.TagName); } else { AnimationClipSettings animSettings = AnimationUtility.GetAnimationClipSettings(clip); clip.wrapMode = animSettings.loopTime ? WrapMode.Loop : WrapMode.Once; } clip.name = fileName + "_" + animation.TagName; clip.frameRate = 25; EditorCurveBinding editorBinding = new EditorCurveBinding(); editorBinding.path = ""; editorBinding.propertyName = "m_Sprite"; switch (Settings.bindType) { case AseAnimationBindType.SpriteRenderer: editorBinding.type = typeof(SpriteRenderer); break; case AseAnimationBindType.UIImage: editorBinding.type = typeof(Image); break; } // plus last frame to keep the duration int length = animation.FrameTo - animation.FrameFrom + 1; ObjectReferenceKeyframe[] spriteKeyFrames = new ObjectReferenceKeyframe[length + 1]; Dictionary <string, AnimationCurve> transformCurveX = new Dictionary <string, AnimationCurve>(), transformCurveY = new Dictionary <string, AnimationCurve>(); float time = 0; int from = (animation.Animation != LoopAnimation.Reverse) ? animation.FrameFrom : animation.FrameTo; int step = (animation.Animation != LoopAnimation.Reverse) ? 1 : -1; int keyIndex = from; for (int i = 0; i < length; i++) { if (i >= length) { keyIndex = from; } ObjectReferenceKeyframe frame = new ObjectReferenceKeyframe(); frame.time = time; frame.value = sprites[keyIndex]; time += aseFile.Frames[keyIndex].FrameDuration / 1000f; spriteKeyFrames[i] = frame; foreach (var metadata in metadatas) { if (metadata.Type == MetaDataType.TRANSFORM && metadata.Transforms.ContainsKey(keyIndex)) { var childTransform = metadata.Args[0]; if (!transformCurveX.ContainsKey(childTransform)) { transformCurveX[childTransform] = new AnimationCurve(); transformCurveY[childTransform] = new AnimationCurve(); } var pos = metadata.Transforms[keyIndex]; transformCurveX[childTransform].AddKey(i, pos.x); transformCurveY[childTransform].AddKey(i, pos.y); } } keyIndex += step; } float frameTime = 1f / clip.frameRate; ObjectReferenceKeyframe lastFrame = new ObjectReferenceKeyframe(); lastFrame.time = time - frameTime; lastFrame.value = sprites[keyIndex - step]; spriteKeyFrames[spriteKeyFrames.Length - 1] = lastFrame; foreach (var metadata in metadatas) { if (metadata.Type == MetaDataType.TRANSFORM && metadata.Transforms.ContainsKey(keyIndex - step)) { var childTransform = metadata.Args[0]; var pos = metadata.Transforms[keyIndex - step]; transformCurveX[childTransform].AddKey(spriteKeyFrames.Length - 1, pos.x); transformCurveY[childTransform].AddKey(spriteKeyFrames.Length - 1, pos.y); } } AnimationUtility.SetObjectReferenceCurve(clip, editorBinding, spriteKeyFrames); foreach (var childTransform in transformCurveX.Keys) { EditorCurveBinding bindingX = new EditorCurveBinding { path = childTransform, type = typeof(Transform), propertyName = "m_LocalPosition.x" }, bindingY = new EditorCurveBinding { path = childTransform, type = typeof(Transform), propertyName = "m_LocalPosition.y" }; MakeConstant(transformCurveX[childTransform]); AnimationUtility.SetEditorCurve(clip, bindingX, transformCurveX[childTransform]); MakeConstant(transformCurveY[childTransform]); AnimationUtility.SetEditorCurve(clip, bindingY, transformCurveY[childTransform]); } AnimationClipSettings clipSettings = AnimationUtility.GetAnimationClipSettings(clip); clipSettings.loopTime = (clip.wrapMode == WrapMode.Loop); AnimationUtility.SetAnimationClipSettings(clip, clipSettings); EditorUtility.SetDirty(clip); index++; res.Add(clip); } return(res); }
public override void Read(AssetReader reader) { base.Read(reader); if (HasClassIDToTrack(reader.Version, reader.Flags)) { ClassIDToTrack = new Dictionary <int, PPtr <BaseAnimationTrack> >(); ClassIDToTrack.Read(reader); ChildTracks = reader.ReadAssetArray <ChildTrack>(); } if (HasAnimationType(reader.Version)) { AnimationType = (AnimationType)reader.ReadInt32(); } if (HasLegacy(reader.Version)) { Legacy = reader.ReadBoolean(); } if (HasCompressed(reader.Version)) { Compressed = reader.ReadBoolean(); } if (HasUseHightQualityCurve(reader.Version)) { UseHightQualityCurve = reader.ReadBoolean(); } if (IsAlignCompressed(reader.Version)) { reader.AlignStream(); } if (HasCurves(reader.Version)) { RotationCurves = reader.ReadAssetArray <QuaternionCurve>(); } if (HasCompressedRotationCurves(reader.Version)) { CompressedRotationCurves = reader.ReadAssetArray <CompressedAnimationCurve>(); } if (HasEulerCurves(reader.Version)) { EulerCurves = reader.ReadAssetArray <Vector3Curve>(); } if (HasCurves(reader.Version)) { PositionCurves = reader.ReadAssetArray <Vector3Curve>(); ScaleCurves = reader.ReadAssetArray <Vector3Curve>(); FloatCurves = reader.ReadAssetArray <FloatCurve>(); } if (HasPPtrCurves(reader.Version)) { PPtrCurves = reader.ReadAssetArray <PPtrCurve>(); } if (HasSampleRate(reader.Version)) { SampleRate = reader.ReadSingle(); } if (HasWrapMode(reader.Version)) { WrapMode = (WrapMode)reader.ReadInt32(); } if (HasBounds(reader.Version)) { Bounds.Read(reader); } if (HasMuscleClip(reader.Version, reader.Flags)) { MuscleClipSize = reader.ReadUInt32(); MuscleClip = new ClipMuscleConstant(); MuscleClip.Read(reader); } if (HasClipBindingConstant(reader.Version)) { ClipBindingConstant.Read(reader); } #if UNIVERSAL if (HasAnimationClipSettings(reader.Version, reader.Flags)) { AnimationClipSettings = new AnimationClipSettings(); AnimationClipSettings.Read(reader); } if (HasEditorCurves(reader.Version, reader.Flags)) { EditorCurves = reader.ReadAssetArray <FloatCurve>(); EulerEditorCurves = reader.ReadAssetArray <FloatCurve>(); } #endif if (HasHasGenericRootTransform(reader.Version, reader.Flags)) { HasGenericRootTransform = reader.ReadBoolean(); } if (HasHasMotionFloatCurves(reader.Version, reader.Flags)) { HasMotionFloatCurves = reader.ReadBoolean(); } #if UNIVERSAL if (HasGenerateMotionCurves(reader.Version, reader.Flags)) { GenerateMotionCurves = reader.ReadBoolean(); } if (HasIsEmpty(reader.Version, reader.Flags)) { IsEmpty = reader.ReadBoolean(); } #endif if (HasHasGenericRootTransform(reader.Version, reader.Flags)) { reader.AlignStream(); } if (HasEvents(reader.Version)) { Events = reader.ReadAssetArray <AnimationEvent>(); } if (IsAlign(reader.Version)) { reader.AlignStream(); } #if UNIVERSAL if (HasRuntimeEvents(reader.Version, reader.Flags)) { RunetimeEvents = reader.ReadAssetArray <AnimationEvent>(); } #endif }
// Use this for initialization public void Run() { Debug.Log("Baking the following animations...."); List <AnimationClip> animClips = GetAnimationLengths(); bones = GetListBones(); for (int j = 0; j < animClips.Count; j++) { newClip = new AnimationClip(); //AnimatorStateInfo state = transform.GetComponent<Animator> ().GetCurrentAnimatorStateInfo(0); //float leng = state.length; clip = animClips[j]; float leng = clip.length; //Debug.Log(leng); curvePosX.Clear(); curvePosY.Clear(); curvePosZ.Clear(); curveRotX.Clear(); curveRotY.Clear(); curveRotZ.Clear(); curveRotW.Clear(); curveScaleX.Clear(); curveScaleY.Clear(); curveScaleZ.Clear(); for (int i = 0; i < bones.Count; i++) { curvePosX.Add(new AnimationCurve()); curvePosY.Add(new AnimationCurve()); curvePosZ.Add(new AnimationCurve()); curveRotX.Add(new AnimationCurve()); curveRotY.Add(new AnimationCurve()); curveRotZ.Add(new AnimationCurve()); curveRotW.Add(new AnimationCurve()); curveScaleX.Add(new AnimationCurve()); curveScaleY.Add(new AnimationCurve()); curveScaleZ.Add(new AnimationCurve()); } //Time.timeScale = 0.0f; //float _lastRealTime = 0.0f; frameTime = 1f / clip.frameRate; float numFramesInAnim = (leng * clip.frameRate); for (int i = 0; i < numFramesInAnim + 1; i++) { AnimationMode.StartAnimationMode(); AnimationMode.BeginSampling(); AnimationMode.SampleAnimationClip(transform.gameObject, clip, i * frameTime); transform.GetComponent <Puppet2D_GlobalControl>().Run(); foreach (Transform bone in bones) { bakeAnimation(bone, i * frameTime); } } AnimationMode.EndSampling(); AnimationMode.StopAnimationMode(); newClip.name = clip.name + "_Baked"; newClip.wrapMode = clip.wrapMode; AnimationClipSettings animClipSettings = new AnimationClipSettings(); animClipSettings.stopTime = clip.length; AnimationUtility.SetAnimationType(newClip, ModelImporterAnimationType.Generic); SaveAnimationClip(newClip); AnimationEvent[] events = new AnimationEvent[1]; events[0] = new AnimationEvent(); events[0].time = clip.length; AnimationUtility.SetAnimationEvents(newClip, events); AnimationEvent[] events2 = new AnimationEvent[0]; AnimationUtility.SetAnimationEvents(newClip, events2); /*AnimationClipCurveData[] curveDatas = AnimationUtility.GetAllCurves(newClip, true); * for (int i=0; i<curveDatas.Length; i++) * { * AnimationUtility.SetEditorCurve( * newClip, * curveDatas[i].path, * curveDatas[i].type, * curveDatas[i].propertyName, * curveDatas[i].curve * ); * }*/ AssetDatabase.SaveAssets(); UnityEngine.Object[] newSelection = new UnityEngine.Object[Selection.objects.Length + 1]; for (int i = 0; i < Selection.objects.Length; i++) { newSelection [i] = Selection.objects [i]; } newSelection [newSelection.Length - 1] = newClip; Selection.objects = newSelection; /* * transform.GetComponent<Animator> ().StartRecording (0); * * * Invoke ("stopRecording", leng); */ } Debug.Log("Finished Baking."); }
// Use this for initialization public void Run() { Debug.Log("Baking the following animations...."); List<AnimationClip> animClips = GetAnimationLengths(); bones = GetListBones () ; for (int j = 0; j < animClips.Count; j++) { newClip = new AnimationClip(); //AnimatorStateInfo state = transform.GetComponent<Animator> ().GetCurrentAnimatorStateInfo(0); //float leng = state.length; clip = animClips[j]; float leng = clip.length; //Debug.Log(leng); curvePosX.Clear();curvePosY.Clear();curvePosZ.Clear(); curveRotX.Clear(); curveRotY.Clear();curveRotZ.Clear();curveRotW.Clear(); curveScaleX.Clear();curveScaleY.Clear();curveScaleZ.Clear(); for (int i = 0; i < bones.Count; i++) { curvePosX.Add (new AnimationCurve()); curvePosY.Add (new AnimationCurve()); curvePosZ.Add (new AnimationCurve()); curveRotX.Add (new AnimationCurve()); curveRotY.Add (new AnimationCurve()); curveRotZ.Add (new AnimationCurve()); curveRotW.Add (new AnimationCurve()); curveScaleX.Add (new AnimationCurve()); curveScaleY.Add (new AnimationCurve()); curveScaleZ.Add (new AnimationCurve()); } //Time.timeScale = 0.0f; //float _lastRealTime = 0.0f; frameTime = 1f/clip.frameRate; float numFramesInAnim = (leng*clip.frameRate); for(int i =0;i<numFramesInAnim+1;i++) { AnimationMode.StartAnimationMode(); AnimationMode.BeginSampling(); AnimationMode.SampleAnimationClip (transform.gameObject, clip, i*frameTime); transform.GetComponent<Puppet2D_GlobalControl>().Run(); foreach(Transform bone in bones) bakeAnimation(bone,i*frameTime); } AnimationMode.EndSampling(); AnimationMode.StopAnimationMode(); newClip.name = clip.name + "_Baked"; newClip.wrapMode = clip.wrapMode; AnimationClipSettings animClipSettings = new AnimationClipSettings(); animClipSettings.stopTime = clip.length; #if UNITY_5_1 newClip.legacy = false; #else AnimationUtility.SetAnimationType(newClip, ModelImporterAnimationType.Generic); #endif SaveAnimationClip( newClip ); AnimationEvent[] events = new AnimationEvent[1]; events[0] = new AnimationEvent(); events[0].time = clip.length; AnimationUtility.SetAnimationEvents(newClip, events); AnimationEvent[] events2 = new AnimationEvent[0]; AnimationUtility.SetAnimationEvents(newClip, events2); /*AnimationClipCurveData[] curveDatas = AnimationUtility.GetAllCurves(newClip, true); for (int i=0; i<curveDatas.Length; i++) { AnimationUtility.SetEditorCurve( newClip, curveDatas[i].path, curveDatas[i].type, curveDatas[i].propertyName, curveDatas[i].curve ); }*/ AssetDatabase.SaveAssets(); UnityEngine.Object[] newSelection = new UnityEngine.Object[Selection.objects.Length + 1]; for (int i = 0; i < Selection.objects.Length; i++) { newSelection [i] = Selection.objects [i]; } newSelection [newSelection.Length - 1] = newClip; Selection.objects = newSelection; /* transform.GetComponent<Animator> ().StartRecording (0); Invoke ("stopRecording", leng); */ } Debug.Log("Finished Baking."); }
void OnGUI() { if (GUILayout.Button("Get Sprite Editor Data")) { GetTextureToSpriteData(); } GUILayout.Label("Name"); sTxt = GUILayout.TextField(sTxt); GUILayout.Label("Sprite Folder"); Folder = EditorGUILayout.ObjectField(Folder, typeof(Object)); bLoop = GUILayout.Toggle(bLoop, "Loop"); string sPath = ""; bUseTagName = GUILayout.Toggle(bUseTagName, "Use Tag Name"); nFrameRate = int.Parse(GUILayout.TextField(nFrameRate.ToString())); for (int i = 0; i < FolderList.Count; i++) { GUILayout.BeginHorizontal(); GUILayout.Label(AssetDatabase.GetAssetPath(FolderList[i].PackingObject) + " / " + FolderList[i].PackingTag + " / " + FolderList[i].Loop); if (GUILayout.Button("X", GUILayout.Width(20))) { FolderList.RemoveAt(i); } bool bEachLoop = FolderList[i].Loop; bEachLoop = GUILayout.Toggle(bEachLoop, "Loop"); if (bEachLoop != FolderList[i].Loop) { FolderList[i].Loop = bEachLoop; } GUILayout.EndHorizontal(); } if (GUILayout.Button("Add") || EnterDown) { EnterDown = false; if (sTxt != string.Empty) { CreateSpriteAnimationStruct ttss = new CreateSpriteAnimationStruct(); if (bUseTagName) { sPath = AssetDatabase.GetAssetPath(Folder); string[] files = Directory.GetFiles(sPath, "*.png"); TextureImporter importer = TextureImporter.GetAtPath(files[0]) as TextureImporter; sTxt = importer.spritePackingTag; } ttss.PackingTag = sTxt; ttss.PackingObject = Folder; ttss.Loop = bLoop; FolderList.Add(ttss); } } if (GUILayout.Button("Create")) { if (Folder == null || sTxt == "") { return; } for (int j = 0; j < FolderList.Count; j++) { sPath = AssetDatabase.GetAssetPath(FolderList[j].PackingObject); string[] files = Directory.GetFiles(sPath, "*.png"); List <Sprite> listSprite = new List <Sprite>(); for (int i = 0; i < files.Length; i++) { //string sName = files[i].Split('\'') listSprite.Add(AssetDatabase.LoadAssetAtPath <Sprite>(files[i])); } Animation anim = new Animation(); AnimationClip clip = new AnimationClip(); AnimationClipSettings sts = AnimationUtility.GetAnimationClipSettings(clip); clip.frameRate = nFrameRate; if (FolderList[j].Loop) { clip.wrapMode = WrapMode.Loop; sts.loopTime = true; AnimationUtility.SetAnimationClipSettings(clip, sts); } sTxt = FolderList[j].PackingTag; //System.IO. EditorCurveBinding spriteBinding = EditorCurveBinding.PPtrCurve("", typeof(UnityEngine.UI.Image), "m_Sprite"); //spriteBinding.type = typeof(SpriteRenderer); //spriteBinding.path = ""; //spriteBinding.propertyName = "m_Sprite"; ObjectReferenceKeyframe[] spriteKeyFrames = new ObjectReferenceKeyframe[listSprite.Count]; Debug.Log(sPath + "/" + " :: " + files.Length + " listSprite.Length] :: " + listSprite.Count); for (int i = 0; i < (listSprite.Count); i++) { spriteKeyFrames[i] = new ObjectReferenceKeyframe(); spriteKeyFrames[i].time = i / clip.frameRate; spriteKeyFrames[i].value = listSprite[i]; } AnimationUtility.SetObjectReferenceCurve(clip, spriteBinding, spriteKeyFrames); //clip.setc //폴더명 CreatedAnimation AssetDatabase.CreateAsset(clip, "assets/CreatedAnimation/" + sTxt + ".anim"); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); EditorUtility.DisplayProgressBar("Progress Bar", "Now : " + (j + 1).ToString() + " Changing.....", (float)j / (float)FolderList.Count); } EditorUtility.ClearProgressBar(); } }
private void Export() { List <AnimationClip> clips = new List <AnimationClip>(); foreach (Direction direction in billboard.directions) { AnimationClip clip = new AnimationClip(); clip.name = billboard.name + "_" + direction.angleStart + "_" + direction.angleEnd; clip.wrapMode = billboard.loop ? WrapMode.Loop : WrapMode.Default; AnimationClipSettings settings = new AnimationClipSettings(); settings.loopTime = billboard.loop; AnimationUtility.SetAnimationClipSettings(clip, settings); clip.ClearCurves(); if (direction.sprites.Count != 0) { //Set Keyframes EditorCurveBinding curveBinding = new EditorCurveBinding(); curveBinding.type = typeof(SpriteRenderer); curveBinding.path = ""; curveBinding.propertyName = "m_Sprite"; ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[direction.sprites.Count]; for (int i = 0; i < direction.sprites.Count; i++) { Sprite sprite = direction.sprites[i]; keyFrames[i] = new ObjectReferenceKeyframe(); keyFrames[i].time = i * billboard.waitTime; keyFrames[i].value = sprite; } AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames); //Set FlipX AnimationCurve curve = direction.invertSprites ? AnimationCurve.Constant(0, (direction.sprites.Count) * billboard.waitTime, 1) : AnimationCurve.Constant(0, direction.sprites.Count * billboard.waitTime, 0); clip.SetCurve("", typeof(SpriteRenderer), "m_FlipX", curve); } clips.Add(clip); } string path = EditorUtility.SaveFilePanelInProject("Export Animations", "animations", "", "Export Animations"); if (path == "") { return; } foreach (AnimationClip clip in clips) { string clipPath = path + clip.name + ".anim"; AssetDatabase.CreateAsset(clip, clipPath); } AssetDatabase.SaveAssets(); AnimatorController controller = null; AnimatorStateMachine rootStateMachine = null; switch (animator) { case null: controller = AnimatorController.CreateAnimatorControllerAtPath(path + ".controller"); controller.AddParameter("angle", AnimatorControllerParameterType.Float); break; default: controller = animator; break; } rootStateMachine = controller.layers[0].stateMachine; AnimatorStateMachine stateMachine = rootStateMachine.AddStateMachine(billboard.name, Vector3.zero); AnimatorState baseState = stateMachine.AddState("Base", new Vector3(0, 600)); for (int x = 0; x < billboard.directions.Count; x++) { Direction direction = billboard.directions[x]; string name = billboard.name + "_" + direction.angleStart + "_" + direction.angleEnd; AnimationClip clip = AssetDatabase.LoadAssetAtPath <AnimationClip>(path + name + ".anim"); float radians = (((float)x / (billboard.directions.Count)) * 360f) * Mathf.Deg2Rad; var cos = Mathf.Cos(radians); var sin = Mathf.Sin(radians); Vector3 pos = new Vector3(0, 600); pos += new Vector3(cos, sin) * 300; AnimatorState state = stateMachine.AddState(name, pos); state.motion = clip; var transition = AddTransition(state, baseState); transition.AddCondition(AnimatorConditionMode.Greater, direction.angleEnd, "angle"); transition = AddTransition(state, baseState); transition.AddCondition(AnimatorConditionMode.Less, direction.angleStart, "angle"); transition = AddTransition(baseState, state); transition.AddCondition(AnimatorConditionMode.Greater, direction.angleStart, "angle"); transition.AddCondition(AnimatorConditionMode.Less, direction.angleEnd, "angle"); } AssetDatabase.SaveAssets(); }
/// <summary> /// Instantiates an <see cref="AnimationClip"/>. /// </summary> /// <returns>The instantiated clip on success; <see langword="null"/> otherwise.</returns> public AnimationClip ToAnimationClip() { // Check béziers restriction flag. if (!Meta.AreBeziersRestricted) { Debug.LogWarning("Béziers are not restricted and curves might be off. Please export motions from Cubism in restricted mode for perfect match."); } // Create animation clip. var animationClip = new AnimationClip { frameRate = Meta.Fps }; // Convert curves. for (var i = 0; i < Curves.Length; ++i) { var curve = Curves[i]; var relativePath = string.Empty; var type = default(Type); var propertyName = string.Empty; var animationCurve = new AnimationCurve(ConvertCurveSegmentsToKeyframes(curve.Segments)); // Create model binding. if (curve.Target == "Model") { // Bind opacity. if (curve.Id == "Opacity") { relativePath = string.Empty; propertyName = "Opacity"; type = typeof(CubismRenderController); } // Bind eye-blink. else if (curve.Id == "EyeBlink") { relativePath = string.Empty; propertyName = "EyeOpening"; type = typeof(CubismEyeBlinkController); } // Bind lip-sync. else if (curve.Id == "LipSync") { relativePath = string.Empty; propertyName = "MouthOpening"; type = typeof(CubismMouthController); } } // Create parameter binding. else if (curve.Target == "Parameter") { relativePath = "Parameters/" + curve.Id; propertyName = "Value"; type = typeof(CubismParameter); } // Create part opacity binding. else if (curve.Target == "PartOpacity") { relativePath = "Parts/" + curve.Id; propertyName = "Opacity"; type = typeof(CubismPart); } #if UNITY_EDITOR var curveBinding = new EditorCurveBinding { path = relativePath, propertyName = propertyName, type = type }; AnimationUtility.SetEditorCurve(animationClip, curveBinding, animationCurve); #else animationClip.SetCurve(relativePath, type, propertyName, animationCurve); #endif } #if UNITY_EDITOR // Apply settings. var animationClipSettings = new AnimationClipSettings { loopTime = Meta.Loop, stopTime = Meta.Duration }; AnimationUtility.SetAnimationClipSettings(animationClip, animationClipSettings); #endif return(animationClip); }
// public method #endregion "public method" #region "private method" // private method private void _ConvertAnim(string newClipAssetPath) { // 0. prepare if (!m_Animator.isHuman) { Dbg.LogWarn("MuscleClipConverterEditor._ConvertAnim: Need to change to Humanoid rig first!"); return; } m_SMR = m_Animator.GetComponentInChildren <SkinnedMeshRenderer>(); if (m_SMR == null) { Dbg.LogWarn("MuscleClipConverterEditor._ConvertAnim: failed to find SMR under {0}", m_Animator.name); return; } m_Animator.Update(0); #if !U5 var ainfos = m_Animator.GetCurrentAnimationClipState(0); //only effect after Update is called #else var ainfos = m_Animator.GetCurrentAnimatorClipInfo(0); //only effect after Update is called #endif AnimationClip clip = ainfos[0].clip; AnimationClipSettings clipSetting = AnimationUtility.GetAnimationClipSettings(clip); //{//debug // var bindings = AnimationUtility.GetCurveBindings(clip); // foreach( var b in bindings) // { // Dbg.Log("path: {0}, prop: {1}", b.path, b.propertyName); // } //} Transform animatorTr = m_Animator.transform; Transform hipsBone = null; CurveDict curveDict = new CurveDict(); float SAMPLE_RATE = clip.frameRate; float clipLen = clip.length; Matrix4x4 animatorInitW2LMat = animatorTr.worldToLocalMatrix; Matrix4x4 hipsInitW2LMat = Matrix4x4.identity; List <Transform> boneLst = new List <Transform>(); for (HumanBodyBones boneIdx = 0; boneIdx < HumanBodyBones.LastBone; ++boneIdx) { Transform tr = m_Animator.GetBoneTransform(boneIdx); //Dbg.Log("Map: {0}->{1}", boneIdx, tr); if (tr != null) { boneLst.Add(tr); if (boneIdx == HumanBodyBones.Hips) { hipsBone = tr; hipsInitW2LMat = hipsBone.parent.worldToLocalMatrix; //clipSetting.level = -hipsBone.localPosition.y; // set Y offset clipSetting.keepOriginalPositionY = false; //use RootNode position } } } Transform[] bones = boneLst.ToArray(); // init curves for each bone for (int idx = 0; idx < bones.Length; ++idx) { Transform oneBone = bones[idx]; string trPath = AnimationUtility.CalculateTransformPath(oneBone, animatorTr); var curves = new _Curves(); curves.relPath = trPath; curveDict.Add(oneBone, curves); } // init rootmotion curve { var curves = new _Curves(); curveDict.Add(animatorTr, curves); } AnimatorStateInfo curStateInfo = m_Animator.GetCurrentAnimatorStateInfo(0); float nt = curStateInfo.normalizedTime; m_Animator.Update(-nt * clipLen); //revert to 0 time { // 1. bake animation info into curve on all bones transform float time = 0f; float deltaTime = 1f / (SAMPLE_RATE); for (; time <= clipLen || Mathf.Approximately(time, clipLen); ) { //Dbg.Log("nt = {0}", m_Animator.GetCurrentAnimatorStateInfo(0).normalizedTime); // bone for (int idx = 0; idx < bones.Length; ++idx) { Transform oneBone = bones[idx]; _Curves curves = curveDict[oneBone]; if (oneBone == hipsBone) { continue; //skip the HipsBone. This is to add rootMotion matrix on hips, so Legacy is right } Vector3 pos = oneBone.localPosition; Quaternion rot = oneBone.localRotation; curves.X.AddKey(time, rot.x); curves.Y.AddKey(time, rot.y); curves.Z.AddKey(time, rot.z); curves.W.AddKey(time, rot.w); curves.PX.AddKey(time, pos.x); curves.PY.AddKey(time, pos.y); curves.PZ.AddKey(time, pos.z); } // root motion process { { //on Animator transform Vector3 pos = /*animatorTr.localPosition*/ animatorTr.position; Vector3 fwd = animatorTr.forward; Vector3 up = animatorTr.up; _Curves rootMotionCurves = curveDict[animatorTr]; Vector3 lpos = animatorInitW2LMat.MultiplyPoint(pos); Vector3 lfwd = animatorInitW2LMat.MultiplyVector(fwd); Vector3 lup = animatorInitW2LMat.MultiplyVector(up); Quaternion rot = Quaternion.LookRotation(lfwd, lup); rootMotionCurves.X.AddKey(time, rot.x); rootMotionCurves.Y.AddKey(time, rot.y); rootMotionCurves.Z.AddKey(time, rot.z); rootMotionCurves.W.AddKey(time, rot.w); rootMotionCurves.PX.AddKey(time, lpos.x); rootMotionCurves.PY.AddKey(time, lpos.y); rootMotionCurves.PZ.AddKey(time, lpos.z); } { //on hips transform if (hipsBone != null) { Vector3 pos = hipsBone.position; Vector3 fwd = hipsBone.forward; Vector3 up = hipsBone.up; _Curves hipsCurves = curveDict[hipsBone]; Vector3 lpos = hipsInitW2LMat.MultiplyPoint(pos); Vector3 lfwd = hipsInitW2LMat.MultiplyVector(fwd); Vector3 lup = hipsInitW2LMat.MultiplyVector(up); //Dbg.Log("time: {0}, lpos: {1}", time, lpos.ToString("F2")); Quaternion rot = Quaternion.LookRotation(lfwd, lup); hipsCurves.X.AddKey(time, rot.x); hipsCurves.Y.AddKey(time, rot.y); hipsCurves.Z.AddKey(time, rot.z); hipsCurves.W.AddKey(time, rot.w); hipsCurves.PX.AddKey(time, lpos.x); hipsCurves.PY.AddKey(time, lpos.y); hipsCurves.PZ.AddKey(time, lpos.z); } } } if (!Mathf.Approximately(time + deltaTime, clipLen)) { m_Animator.Update(deltaTime); time += deltaTime; } else { m_Animator.Update(deltaTime - 0.005f); //keep it in the range, if go beyond, something bad could happen time += deltaTime - 0.005f; } } } //end of 1. { // 2. set animation clip and store in AssetDatabase AnimationClip newClip = new AnimationClip(); newClip.frameRate = SAMPLE_RATE; newClip.localBounds = clip.localBounds; // set bone curves for (var ie = curveDict.GetEnumerator(); ie.MoveNext();) { var curves = ie.Current.Value; if (ie.Current.Key == animatorTr) { //root motion newClip.SetCurve(curves.relPath, typeof(Animator), "MotionT.x", curves.PX); newClip.SetCurve(curves.relPath, typeof(Animator), "MotionT.y", curves.PY); newClip.SetCurve(curves.relPath, typeof(Animator), "MotionT.z", curves.PZ); newClip.SetCurve(curves.relPath, typeof(Animator), "MotionQ.x", curves.X); newClip.SetCurve(curves.relPath, typeof(Animator), "MotionQ.y", curves.Y); newClip.SetCurve(curves.relPath, typeof(Animator), "MotionQ.z", curves.Z); newClip.SetCurve(curves.relPath, typeof(Animator), "MotionQ.w", curves.W); } else { newClip.SetCurve(curves.relPath, typeof(Transform), "localRotation.x", curves.X); newClip.SetCurve(curves.relPath, typeof(Transform), "localRotation.y", curves.Y); newClip.SetCurve(curves.relPath, typeof(Transform), "localRotation.z", curves.Z); newClip.SetCurve(curves.relPath, typeof(Transform), "localRotation.w", curves.W); newClip.SetCurve(curves.relPath, typeof(Transform), "localPosition.x", curves.PX); newClip.SetCurve(curves.relPath, typeof(Transform), "localPosition.y", curves.PY); newClip.SetCurve(curves.relPath, typeof(Transform), "localPosition.z", curves.PZ); } } // 2.1 copy the unmapped curves to new clip( not mapped by Muscle clip ) _CopyOtherCurves(newClip, clip); // some setting work newClip.EnsureQuaternionContinuity(); #if !U5 AnimationUtility.SetAnimationType(newClip, m_AnimType); RCall.CallMtd("UnityEditor.AnimationUtility", "SetAnimationClipSettings", null, newClip, clipSetting); #else if (m_AnimType == ModelImporterAnimationType.Legacy) { newClip.legacy = true; } AnimationUtility.SetAnimationClipSettings(newClip, clipSetting); #endif EUtil.SaveAnimClip(newClip, newClipAssetPath); EUtil.ShowNotification("Converted to: " + m_AnimType + (hipsBone != null ? ("\nroot=" + AnimationUtility.CalculateTransformPath(hipsBone, animatorTr)) : ""), 3f ); } //end of 2. // 3. clean job curveDict = null; AssetDatabase.SaveAssets(); Dbg.Log("Converted: {0}", newClipAssetPath); }