Home > Mobile >  Need help Slerping positions and rotations
Need help Slerping positions and rotations

Time:05-07

I have 2 scripts on my camera, one for following the player ( FollowTarget.cs ), and one which is supposed to, over time, Slerp the camera's transform position and rotation around the player on death ( DeathCam.cs ).

With DeathCam.cs I am trying to get a nice smooth movement to the [desired/set in inspector] position and rotation values over time on death but currently the camera jumps to straight to the position and rotation set in inspector. Which I think maybe down to the transform.position = camPos; in Update.

I have tried to set the position and rotation in the PlayDeathCam() function but that fails to work and is currently commented out and replaced by a bool which checks in Update to see if the death cam is active

Code: FollowTarget.cs

       using System.Collections;
        using System.Collections.Generic;
        using UnityEngine;
        
        public class FollowTarget : MonoBehaviour{
        
          [Header("----- Target To Follow --------------------------------------------------")]
          public GameObject target;
        
          [Header("----- Adjustments To Make ------------------------------------------")]
          public Vector3 adjustVal;
        
           void Update(){
              pos = new Vector3( target.transform.position.x   adjustVal.x,
                                 target.transform.position.y   adjustVal.y,
                                 target.transform.position.z   adjustVal.z);
              
              transform.position = pos;
           }
         }

Code: DeathCam.cs

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

public class DeathCam : MonoBehaviour{

  [Header("----- Duration -----------------------------------------------------")]
  [SerializeField] float duration = 5.0f;

  [Header("----- Positions ----------------------------------------------------")]
  [SerializeField] float finalPosX;
  [SerializeField] float finalPosY;
  [SerializeField] float finalPosZ;


  [Header("----- Angles -------------------------------------------------------")]
  [SerializeField] float tiltAngleX;
  [SerializeField] float tiltAngleY;
  [SerializeField] float tiltAngleZ;

  [Header("--------------------------------------------------------------------")]
  [SerializeField] Vector3 camPos;
  [SerializeField] Quaternion camRot;

  [SerializeField] bool deathCamActive;


///[ Start]
    void Start(){

    }


///[ Update]
    void Update(){
      if (deathCamActive) {
        camPos = new Vector3((transform.position.x   finalPosX),
                             (transform.position.y   finalPosY),
                             (transform.position.z   finalPosZ));
                             
        transform.position = camPos;
      }
    }


///[ PlayDeathCam]
    public void PlayDeathCam(){
      float tiltAroundX = camPos.x * tiltAngleX;
      float tiltAroundY = camPos.y * tiltAngleY;
      float tiltAroundZ = camPos.z * tiltAngleZ;

      // camPos = new Vector3((transform.position.x   finalPosX),
      //                     (transform.position.y   finalPosY),
      //                     (transform.position.z   finalPosZ));

      camRot = Quaternion.Euler(tiltAroundX, tiltAroundY, tiltAroundZ);

      transform.position = Vector3.Slerp(transform.position, camPos,  Time.deltaTime * duration);
      deathCamActive = true;

      transform.rotation = Quaternion.Slerp(transform.rotation, camRot,  Time.deltaTime * duration);

      StartCoroutine("DeathCamSlow");
    }


///[ DeathCamSlow]
    IEnumerator DeathCamSlow(){
      Time.timeScale = 0.3f;
      yield return new WaitForSeconds(1.6f);
      Time.timeScale = 1.0f;
    }

}

CodePudding user response:

There is a few things wrong with your code, it should be fixable, but first let's try to disassembly some confusion that seems to be going on.

Interpolating position with slerp looks wrong for starters.

But you seem to have placed code that you believe is going to do an animation in a method that is only going to be called once.

I like to separate my thinking about triggering animations by using a pattern similar to

void StartAnimation()
{
  StartCorouting(LerpDriverRoutine());
}


IEnumerator LerpDriverRoutine()
{
  float x=0;
  while (x<1)
  {
    ApplyLerp(x);
    x =Time.deltaTime*speed;
    yield return null;
  }
  ApplyLerp(1);
}

void ApplyLerp(float lerpAmount) // this will get called with varying amount as time passes
{
 // use lerp amount here
}

While lerping x=lerp(x,other,Time.deltaTime) makes sense sometimes, more often it does, here you are not lerping between values A and B here, instead lerping between current value and target, which is leads to a similar result but often will not feel smooth. It's often much better to use Mathf.SmoothDamp if you want to gently settle onto a target value. But if Linear interpolation is what you want, and learning to code animations you might want to start with that, you need to store your start position somewhere and use it for lerp (for the time the animation is running), not just use the current value, at least not before you know what you are doing

IEnumerator LerpDriverRoutine()
{
  float x=0;
  Vector3 startPosition=transform.position;
  Quaternion startRotation=transform.rotation;
  while (x<1)
  {
    transform.position=Vector3.Lerp(startPosition,camPos,x);
    transform.rotation=Quaternion.Slerp(startRotation,camRot,x);
    x =Time.deltaTime*speed;
    yield return null;
  }
}
  • Related