Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Quaternion.SmoothDamp?

Discussion in 'Scripting' started by PanayotCankov, Dec 13, 2019.

Thread Status:
Not open for further replies.
  1. PanayotCankov

    PanayotCankov

    Joined:
    May 28, 2018
    Posts:
    16
    I am working on AR/VR and often find I need to smooth damp rotations. Either to simulate a steady cam. Or to show head up display that won't be fixed with the user's rotation but will rather "follow" the gaze trying not to introduce motion sickens.

    I often end up with something like:

    Code (CSharp):
    1.     float eulerXVelocity;
    2.     float eulerYVelocity;
    3.     float eulerZVelocity;
    4.  
    5.     void Update()
    6.     {
    7.         var cam = Camera.main.transform;
    8.  
    9.         var currentAngles = this.transform.rotation.eulerAngles;
    10.         var targetAngles = cam.rotation.eulerAngles;
    11.  
    12.         var x = Mathf.SmoothDampAngle(currentAngles.x, targetAngles.x, ref eulerXVelocity, 0.3f);
    13.         var y = Mathf.SmoothDampAngle(currentAngles.y, targetAngles.y, ref eulerYVelocity, 0.3f);
    14.         var z = Mathf.SmoothDampAngle(currentAngles.z, targetAngles.z, ref eulerZVelocity, 0.3f);
    15.  
    16.         this.transform.rotation = Quaternion.Euler(x, y, z);
    17.  
    18.         this.transform.position = cam.transform.position + this.transform.rotation * Vector3.forward;
    19.     }
    Resolving to Mathf.SmoothDampAngle, but I was kind of expecting something similar to exist on Quaternion or Vector3.SmoothDampAngle.

    Am I missing something?
     
    mattxreality and macagu like this.
  2. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,077
    https://docs.unity3d.com/ScriptReference/Quaternion.Slerp.html is the 'correct' way mathematically to move between two quaternions as it's guaranteed to take the shortest distance. Interpolating between eulers can produce some really odd results although in your case it'll probably be ok as the gap between them is very small.

    You could use slerp with a small T value and that would gradually 'chase' to the correct destination quaternion over a period of frame updates.
     
    oleg_v likes this.
  3. PanayotCankov

    PanayotCankov

    Joined:
    May 28, 2018
    Posts:
    16
    There is huge difference between what slerp and smooth damp do. The sensors from VR devices usually provide noisy input and the lerp functions tend to be much more reactive to sudden spikes in values compared to the smooth damp. Another issue is that smooth damp velocity will gradually increase and decrease, while the slerp will chase with large velocity that gradually decreases when you reach your target. That makes the smooth damp somewhat better for VR for things that may introduce motion sickness. For example a head up display that is lerped to stay infront of the camera with react quickly to movement and rotation and appear to be fixed to the cam, while with smooth damp it will take some time for the hud to build up velocity, when you move or rotate your head the HUD will appear to be fixed in space and chase its desired position later introducing less motion sickness.

    With all that said - I am pretty familiar with slerp but it’s not what I want. Slerp version that keeps track of velocity as smooth damp would be ok.
     
  4. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,077
    Volorf, EZaca, curbol and 8 others like this.
  5. PanayotCankov

    PanayotCankov

    Joined:
    May 28, 2018
    Posts:
    16
    Wow, that’s much more helpful. I will check these as soon as I get in the office.
    Thank you!
     
  6. stevencr4z

    stevencr4z

    Joined:
    Jul 2, 2020
    Posts:
    5
    I know this is necro, but I just want to include that I've found a very sharp work-around with this little snippet:
    Code (CSharp):
    1. transform.rotation = Quaternion.Euler(Vector3.SmoothDamp(transform.rotation.eulerAngles, targetRotation.eulerAngles, ref velocity, rotateTime * Time.deltaTime));
    Hope this helps anyone working for a smooth rotation!
     
  7. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,498
    See Vector3.SmoothDamp for explanation of usage :)

    Code (CSharp):
    1. public static Quaternion SmoothDampQuaternion(Quaternion current, Quaternion target, ref Vector3 currentVelocity, float smoothTime)
    2. {
    3.   Vector3 c = current.eulerAngles;
    4.   Vector3 t = target.eulerAngles;
    5.   return Quaternion.Euler(
    6.     Mathf.SmoothDampAngle(c.x, t.x, ref currentVelocity.x, smoothTime),
    7.     Mathf.SmoothDampAngle(c.y, t.y, ref currentVelocity.y, smoothTime),
    8.     Mathf.SmoothDampAngle(c.z, t.z, ref currentVelocity.z, smoothTime)
    9.   );
    10. }
    Code (CSharp):
    1. public static Vector3 SmoothDampEuler(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime)
    2. {
    3.   return new Vector3(
    4.     Mathf.SmoothDampAngle(current.x, target.x, ref currentVelocity.x, smoothTime),
    5.     Mathf.SmoothDampAngle(current.y, target.y, ref currentVelocity.y, smoothTime),
    6.     Mathf.SmoothDampAngle(current.z, target.z, ref currentVelocity.z, smoothTime)
    7.   );
    8. }
    Edit: About 2.5 years later.. adding a note here that with SmoothDamp/SmoothDampAngle functions, you can end up with NaN issues if you have a smoothTime value of 0 or Time.deltaTime is 0 like with a paused game using a Time.timeScale of 0. You can add the following two lines at the top of each function to avoid both of these issues easily:
    Code (CSharp):
    1. if (Time.deltaTime == 0) return current;
    2. if (smoothTime == 0) return target;
    Related info: https://discussions.unity.com/t/smoohtdamp-nan-problem/36392
     
    Last edited: Jun 25, 2023
  8. abusfad

    abusfad

    Joined:
    Aug 20, 2018
    Posts:
    1
    The code from this answer is simple enough and achieved a very smoothdamp-like effect for me:
    Code (CSharp):
    1. float delta = Quaternion.Angle(transform.rotation, targetRotation);
    2. if (delta > 0f)
    3. {
    4.     float t = Mathf.SmoothDampAngle(_delta, 0.0f, ref currVel, rotateSmoothTime);
    5.     t = 1.0f - (t / delta);
    6.     transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, t);
    7. }
     
    Last edited: Feb 9, 2021
  9. lucidtripper

    lucidtripper

    Joined:
    Aug 3, 2017
    Posts:
    21
    I wanted a smooth camera to trak along with my vr pov - and sent the visual out to vpt8 vj software (using klakspout)

    smooths position and rotation of "this" object according to a "player" GameObject

    Code (CSharp):

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Smooth : MonoBehaviour
    {
    [SerializeField] //for explicity sake
    public GameObject player;
    public float smoothTime = 0.3F;
    private Vector3 velocity = Vector3.zero;
    void LateUpdate()
    {
    this.transform.position = Vector3.SmoothDamp(this.transform.position, player.transform.position, ref velocity, smoothTime);
    this.transform.rotation = Quaternion.Lerp(transform.rotation, player.transform.rotation, Time.deltaTime * smoothTime);
    }
    }
     
Thread Status:
Not open for further replies.