Esempio n. 1
0
        /// <summary>This is a slerp that mimics a camera operator's movement in that
        /// it chooses a path that avoids the lower hemisphere, as defined by
        /// the up param</summary>
        /// <param name="vA">First direction</param>
        /// <param name="vB">Second direction</param>
        /// <param name="t">Interpolation amoun t</param>
        /// <param name="up">Defines the up direction</param>
        public static Vector3 SlerpWithReferenceUp(
            Vector3 vA, Vector3 vB, float t, Vector3 up)
        {
            float dA = vA.magnitude;
            float dB = vB.magnitude;

            if (dA < Epsilon || dB < Epsilon)
            {
                return(Vector3.Lerp(vA, vB, t));
            }

            Vector3    dirA = vA / dA;
            Vector3    dirB = vB / dB;
            Quaternion qA   = Quaternion.LookRotation(dirA, up);
            Quaternion qB   = Quaternion.LookRotation(dirB, up);
            Quaternion q    = UnityQuaternionExtensions.SlerpWithReferenceUp(qA, qB, t, up);
            Vector3    dir  = q * Vector3.forward;

            return(dir * Mathf.Lerp(dA, dB, t));
        }
Esempio n. 2
0
        /// <summary>Intelligently blend the contents of two states.</summary>
        /// <param name="stateA">The first state, corresponding to t=0</param>
        /// <param name="stateB">The second state, corresponding to t=1</param>
        /// <param name="t">How much to interpolate.  Internally clamped to 0..1</param>
        /// <returns>Linearly interpolated CameraState</returns>
        public static CameraState Lerp(CameraState stateA, CameraState stateB, float t)
        {
            t = Mathf.Clamp01(t);
            float adjustedT = t;

            CameraState state = new CameraState();

            state.Lens        = LensSettings.Lerp(stateA.Lens, stateB.Lens, t);
            state.ReferenceUp = Vector3.Slerp(stateA.ReferenceUp, stateB.ReferenceUp, t);
            state.RawPosition = Vector3.Lerp(stateA.RawPosition, stateB.RawPosition, t);

            state.ShotQuality        = Mathf.Lerp(stateA.ShotQuality, stateB.ShotQuality, t);
            state.PositionCorrection = Vector3.Lerp(
                stateA.PositionCorrection, stateB.PositionCorrection, t);
            // GML todo: is this right?  Can it introduce a roll?
            state.OrientationCorrection = Quaternion.Slerp(
                stateA.OrientationCorrection, stateB.OrientationCorrection, t);

            Vector3 dirTarget = Vector3.zero;

            if (!stateA.HasLookAt || !stateB.HasLookAt)
            {
                state.ReferenceLookAt = kNoPoint;   // can't interpolate if undefined
            }
            else
            {
                // Re-interpolate FOV to preserve target composition, if possible
                float fovA = stateA.Lens.FieldOfView;
                float fovB = stateB.Lens.FieldOfView;
                if (!state.Lens.Orthographic && !Mathf.Approximately(fovA, fovB))
                {
                    LensSettings lens = state.Lens;
                    lens.FieldOfView = state.InterpolateFOV(
                        fovA, fovB,
                        Mathf.Max((stateA.ReferenceLookAt - stateA.CorrectedPosition).magnitude, stateA.Lens.NearClipPlane),
                        Mathf.Max((stateB.ReferenceLookAt - stateB.CorrectedPosition).magnitude, stateB.Lens.NearClipPlane), t);
                    state.Lens = lens;

                    // Make sure we preserve the screen composition through FOV changes
                    adjustedT = Mathf.Abs((lens.FieldOfView - fovA) / (fovB - fovA));
                }

                // Linear interpolation of lookAt target point
                state.ReferenceLookAt = Vector3.Lerp(
                    stateA.ReferenceLookAt, stateB.ReferenceLookAt, adjustedT);

                // If orientations are different, use LookAt to blend them
                float angle = Quaternion.Angle(stateA.RawOrientation, stateB.RawOrientation);
                if (angle > UnityVectorExtensions.Epsilon)
                {
                    dirTarget = state.ReferenceLookAt - state.CorrectedPosition;
                }
            }

            // Clever orientation interpolation
            if (dirTarget.AlmostZero())
            {
                // Don't know what we're looking at - can only slerp
                state.RawOrientation = UnityQuaternionExtensions.SlerpWithReferenceUp(
                    stateA.RawOrientation, stateB.RawOrientation, t, state.ReferenceUp);
            }
            else
            {
                // Rotate while preserving our lookAt target
                dirTarget = dirTarget.normalized;
                if ((dirTarget - state.ReferenceUp).AlmostZero() ||
                    (dirTarget + state.ReferenceUp).AlmostZero())
                {
                    // Looking up or down at the pole
                    state.RawOrientation = UnityQuaternionExtensions.SlerpWithReferenceUp(
                        stateA.RawOrientation, stateB.RawOrientation, t, state.ReferenceUp);
                }
                else
                {
                    // Put the target in the center
                    state.RawOrientation = Quaternion.LookRotation(dirTarget, state.ReferenceUp);

                    // Blend the desired offsets from center
                    Vector2 deltaA = -stateA.RawOrientation.GetCameraRotationToTarget(
                        stateA.ReferenceLookAt - stateA.CorrectedPosition, stateA.ReferenceUp);
                    Vector2 deltaB = -stateB.RawOrientation.GetCameraRotationToTarget(
                        stateB.ReferenceLookAt - stateB.CorrectedPosition, stateB.ReferenceUp);
                    state.RawOrientation = state.RawOrientation.ApplyCameraRotation(
                        Vector2.Lerp(deltaA, deltaB, adjustedT), state.ReferenceUp);
                }
            }

            // Accumulate the custom blendables and apply the weights
            for (int i = 0; i < stateA.NumCustomBlendables; ++i)
            {
                CustomBlendable b = stateA.GetCustomBlendable(i);
                b.m_Weight *= (1 - t);
                if (b.m_Weight > UnityVectorExtensions.Epsilon)
                {
                    state.AddCustomBlendable(b);
                }
            }
            for (int i = 0; i < stateB.NumCustomBlendables; ++i)
            {
                CustomBlendable b = stateB.GetCustomBlendable(i);
                b.m_Weight *= t;
                if (b.m_Weight > UnityVectorExtensions.Epsilon)
                {
                    state.AddCustomBlendable(b);
                }
            }
            return(state);
        }