Пример #1
0
        public static Quaternion Slerp(Quaternion from, Quaternion to, double t, bool useShortestPath)
        {
            //For more information on how this works see:
            //Chapter 10 in "Essential Mathermatics for Games & Interactive Applications"
            //James M. Van Verth & Lars M. Bishop

            //Slerp(p,q,t) = (sin((1-t)angle) * p + sin(t*angle) * q) / sin(angle)

            //Interpolate along a sphere between the two quaternions

            //Find the angle between the two axis
            double fromNorm = from.Norm;
            double toNorm = to.Norm;
            from.Normalize();
            to.Normalize();
            double fromDotTo = from.X * to.X + from.Y * to.Y + from.Z * to.Z + from.W * to.W;

            if (useShortestPath) {
                if (fromDotTo < 0) {
                    //Need to negate one of the quaternions
                    to = new Quaternion(-to.X, -to.Y, -to.Z, -to.W);
                    fromDotTo *= -1;
                }
            }
            if (fromDotTo < -1) {
                fromDotTo = -1;
            }
            else if (fromDotTo > 1) {
                fromDotTo = 1;
            }

            double angleInRadians = System.Math.Acos(fromDotTo);
            double sinAngle = System.Math.Sin(angleInRadians);

            //Be careful about division by zero
            if (MathHelper.IsZero(sinAngle)) {
                //Just lerp instead of slerp
                return new Quaternion(from.X + (to.X - from.X) * t,
                                      from.Y + (to.Y - from.Y) * t,
                                      from.Z + (to.Z - from.Z) * t,
                                      from.W + (to.W - from.W) * t);
            }
            else {

                double sinFrom = System.Math.Sin((1.0 - t) * angleInRadians) / sinAngle;
                double sinTo = System.Math.Sin(t * angleInRadians) / sinAngle;

                //Scale from FromNorm to toNorm depending on t.  When t==0 then
                //scale == fromNorm, when t==1 scale == toNorm
                double scale = 1;//fromNorm * System.Math.Pow((toNorm / fromNorm), t);
                return new Quaternion(scale * (from.X * sinFrom + to.X * sinTo),
                                      scale * (from.Y * sinFrom + to.Y * sinTo),
                                      scale * (from.Z * sinFrom + to.Z * sinTo),
                                      scale * (from.W * sinFrom + to.W * sinTo));
            }
        }
Пример #2
0
        public static Quaternion Slerp(Quaternion from, Quaternion to, double t, bool useShortestPath)
        {
            //For more information on how this works see:
            //Chapter 10 in "Essential Mathermatics for Games & Interactive Applications"
            //James M. Van Verth & Lars M. Bishop

            //Slerp(p,q,t) = (sin((1-t)angle) * p + sin(t*angle) * q) / sin(angle)

            //Interpolate along a sphere between the two quaternions

            //Find the angle between the two axis
            double fromNorm = from.Norm;
            double toNorm   = to.Norm;

            from.Normalize();
            to.Normalize();
            double fromDotTo = from.X * to.X + from.Y * to.Y + from.Z * to.Z + from.W * to.W;

            if (useShortestPath)
            {
                if (fromDotTo < 0)
                {
                    //Need to negate one of the quaternions
                    to         = new Quaternion(-to.X, -to.Y, -to.Z, -to.W);
                    fromDotTo *= -1;
                }
            }
            if (fromDotTo < -1)
            {
                fromDotTo = -1;
            }
            else if (fromDotTo > 1)
            {
                fromDotTo = 1;
            }

            double angleInRadians = System.Math.Acos(fromDotTo);
            double sinAngle       = System.Math.Sin(angleInRadians);

            //Be careful about division by zero
            if (MathHelper.IsZero(sinAngle))
            {
                //Just lerp instead of slerp
                return(new Quaternion(from.X + (to.X - from.X) * t,
                                      from.Y + (to.Y - from.Y) * t,
                                      from.Z + (to.Z - from.Z) * t,
                                      from.W + (to.W - from.W) * t));
            }
            else
            {
                double sinFrom = System.Math.Sin((1.0 - t) * angleInRadians) / sinAngle;
                double sinTo   = System.Math.Sin(t * angleInRadians) / sinAngle;

                //Scale from FromNorm to toNorm depending on t.  When t==0 then
                //scale == fromNorm, when t==1 scale == toNorm
                double scale = 1;//fromNorm * System.Math.Pow((toNorm / fromNorm), t);
                return(new Quaternion(scale * (from.X * sinFrom + to.X * sinTo),
                                      scale * (from.Y * sinFrom + to.Y * sinTo),
                                      scale * (from.Z * sinFrom + to.Z * sinTo),
                                      scale * (from.W * sinFrom + to.W * sinTo)));
            }
        }