separate bvh from VrmAnimationExporter

This commit is contained in:
ousttrue 2023-06-19 17:07:50 +09:00
parent 16ff381cdc
commit a4cfc4ebdb
2 changed files with 98 additions and 80 deletions

View File

@ -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<HumanBodyBones, Transform> 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<HumanBodyBones, Transform>();
var animator = bvh.Root.GetComponent<Animator>();
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<Animation>();
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();
}
}
}

View File

@ -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<HumanBodyBones, RotationExporter> m_rotations = new();
static Transform GetParentBone(Dictionary<HumanBodyBones, Transform> 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<VrmAnimationExporter> addFrames)
{
base.Export(new RuntimeTextureSerializer());
//
// setup
//
var map = new Dictionary<HumanBodyBones, Transform>();
var animator = bvh.Root.GetComponent<Animator>();
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<Animation>();
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();
}
}
}