public static Model Load(string name, Bvh.Bvh bvh) { var model = CreateFromBvh(bvh.Root); // estimate skeleton var skeleton = SkeletonEstimator.Detect(model.Root); if (skeleton == null) { throw new Exception("fail to estimate skeleton"); } // foot to zero var minY = model.Nodes.Min(x => x.Translation.Y); var hips = model.Nodes.First(x => x.HumanoidBone == HumanoidBones.hips); if (model.Root.Children.Count != 1) { throw new Exception(); } if (model.Root.Children[0] != hips) { throw new Exception(); } hips.Translation -= new Vector3(0, minY, 0); // normalize scale var pos = hips.Translation; var factor = 1.0f; if (pos.Y != 0) { factor = 1.0f / pos.Y; foreach (var x in hips.Traverse()) { x.LocalTranslation *= factor; } hips.Translation = new Vector3(pos.X, 1.0f, pos.Z); } // animation model.Animations.Add(LoadAnimation(name, bvh, model, factor)); // add origin var origin = new Node("origin"); origin.Add(model.Root.Children[0]); model.Nodes.Add(origin); model.Root.Add(origin); return(model); }
public static Bvh Parse(string src) { using (var r = new StringReader(src)) { if (r.ReadLine() != "HIERARCHY") { throw new BvhException("not start with HIERARCHY"); } var root = ParseNode(r); if (root == null) { return(null); } var frames = 0; var frameTime = 0.0f; if (r.ReadLine() == "MOTION") { var frameSplitted = r.ReadLine().Split(':'); if (frameSplitted[0] != "Frames") { throw new BvhException("Frames is not found"); } frames = int.Parse(frameSplitted[1]); var frameTimeSplitted = r.ReadLine().Split(':'); if (frameTimeSplitted[0] != "Frame Time") { throw new BvhException("Frame Time is not found"); } frameTime = float.Parse(frameTimeSplitted[1]); } var bvh = new Bvh(root, frames, frameTime); for (int i = 0; i < frames; ++i) { var line = r.ReadLine(); bvh.ParseFrame(i, line); } bvh.Root.UpdatePosition(Vector3.Zero); return(bvh); } }
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); }