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

unity – Unity3D – Camera Jitters When Displacing and Rotating Smoothly

0
unity – Unity3D – Camera Jitters When Displacing and Rotating Smoothly

[ad_1]

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

I attempted to make a easy Third Person Camera that displaces and rotates in 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 will probably 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 digicam and the goal.
  • An offset vector as Euler for the rotation, it’s equally affected by the rotation relative following’s flag.
  • Other attributes, reminiscent of ‘displacementFollowDuration’, ‘maxDisplacementFollowSpeed’, ‘rotationFollowDuration’, ‘maxRotationFollowingSpeed’, and many others., are for the sleek following. The attributes not talked about are both self-explanatory or irrelevant (at the least that is what I need to assume, right me if I could also be fallacious).

The Problem:

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

Things I’ve tried already:

  • Call the rotation and displacement following on totally 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 capabilities.
  • Use totally 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 affords.
  • Change the sleek capabilities for each displacement and rotation, reminiscent of Lerp, SmoothDamp, Slerp, even customized elastic capabilities, and many others.
  • 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 digicam 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


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 digicam (return to the unique rotation if there are not 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.
    personal Vector3 eulerOrbitRotation;             /// Current Orbit Rotation as Euler.
    personal Vector3 displacementVelocity;           /// Displacement's Velocity.
    personal Quaternion orbitRotation;               /// Orbit Rotation as Quaternion.
    personal Quaternion rotationOffset;              /// Rotation's Offset as Quaternion.
    personal Vector2 enterAxes;                      /// Input's Axes.
    personal float presentDistance;                  /// Current Distance from Camera and Player.
    personal float angularSpeed;                     /// Angular's Speed.

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

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

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

            Quaternion rotation = rework.rotation * rotationOffset;

            Handles.shade = 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.shade = 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.shade = 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>
    personal void Reset()
    {
        up = Vector3.up;
    }

    /// <abstract>GameplayCamera's tick at every body.</abstract>
    personal 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>
    personal 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>
    personal void FixedUpdate()
    {
        if(goal == null) return;

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

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

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

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

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

    /// <abstract>Performs the Rotation's Following.</abstract>
    personal void RotationFollow()
    {
        change(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 title="x">X's Axis.</param>
    /// <param title="y">Y's Axis.</param>
    personal void OrbitInAxes(float x, float y)
     Axes.X) == restrictOrbitAxes ?
            Mathf.Clamp(eulerOrbitRotation.x + xRotation, minOrbitLimits.x, maxOrbitLimits.x) : eulerOrbitRotation.x + xRotation;
        eulerOrbitRotation.y = (restrictOrbitAxes 

    /// <returns>Gets the sleek displacement following's Vector.</returns>
    personal 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>
    personal Vector3 GetOffsetPoint()
     Axes.Y) == ignoreDisplacementAxes) level.y = rework.place.y;

        return level;
    

    /// <returns>Looking Direction, bearing in mind the axes to disregard.</returns>
    personal Vector3 GetLookDirection()
     Axes.X) == ignoreRotationAxes) course.x = rework.place.x;
        if((ignoreRotationAxes 

    /// <return>Following Rotation, with the Rotation's Offset already mixed.</return>
    personal 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>
    personal void UpdateRotationOffset()
    {
        Quaternion rotation = Quaternion.Euler(eulerRotationOffset);
        rotationOffset = relativeRotationFollow ? goal.rotation * rotation : rotation;
    }

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

    /// <abstract>Gets Time's Delta.</abstract>
    /// <param title="_pa">Time Delta's Type.</param>
    /// <returns>Time's Delta of the Given Type.</returns>
    personal float GetTimeDelta(TimeDelta _timeDelta = TimeDelta.Default)
    {
        change(_timeDelta)
        {
            case TimeDelta.Default: return Time.deltaTime;
            case TimeDelta.Fixed:   return Time.mountedDeltaTime;
            case TimeDelta.Smooth:  return Time.easyDeltaTime;
            default:                return 0.0f;
        }
    }
}

I additionally made a rapid Character’s script for the sake of giving a fast instance (the unique Character script I’ve a has tons of dependencies). So its bounce doesn’t have cooldown, and it would 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] personal GameplayCamera digicam;     /// Gameplay's Camera.
    [Space(5f)]
    [SerializeField] personal KeyCode bounceKey;           /// Jump's KeyCode.
    [SerializeField] personal KeyCode displacementKey;   /// Displacement's Key.
    [SerializeField] personal float displacementSpeed;   /// Displacements Speed.
    [SerializeField] personal float bounceForce;           /// Jump's Force .
    [SerializeField] personal ForceMode mode;            /// Jump Force' sMode.
    personal Rigidbody rigidbody;                        /// Rigidbody's Component.

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

    /// <abstract>CharacterMovement's tick at every body.</abstract>
    personal 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(bounceKey)) Jump();
    }
#endregion

    /// <abstract>Performs Jump.</abstract>
    personal void Jump()
    {
        rigidbody.AddForce(Vector3.up * bounceForce, mode);
    }
}

What I Want to Know:

If I’m lacking one thing, I’m utilizing the fallacious capabilities, calling the capabilities within the fallacious threads/orders, and many others.

Please let me know if there may be extra info I’ve to supply.

[ad_2]

LEAVE A REPLY

Please enter your comment!
Please enter your name here