BvhAnimationClip.cs
4.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UniHumanoid
{
public static class BvhAnimation
{
class CurveSet
{
BvhNode Node;
Func<float, float, float, Quaternion> EulerToRotation;
public CurveSet(BvhNode node)
{
Node = node;
}
public ChannelCurve PositionX;
public ChannelCurve PositionY;
public ChannelCurve PositionZ;
public Vector3 GetPosition(int i)
{
return new Vector3(
PositionX.Keys[i],
PositionY.Keys[i],
PositionZ.Keys[i]);
}
public ChannelCurve RotationX;
public ChannelCurve RotationY;
public ChannelCurve RotationZ;
public Quaternion GetRotation(int i)
{
if (EulerToRotation == null)
{
EulerToRotation = Node.GetEulerToRotation();
}
return EulerToRotation(
RotationX.Keys[i],
RotationY.Keys[i],
RotationZ.Keys[i]
);
}
static void AddCurve(Bvh bvh, AnimationClip clip, ChannelCurve ch, float scaling)
{
if (ch == null) return;
var pathWithProp = default(Bvh.PathWithProperty);
bvh.TryGetPathWithPropertyFromChannel(ch, out pathWithProp);
var curve = new AnimationCurve();
for (int i = 0; i < bvh.FrameCount; ++i)
{
var time = (float)(i * bvh.FrameTime.TotalSeconds);
var value = ch.Keys[i] * scaling;
curve.AddKey(time, value);
}
clip.SetCurve(pathWithProp.Path, typeof(Transform), pathWithProp.Property, curve);
}
public void AddCurves(Bvh bvh, AnimationClip clip, float scaling)
{
AddCurve(bvh, clip, PositionX, -scaling);
AddCurve(bvh, clip, PositionY, scaling);
AddCurve(bvh, clip, PositionZ, scaling);
var pathWithProp = default(Bvh.PathWithProperty);
bvh.TryGetPathWithPropertyFromChannel(RotationX, out pathWithProp);
// rotation
var curveX = new AnimationCurve();
var curveY = new AnimationCurve();
var curveZ = new AnimationCurve();
var curveW = new AnimationCurve();
for (int i = 0; i < bvh.FrameCount; ++i)
{
var time = (float)(i * bvh.FrameTime.TotalSeconds);
var q = GetRotation(i).ReverseX();
curveX.AddKey(time, q.x);
curveY.AddKey(time, q.y);
curveZ.AddKey(time, q.z);
curveW.AddKey(time, q.w);
}
clip.SetCurve(pathWithProp.Path, typeof(Transform), "localRotation.x", curveX);
clip.SetCurve(pathWithProp.Path, typeof(Transform), "localRotation.y", curveY);
clip.SetCurve(pathWithProp.Path, typeof(Transform), "localRotation.z", curveZ);
clip.SetCurve(pathWithProp.Path, typeof(Transform), "localRotation.w", curveW);
}
}
public static AnimationClip CreateAnimationClip(Bvh bvh, float scaling)
{
var clip = new AnimationClip();
clip.legacy = true;
var curveMap = new Dictionary<BvhNode, CurveSet>();
int j = 0;
foreach (var node in bvh.Root.Traverse())
{
var set = new CurveSet(node);
curveMap[node] = set;
for (int i = 0; i < node.Channels.Length; ++i, ++j)
{
var curve = bvh.Channels[j];
switch (node.Channels[i])
{
case Channel.Xposition: set.PositionX = curve; break;
case Channel.Yposition: set.PositionY = curve; break;
case Channel.Zposition: set.PositionZ = curve; break;
case Channel.Xrotation: set.RotationX = curve; break;
case Channel.Yrotation: set.RotationY = curve; break;
case Channel.Zrotation: set.RotationZ = curve; break;
default: throw new Exception();
}
}
}
foreach (var set in curveMap)
{
set.Value.AddCurves(bvh, clip, scaling);
}
clip.EnsureQuaternionContinuity();
return clip;
}
}
}