diff --git a/Assets/VRM10/Editor/VrmAnimationMenu.cs b/Assets/VRM10/Editor/VrmAnimationMenu.cs index d8a8230d9..b56b7370e 100644 --- a/Assets/VRM10/Editor/VrmAnimationMenu.cs +++ b/Assets/VRM10/Editor/VrmAnimationMenu.cs @@ -1,5 +1,10 @@ +using System; +using System.Collections.Generic; using System.IO; +using UniGLTF; +using UniHumanoid; using UnityEditor; +using UnityEngine; namespace UniVRM10 { @@ -10,7 +15,7 @@ namespace UniVRM10 var path = EditorUtility.OpenFilePanel("select bvh", null, "bvh"); if (!string.IsNullOrEmpty(path)) { - var bytes = VrmAnimationExporter.BvhToVrmAnimation(path); + var bytes = BvhToVrmAnimation(path); var dst = EditorUtility.SaveFilePanel("write vrma", Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path), @@ -21,5 +26,87 @@ namespace UniVRM10 } } } + + static Transform GetParentBone(Dictionary map, Vrm10HumanoidBones bone) + { + while (true) + { + if (bone == Vrm10HumanoidBones.Hips) + { + break; + } + var parentBone = Vrm10HumanoidBoneSpecification.GetDefine(bone).ParentBone.Value; + var unityParentBone = Vrm10HumanoidBoneSpecification.ConvertToUnityBone(parentBone); + if (map.TryGetValue(unityParentBone, out var found)) + { + return found; + } + bone = parentBone; + } + + // hips has no parent + return null; + } + + static byte[] BvhToVrmAnimation(string path) + { + var bvh = new BvhImporterContext(); + bvh.Parse(path, File.ReadAllText(path)); + bvh.Load(); + + var data = new ExportingGltfData(); + using var exporter = new VrmAnimationExporter( + data, new GltfExportSettings()); + exporter.Prepare(bvh.Root.gameObject); + + exporter.Export((VrmAnimationExporter vrma) => + { + // + // setup + // + var map = new Dictionary(); + var animator = bvh.Root.GetComponent(); + foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones))) + { + if (bone == HumanBodyBones.LastBone) + { + continue; + } + var t = animator.GetBoneTransform(bone); + if (t == null) + { + continue; + } + map.Add(bone, t); + } + + vrma.SetPositionBoneAndParent(map[HumanBodyBones.Hips], bvh.Root.transform); + + foreach (var kv in map) + { + var vrmBone = Vrm10HumanoidBoneSpecification.ConvertFromUnityBone(kv.Key); + var parent = GetParentBone(map, vrmBone) ?? bvh.Root.transform; + vrma.AddRotationBoneAndParent(kv.Key, kv.Value, parent); + } + + // + // get data + // + var animation = bvh.Root.gameObject.GetComponent(); + var clip = animation.clip; + var state = animation[clip.name]; + + var time = default(TimeSpan); + for (int i = 0; i < bvh.Bvh.FrameCount; ++i, time += bvh.Bvh.FrameTime) + { + state.time = (float)time.TotalSeconds; + animation.Sample(); + vrma.AddFrame(time); + } + + }); + + return data.ToGlbBytes(); + } } } diff --git a/Assets/VRM10/Runtime/IO/VrmAnimationExporter.cs b/Assets/VRM10/Runtime/IO/VrmAnimationExporter.cs index 3bc90a87e..864dd9a5f 100644 --- a/Assets/VRM10/Runtime/IO/VrmAnimationExporter.cs +++ b/Assets/VRM10/Runtime/IO/VrmAnimationExporter.cs @@ -41,6 +41,10 @@ namespace UniVRM10 } } PositionExporter m_position; + public void SetPositionBoneAndParent(Transform bone, Transform parent) + { + m_position = new PositionExporter(bone, parent); + } class RotationExporter { @@ -62,29 +66,12 @@ namespace UniVRM10 } } readonly Dictionary m_rotations = new(); - - static Transform GetParentBone(Dictionary map, Vrm10HumanoidBones bone) + public void AddRotationBoneAndParent(HumanBodyBones bone, Transform transform, Transform parent) { - while (true) - { - if (bone == Vrm10HumanoidBones.Hips) - { - break; - } - var parentBone = Vrm10HumanoidBoneSpecification.GetDefine(bone).ParentBone.Value; - var unityParentBone = Vrm10HumanoidBoneSpecification.ConvertToUnityBone(parentBone); - if (map.TryGetValue(unityParentBone, out var found)) - { - return found; - } - bone = parentBone; - } - - // hips has no parent - return null; + m_rotations.Add(bone, new RotationExporter(transform, parent)); } - private void AddFrame(TimeSpan time) + public void AddFrame(TimeSpan time) { m_times.Add((float)time.TotalSeconds); m_position.Add(); @@ -94,53 +81,11 @@ namespace UniVRM10 } } - public void Export(BvhImporterContext bvh) + public void Export(Action addFrames) { base.Export(new RuntimeTextureSerializer()); - // - // setup - // - var map = new Dictionary(); - var animator = bvh.Root.GetComponent(); - foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones))) - { - if (bone == HumanBodyBones.LastBone) - { - continue; - } - var t = animator.GetBoneTransform(bone); - if (t == null) - { - continue; - } - map.Add(bone, t); - } - - m_position = new PositionExporter(map[HumanBodyBones.Hips], - bvh.Root.transform); - - foreach (var kv in map) - { - var vrmBone = Vrm10HumanoidBoneSpecification.ConvertFromUnityBone(kv.Key); - var parent = GetParentBone(map, vrmBone) ?? bvh.Root.transform; - m_rotations.Add(kv.Key, new RotationExporter(kv.Value, parent)); - } - - // - // get data - // - var animation = bvh.Root.gameObject.GetComponent(); - var clip = animation.clip; - var state = animation[clip.name]; - - var time = default(TimeSpan); - for (int i = 0; i < bvh.Bvh.FrameCount; ++i, time += bvh.Bvh.FrameTime) - { - state.time = (float)time.TotalSeconds; - animation.Sample(); - AddFrame(time); - } + addFrames(this); // // export @@ -201,24 +146,10 @@ namespace UniVRM10 } // VRMC_vrm_animation - var vrmAnimation = VrmAnimationUtil.Create(map, names); + var vrmAnimation = VrmAnimationUtil.Create(m_rotations.ToDictionary(kv => kv.Key, kv => kv.Value.Node), names); UniGLTF.Extensions.VRMC_vrm_animation.GltfSerializer.SerializeTo( ref _data.Gltf.extensions , vrmAnimation); } - - public static byte[] BvhToVrmAnimation(string path) - { - var bvh = new BvhImporterContext(); - bvh.Parse(path, File.ReadAllText(path)); - bvh.Load(); - - var data = new ExportingGltfData(); - using var exporter = new VrmAnimationExporter( - data, new GltfExportSettings()); - exporter.Prepare(bvh.Root.gameObject); - exporter.Export(bvh); - return data.ToGlbBytes(); - } } }