mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-13 22:09:53 -05:00
VrmAnimationExporter
This commit is contained in:
parent
b9293f0c14
commit
60c79b5e7a
|
|
@ -26,6 +26,7 @@ namespace UniGLTF
|
|||
{ typeof(Vector2), new ComponentVec(glComponentType.FLOAT, 2) },
|
||||
{ typeof(Vector3), new ComponentVec(glComponentType.FLOAT, 3) },
|
||||
{ typeof(Vector4), new ComponentVec(glComponentType.FLOAT, 4) },
|
||||
{ typeof(Quaternion), new ComponentVec(glComponentType.FLOAT, 4) },
|
||||
{ typeof(UShort4), new ComponentVec(glComponentType.UNSIGNED_SHORT, 4) },
|
||||
{ typeof(Matrix4x4), new ComponentVec(glComponentType.FLOAT, 16) },
|
||||
{ typeof(Color), new ComponentVec(glComponentType.FLOAT, 4) },
|
||||
|
|
|
|||
|
|
@ -6,10 +6,14 @@ namespace UniVRM10
|
|||
{
|
||||
private const string UserMenuPrefix = VRMVersion.MENU;
|
||||
private const string DevelopmentMenuPrefix = VRMVersion.MENU + "/Development";
|
||||
private const string ExperimentalMenuPrefix = VRMVersion.MENU + "/Experimental";
|
||||
|
||||
[MenuItem(UserMenuPrefix + "/Export VRM-1.0", priority = 1)]
|
||||
private static void OpenExportDialog() => VRM10ExportDialog.Open();
|
||||
|
||||
[MenuItem(ExperimentalMenuPrefix + "/Convert BVH to VRM-Animation", priority = 100)]
|
||||
private static void ConvertVrmAnimation() => VrmAnimationMenu.BvhToVrmAnimationMenu();
|
||||
|
||||
#if VRM_DEVELOP
|
||||
[MenuItem(UserMenuPrefix + "/VRM1 Window", false, 2)]
|
||||
private static void OpenWindow() => VRM10Window.Open();
|
||||
|
|
|
|||
25
Assets/VRM10/Editor/VrmAnimationMenu.cs
Normal file
25
Assets/VRM10/Editor/VrmAnimationMenu.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using System.IO;
|
||||
using UnityEditor;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
internal static class VrmAnimationMenu
|
||||
{
|
||||
public static void BvhToVrmAnimationMenu()
|
||||
{
|
||||
var path = EditorUtility.OpenFilePanel("select bvh", null, "bvh");
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
var bytes = VrmAnimationExporter.BvhToVrmAnimation(path);
|
||||
var dst = EditorUtility.SaveFilePanel("write vrma",
|
||||
Path.GetDirectoryName(path),
|
||||
Path.GetFileNameWithoutExtension(path),
|
||||
"vrma");
|
||||
if (!string.IsNullOrEmpty(dst))
|
||||
{
|
||||
File.WriteAllBytes(dst, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/VRM10/Editor/VrmAnimationMenu.cs.meta
Normal file
11
Assets/VRM10/Editor/VrmAnimationMenu.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7cd670e43db7e7f42a210eb10f5da2c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
209
Assets/VRM10/Runtime/IO/VrmAnimationExporter.cs
Normal file
209
Assets/VRM10/Runtime/IO/VrmAnimationExporter.cs
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UniGLTF;
|
||||
using UniHumanoid;
|
||||
using UnityEngine;
|
||||
using VRMShaders;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
public class VrmAnimationExporter : gltfExporter
|
||||
{
|
||||
public VrmAnimationExporter(
|
||||
ExportingGltfData data,
|
||||
GltfExportSettings settings)
|
||||
: base(data, settings) { }
|
||||
|
||||
// private (INormalizedPoseProvider, ITPoseProvider) m_controlRig;
|
||||
readonly List<float> m_times = new();
|
||||
|
||||
class PositionExporter
|
||||
{
|
||||
public List<Vector3> Values = new();
|
||||
public Transform Node;
|
||||
readonly Transform m_root;
|
||||
|
||||
public PositionExporter(Transform bone, Transform root)
|
||||
{
|
||||
Node = bone;
|
||||
m_root = root;
|
||||
}
|
||||
|
||||
public void Add()
|
||||
{
|
||||
Values.Add(m_root.worldToLocalMatrix.MultiplyPoint(Node.position));
|
||||
}
|
||||
}
|
||||
PositionExporter m_position;
|
||||
|
||||
class RotationExporter
|
||||
{
|
||||
public List<Quaternion> Values = new();
|
||||
readonly Transform Node;
|
||||
public Transform m_parent;
|
||||
|
||||
public RotationExporter(Transform bone, Transform parent)
|
||||
{
|
||||
Node = bone;
|
||||
m_parent = parent;
|
||||
}
|
||||
|
||||
public void Add()
|
||||
{
|
||||
Values.Add(Quaternion.Inverse(m_parent.rotation) * Node.rotation);
|
||||
}
|
||||
}
|
||||
readonly Dictionary<HumanBodyBones, RotationExporter> m_rotations = new();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private void AddFrame(TimeSpan time)
|
||||
{
|
||||
m_times.Add((float)time.TotalSeconds);
|
||||
m_position.Add();
|
||||
foreach (var kv in m_rotations)
|
||||
{
|
||||
kv.Value.Add();
|
||||
}
|
||||
}
|
||||
|
||||
public void Export(BvhImporterContext bvh)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
// export
|
||||
//
|
||||
var gltfAnimation = new glTFAnimation
|
||||
{
|
||||
};
|
||||
_data.Gltf.animations.Add(gltfAnimation);
|
||||
|
||||
// time values
|
||||
var input = _data.ExtendBufferAndGetAccessorIndex(m_times.ToArray());
|
||||
|
||||
{
|
||||
var output = _data.ExtendBufferAndGetAccessorIndex(m_position.Values.ToArray());
|
||||
var sampler = gltfAnimation.samplers.Count;
|
||||
gltfAnimation.samplers.Add(new glTFAnimationSampler
|
||||
{
|
||||
input = input,
|
||||
output = output,
|
||||
interpolation = "LINEAR",
|
||||
});
|
||||
|
||||
gltfAnimation.channels.Add(new glTFAnimationChannel
|
||||
{
|
||||
sampler = sampler,
|
||||
target = new glTFAnimationTarget
|
||||
{
|
||||
node = Nodes.IndexOf(m_position.Node),
|
||||
path = "translation",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var kv in m_rotations)
|
||||
{
|
||||
var output = _data.ExtendBufferAndGetAccessorIndex(kv.Value.Values.ToArray());
|
||||
var sampler = gltfAnimation.samplers.Count;
|
||||
gltfAnimation.samplers.Add(new glTFAnimationSampler
|
||||
{
|
||||
input = input,
|
||||
output = output,
|
||||
interpolation = "LINEAR",
|
||||
});
|
||||
|
||||
gltfAnimation.channels.Add(new glTFAnimationChannel
|
||||
{
|
||||
sampler = sampler,
|
||||
target = new glTFAnimationTarget
|
||||
{
|
||||
node = Nodes.IndexOf(m_position.Node),
|
||||
path = "rotation",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/VRM10/Runtime/IO/VrmAnimationExporter.cs.meta
Normal file
11
Assets/VRM10/Runtime/IO/VrmAnimationExporter.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9ec9e478ed511fa478a5935aa08b36c8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue
Block a user