コード例 #1
0
 public void AddCurve(Node node, NodeAnimation nodeAnimation)
 {
     NodeMap.Add(node, nodeAnimation);
     if (nodeAnimation.Duration > m_lastTime)
     {
         m_lastTime = nodeAnimation.Duration;
     }
 }
コード例 #2
0
        public NodeAnimation GetOrCreateNodeAnimation(Node node)
        {
            NodeAnimation nodeAnimation;

            if (!NodeMap.TryGetValue(node, out nodeAnimation))
            {
                nodeAnimation = new NodeAnimation();
                NodeMap.Add(node, nodeAnimation);
            }
            return(nodeAnimation);
        }
コード例 #3
0
        /// <summary>
        /// モーションの基本姿勢を basePose ベースに再計算する
        ///
        /// basePose は Humanoid.CopyNodes が必用 !
        /// </summary>
        public Animation RebaseAnimation(Humanoid basePose)
        {
            var map           = NodeMap.ToDictionary(kv => kv.Key, kv => new List <Quaternion>());
            var hipsPositions = new List <Vector3>();

            foreach (var(seconds, keyframes) in KeyFramesGroupBySeconds())
            {
                // モーション適用
                SetTime(seconds);
                Root.CalcWorldMatrix();

                foreach (var keyframe in keyframes)
                {
                    if (!keyframe.Node.HumanoidBone.HasValue ||
                        keyframe.Node.HumanoidBone.Value == HumanoidBones.unknown)
                    {
                        continue;
                    }

                    // ローカル回転を算出する
                    var t        = basePose[keyframe.Node].Rotation;
                    var w        = keyframe.Node.Rotation;
                    var w_from_t = w * Quaternion.Inverse(t);

                    // parent
                    var key   = keyframe.Node.HumanoidBone.Value;
                    var curve = map[keyframe.Node];
                    if (key != HumanoidBones.hips)
                    {
                        if (basePose[key].Parent == null)
                        {
                            throw new Exception();
                        }
                        var parent_t        = basePose[key].Parent.Rotation;
                        var parent_w        = keyframe.Node.Parent.Rotation;
                        var parent_w_from_t = parent_w * Quaternion.Inverse(parent_t);

                        var r = Quaternion.Inverse(parent_w_from_t) * w_from_t;
                        curve.Add(r);
                    }
                    else
                    {
                        // hips
                        curve.Add(w_from_t);
                        hipsPositions.Add(keyframe.Node.Translation);
                    }
                }
            }

            var dst = new Animation(Name + ".tpose");

            foreach (var kv in map)
            {
                if (!kv.Value.Any())
                {
                    continue;
                }

                var bone = kv.Key.HumanoidBone.Value;

                var inCurve = NodeMap[kv.Key].Curves[AnimationPathType.Rotation].In;
                if (inCurve.Count != kv.Value.Count)
                {
                    throw new Exception();
                }

                var nodeAnimation = new NodeAnimation();
                nodeAnimation.Curves.Add(AnimationPathType.Rotation, new CurveSampler
                {
                    In  = inCurve,
                    Out = BufferAccessor.Create(kv.Value.ToArray()),
                });
                if (bone == HumanoidBones.hips)
                {
                    nodeAnimation.Curves.Add(AnimationPathType.Translation, new CurveSampler
                    {
                        In  = inCurve,
                        Out = BufferAccessor.Create(hipsPositions.ToArray()),
                    });
                }
                dst.AddCurve(kv.Key, nodeAnimation);
            }
            return(dst);
        }
コード例 #4
0
        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);
        }