static Animation LoadAnimation(string name, Bvh.Bvh bvh, Model model, float scalingFactor) { var animation = new Animation(name); Dictionary <string, BvhNodeCurves> pathMap = new Dictionary <string, BvhNodeCurves>(); for (int i = 0; i < bvh.Channels.Length; ++i) { var channel = bvh.Channels[i]; if (!bvh.TryGetPathWithPropertyFromChannel(channel, out Bvh.Bvh.PathWithProperty prop)) { throw new Exception(); } if (!pathMap.TryGetValue(prop.Path, out BvhNodeCurves curves)) { curves = new BvhNodeCurves(); pathMap.Add(prop.Path, curves); } curves.Set(prop.Property, channel); } // setup time var timeBytes = new byte[Marshal.SizeOf(typeof(float)) * bvh.FrameCount]; var timeSpan = SpanLike.Wrap <Single>(new ArraySegment <byte>(timeBytes)); var now = 0.0; for (int i = 0; i < timeSpan.Length; ++i, now += bvh.FrameTime.TotalSeconds) { timeSpan[i] = (float)now; } var times = new BufferAccessor(new ArraySegment <byte>(timeBytes), AccessorValueType.FLOAT, AccessorVectorType.SCALAR, bvh.FrameCount); foreach (var(key, nodeCurve) in pathMap) { var node = Model.GetNode(model.Root, key); var bvhNode = GetNode(bvh.Root, key); var curve = new NodeAnimation(); if (nodeCurve.LocalPositionX != null) { var values = new byte[Marshal.SizeOf(typeof(Vector3)) * nodeCurve.LocalPositionX.Keys.Length]; var span = SpanLike.Wrap <Vector3>(new ArraySegment <byte>(values)); for (int i = 0; i < nodeCurve.LocalPositionX.Keys.Length; ++i) { span[i] = new Vector3 { X = nodeCurve.LocalPositionX.Keys[i] * scalingFactor, Y = nodeCurve.LocalPositionY.Keys[i] * scalingFactor, Z = nodeCurve.LocalPositionZ.Keys[i] * scalingFactor, }; } var sampler = new CurveSampler { In = times, Out = new BufferAccessor(new ArraySegment <byte>(values), AccessorValueType.FLOAT, AccessorVectorType.VEC3, span.Length) }; curve.Curves.Add(AnimationPathType.Translation, sampler); } if (nodeCurve.EulerX != null) { var values = new byte[Marshal.SizeOf(typeof(Quaternion)) * nodeCurve.EulerX.Keys.Length]; var span = SpanLike.Wrap <Quaternion>(new ArraySegment <byte>(values)); Func <Quaternion, BvhNodeCurves, int, Quaternion> getRot = (q, c, i) => q; foreach (var ch in bvhNode.Channels) { var tmp = getRot; switch (ch) { case Channel.Xrotation: getRot = (_, c, i) => { return(tmp(_, c, i) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, ToRad(c.EulerX.Keys[i]))); }; break; case Channel.Yrotation: getRot = (_, c, i) => { return(tmp(_, c, i) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, ToRad(c.EulerY.Keys[i]))); }; break; case Channel.Zrotation: getRot = (_, c, i) => { return(tmp(_, c, i) * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, ToRad(c.EulerZ.Keys[i]))); }; break; default: // throw new NotImplementedException(); break; } } for (int i = 0; i < nodeCurve.EulerX.Keys.Length; ++i) { span[i] = getRot(Quaternion.Identity, nodeCurve, i); } var sampler = new CurveSampler { In = times, Out = new BufferAccessor(new ArraySegment <byte>(values), AccessorValueType.FLOAT, AccessorVectorType.VEC4, span.Length) }; curve.Curves.Add(AnimationPathType.Rotation, sampler); } animation.AddCurve(node, curve); } return(animation); }