Home Game Development unity – Camera Jitters When Displacing and Rotating Smoothly

unity – Camera Jitters When Displacing and Rotating Smoothly

0
unity – Camera Jitters When Displacing and Rotating Smoothly

[ad_1]

DISCLAIMER: I’m utilizing Unity 5.6.5f1 for this code, I actually do not know if there could be API updates on later variations, although I do not suppose so.

I attempted to make a easy Third Person Camera that displaces and rotates in the direction of a given goal, with the next key parameters:

  • Following sorts for each displacement and rotation. Right now the enum is simply { Instant, Smooth }.
  • Axes to disregard for each displacement and rotation, all axes in an enum.
  • Axes to invert for the orbiting performance.
  • ‘Relative Following’ for each displacement and rotation. If the flags are checked the displacement/rotation might be relative to the goal’s orientation (‘goal.rotation * displacement’ and ‘goal.rotation * rotation’ for displacement and rotation respectively).
  • An offset vector, which is affected by the displacement relative following’s flag. It is handled as a normalized vector at runtime.
  • A scalar of the aforementioned offset. Which is mainly de distance between the digital camera and the goal.
  • An offset vector as Euler for the rotation, it’s equally affected by the rotation relative following’s flag.
  • Other attributes, akin to ‘displacementFollowDuration’, ‘maxDisplacementFollowSpeed’, ‘rotationFollowDuration’, ‘maxRotationFollowingSpeed’, and so forth., are for the sleek following. The attributes not talked about are both self-explanatory or irrelevant (not less than that is what I need to suppose, right me if I could also be improper).

The Problem:

When the sleek flags are enabled for each displacement and rotation, the digital camera begins to shake, I feel it has one thing to do with the rotation.

Things I’ve tried already:

  • Call the rotation and displacement following on completely different threads (being Update, Late Update and FixedUpdate), not but on coroutines. This time I made an enum ‘LoopType’ to encapsulate all threads, and keep away from re-compiling every time I transfer the features.
  • Use completely different sorts of time deltas. By the identical vogue of the threads, I made an enum ‘TimeDelta’ which encapsulates the three forms of time deltas Unity gives.
  • Change the sleek features for each displacement and rotation, akin to Lerp, SmoothDamp, Slerp, even customized elastic features, and so forth.
  • Sacrifing 1 body by following the goal’s level of the final body, as proposed right here.
  • Given that the goal’s displacement is that of a Rigidbody, this publish suggests to connect a Rigidbody to the digital camera and displace/rotate it by Rigidbody.place/Rigidbody.rotation respectively.

Camera’s Script:

utilizing System;
utilizing System.Collections;
utilizing System.Collections.Generic;
utilizing UnityEngine;
#if UNITY_EDITOR
utilizing UnityEditor;
#endif

[Flags]
public enum Axes
 Z,
    All = X 

public enum LoopType { Update, LateUpdate, FixedUpdate }

public enum TimeDelta { Default, Fixed, Smooth }

public enum FollowingType { Instant, Smooth }

/// TODO Maybe one thing like Lucky Tale and Resident Evil 4 and 5 digital camera (return to the unique rotation if there aren't any axes)
public class GameplayCamera : MonoBehaviour
{
    public Transform goal;                        /// Camera's Target.
    [Space(5f)]
    [Header("Displacement Following's Attributes:")]
    public LoopType comply withDisplacementAt;           /// Loop to do the Displacement Following.
    public FollowingType displacementFollowType;    /// Type of Following for Displacement.
    public TimeDelta displacementTimeDelta;         /// Displacement's Time Delta.
    public Axes ignoreDisplacementAxes;             /// Displacement Axes to Ignore.
    public Axes invertAxes;                         /// Axes to Invert.
    public Axes restrictOrbitAxes;                     /// Orbit's Axes to Limit.
    public bool relativeDisplacementFollow;         /// Follow Target's Displacement Relative to Target's Orientation?.
    public bool restrictDisplacementFollow;            /// Limit Displacement Following's Speed?.
    public Vector3 displacementOffset;              /// [Normalized] Displacement Offset between Camera and Target.
    public Vector2 orbitSpeed;                      /// Orbit's Speed on every Axis.
    public Vector2 minOrbitLimits;                  /// Orbit's Negative Boundaries.
    public Vector2 maxOrbitLimits;                  /// Orbit's Positive Boundaries.
    public float displacementFollowDuration;        /// Displacement's Follow Duration.
    public float maxDisplacementFolowSpeed;         /// Maximum Displacement's Follow Duration.
    public float minDistance;                       /// Minimum Distance Between Camera and Target.
    public float maxDistance;                       /// Maximum Distance Between Camera and Target.
    [Space(5f)]
    [Header("Rotation Following's Attributes:")]
    public LoopType comply withRotationAt;               /// Loop to do the Rotation Following.
    public FollowingType rotationFollowType;        /// Type of Following for Rotation.
    public TimeDelta rotationTimeDelta;             /// Rotations' Time Delta.
    public Axes ignoreRotationAxes;                 /// Rotation Axes to Ignore.
    public bool relativeRotationFollow;             /// Follow Target's Rotation Relative to Target's Orientation?.
    public bool restrictRotationFollow;                /// Limit Rotation Following's Speed?.
    public Vector3 eulerRotationOffset;             /// Rotation Offset between Camera and Target as Euler.
    public float rotationFollowDuration;            /// Rotation's Following Duration.
    public float maxRotationFollowSpeed;            /// Maximum Rotation's Following Speed.
    [Space(5f)]
    public Vector3 up;                              /// Up Vector's Reference.
    [HideInInspector] public Vector3 ahead;       /// Reoriented Forward's Vector.
    non-public Vector3 eulerOrbitRotation;             /// Current Orbit Rotation as Euler.
    non-public Vector3 displacementVelocity;           /// Displacement's Velocity.
    non-public Quaternion orbitRotation;               /// Orbit Rotation as Quaternion.
    non-public Quaternion rotationOffset;              /// Rotation's Offset as Quaternion.
    non-public Vector2 enterAxes;                      /// Input's Axes.
    non-public float presentDistance;                  /// Current Distance from Camera and Player.
    non-public float angularSpeed;                     /// Angular's Speed.

#area UnityStrategies:
    /// <abstract>Draws Gizmos on Editor mode.</abstract>
    non-public void OnDrawGizmos()
    {
        Gizmos.coloration = Color.inexperienced;
        Gizmos.DrawRay(rework.place, up);
        Gizmos.coloration = Color.blue;
        Gizmos.DrawRay(rework.place, ahead);

        if(goal != null)
        {
            Gizmos.coloration = Color.cyan;
            Gizmos.DrawLine(goal.place, GetOffsetPoint());

            if(!Application.isPlaying)
            {
                UpdateRotationOffset();
                ReorientForward();
            }

            Quaternion rotation = rework.rotation * rotationOffset;

            Handles.coloration = new Color(1.0f, 0.0f, 0.0f, 0.35f); /// Red
            Handles.DrawSolidArc(rework.place, rework.proper, rework.ahead, Vector3.Angle(rework.ahead, rotation * Vector3.ahead) * Mathf.Sign(eulerRotationOffset.x), 1.0f);
            Handles.coloration = new Color(0.0f, 1.0f, 0.0f, 0.35f); /// Green
            Handles.DrawSolidArc(rework.place, rework.up, rework.proper, Vector3.Angle(rework.proper, rotation * Vector3.proper) * Mathf.Sign(eulerRotationOffset.y), 1.0f);
            Handles.coloration = new Color(1.0f, 0.0f, 1.0f, 0.35f); /// Blue
            Handles.DrawSolidArc(rework.place, rework.ahead, rework.up, Vector3.Angle(rework.up, rotation * Vector3.up) * Mathf.Sign(eulerRotationOffset.z), 1.0f);

            if(!Application.isPlaying)
            {
                rework.place = GetOffsetPoint();
                rework.rotation = Quaternion.LookRotation(GetLookDirection()) * rotationOffset;
            }
        }       
    }

    /// <abstract>Resets GameplayCamera's occasion to its default values.</abstract>
    non-public void Reset()
    {
        up = Vector3.up;
    }

    /// <abstract>GameplayCamera's tick at every body.</abstract>
    non-public void Update()
    {
        if(goal == null) return;

        ObserveInput();
        UpdateRotationOffset();

        if(comply withDisplacementAt == LoopType.Update) DisplacementFollow();
        if(comply withRotationAt == LoopType.Update) RotationFollow();
    }

    /// <abstract>Updates GameplayCamera's occasion on the finish of every body.</abstract>
    non-public void LateUpdate()
    {
        if(goal == null) return;

        if(comply withDisplacementAt == LoopType.LateUpdate) DisplacementFollow();
        if(comply withRotationAt == LoopType.LateUpdate) RotationFollow();

        ReorientForward();
    }

    /// <abstract>Updates GameplayCamera's occasion at every Physics Thread's body.</abstract>
    non-public void FixedUpdate()
    {
        if(goal == null) return;

        if(comply withDisplacementAt == LoopType.FixedUpdate) DisplacementFollow();
        if(comply withRotationAt == LoopType.FixedUpdate) RotationFollow();
    }
#endregion

    /// <abstract>Tracks Input.</abstract>
    non-public void ObserveInput()
    {
        enterAxes.x = Input.GetAxis("Mouse Y");
        enterAxes.y = Input.GetAxis("Mouse X");
    }

    /// <abstract>Performs the Displacement's Following.</abstract>
    non-public void DisplacementFollow()
    {
        if(enterAxes.sqrMagnitude > 0.0f) OrbitInAxes(enterAxes.x, enterAxes.y);

        swap(displacementFollowType)
        {
            case FollowingType.Instant:
            rework.place = GetOffsetPoint();
            break;

            case FollowingType.Smooth:
            rework.place = GetSmoothDisplacementFollowDirection();
            break;
        }
    }

    /// <abstract>Performs the Rotation's Following.</abstract>
    non-public void RotationFollow()
    {
        swap(rotationFollowType)
        {
            case FollowingType.Instant:
            rework.rotation = Quaternion.LookRotation(GetLookDirection()) * rotationOffset;
            break;

            case FollowingType.Smooth:
            rework.rotation = GetSmoothFollowRotation();
            break;
        }
    }

    /// <abstract>Orbits Camera in Given Axes.</abstract>
    /// <param identify="x">X's Axis.</param>
    /// <param identify="y">Y's Axis.</param>
    non-public void OrbitInAxes(float x, float y)
     Axes.Y) == invertAxes) y *= -1.0f;

        float xRotation = (x * orbitSpeed.x * GetTimeDelta(displacementTimeDelta));
        float yRotation = (y * orbitSpeed.y * GetTimeDelta(displacementTimeDelta));

        eulerOrbitRotation.x = (restrictOrbitAxes 

    /// <returns>Gets the sleek displacement following's Vector.</returns>
    non-public Vector3 GetSmoothDisplacementFollowDirection()
    {
        return Vector3.SmoothDamp
        (
            rework.place,
            GetOffsetPoint(),
            ref displacementVelocity,
            displacementFollowDuration,
            restrictDisplacementFollow ? maxDisplacementFolowSpeed : Mathf.Infinity,
            GetTimeDelta(displacementTimeDelta)
        );
    }

    /// <abstract>Gets Offset Point, with the Orbit's Rotation already mixed.</abstract>
    non-public Vector3 GetOffsetPoint()
     Axes.Y) == ignoreDisplacementAxes) level.y = rework.place.y;

        return level;
    

    /// <returns>Looking Direction, considering the axes to disregard.</returns>
    non-public Vector3 GetLookDirection()
     Axes.X) == ignoreRotationAxes) course.x = rework.place.x;
        if((ignoreRotationAxes 

    /// <return>Following Rotation, with the Rotation's Offset already mixed.</return>
    non-public Quaternion GetSmoothFollowRotation()
    {
        Quaternion rotation = Quaternion.LookRotation(GetLookDirection()) * rotationOffset;
        float angle = Quaternion.Angle(rework.rotation, rotation);

        if(angle > 0.0f)
        {
            float t = Mathf.SmoothDampAngle(
                angle,
                0.0f,
                ref angularSpeed,
                rotationFollowDuration,
                restrictRotationFollow ? maxRotationFollowSpeed : Mathf.Infinity,
                GetTimeDelta(rotationTimeDelta)
            );
            return Quaternion.Slerp(rework.rotation, rotation, t);
        }

        return rotation;
    }

    /// <abstract>Updates the Rotation's Offset Given the Wuler Representation.</abstract>
    non-public void UpdateRotationOffset()
    {
        Quaternion rotation = Quaternion.Euler(eulerRotationOffset);
        rotationOffset = relativeRotationFollow ? goal.rotation * rotation : rotation;
    }

    /// <abstract>Reorients Forward's Vector.</abstract>
    non-public void ReorientForward()
    {
        ahead = Vector3.Cross(rework.proper, up);
    }

    /// <abstract>Gets Time's Delta.</abstract>
    /// <param identify="_pa">Time Delta's Type.</param>
    /// <returns>Time's Delta of the Given Type.</returns>
    non-public float GetTimeDelta(TimeDelta _timeDelta = TimeDelta.Default)
    {
        swap(_timeDelta)
        {
            case TimeDelta.Default: return Time.deltaTime;
            case TimeDelta.Fixed:   return Time.fastenedDeltaTime;
            case TimeDelta.Smooth:  return Time.cleanDeltaTime;
            default:                return 0.0f;
        }
    }
}

I additionally made a fast Character’s script for the sake of giving a fast instance (the unique Character script I’ve a has tons of dependencies). So its leap doesn’t have cooldown, and it does not consider whether it is grounded.

Simple Character Movement’s Script:

utilizing System;
utilizing System.Collections;
utilizing System.Collections.Generic;
utilizing UnityEngine;

[RequireComponent(typeof(Rigidbody))]
public class CharacterMotion : MonoBehaviour
{
    [SerializeField] non-public GameplayCamera digital camera;     /// Gameplay's Camera.
    [Space(5f)]
    [SerializeField] non-public KeyCode leapKey;           /// Jump's KeyCode.
    [SerializeField] non-public KeyCode displacementKey;   /// Displacement's Key.
    [SerializeField] non-public float displacementSpeed;   /// Displacements Speed.
    [SerializeField] non-public float leapForce;           /// Jump's Force .
    [SerializeField] non-public ForceMode mode;            /// Jump Force' sMode.
    non-public Rigidbody rigidbody;                        /// Rigidbody's Component.

#area UnityStrategies:
    /// <abstract>CharacterMovement's occasion initialization.</abstract>
    non-public void Awake()
    {
        rigidbody = GetComponent<Rigidbody>();
    }

    /// <abstract>CharacterMovement's tick at every body.</abstract>
    non-public void Update ()
    {
        Vector3 axes = new Vector3
        (
            Input.GetAxis("Horizontal"),
            0.0f,
            Input.GetAxis("Vertical")
        );

        if(axes.sqrMagnitude > 0.0f)
        {
            rework.rotation = Quaternion.LookRotation(axes);
            rework.Translate(rework.ahead * displacementSpeed * Time.deltaTime, Space.World);
        }
        if(Input.GetKeyDown(leapKey)) Jump();
    }
#endregion

    /// <abstract>Performs Jump.</abstract>
    non-public void Jump()
    {
        rigidbody.AddForce(Vector3.up * leapForce, mode);
    }
}

What I Want to Know:

If I’m lacking one thing, I’m utilizing the improper features, calling the features within the improper threads/orders, and so forth.

Please let me know if there’s extra data I’ve to supply.

[ad_2]

LEAVE A REPLY

Please enter your comment!
Please enter your name here