- Home /
Rotation smoothly between two points...
OK so I'm trying to rotate an object between two points using this code:
public float rotationSpeed = .01f;
private Quaternion beginRotQuat = new Quaternion(0f, 0f, 45, 0f);
private Quaternion endRotQuat = new Quaternion(0f, 0f, 90, 0f);
void Start()
{
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
transform.rotation = Quaternion.Lerp(beginRotQuat, endRotQuat, rotationSpeed * Time.deltaTime);
}
}
I've watched too many videos, so now I'm asking specifically!
Answer by unity_ek98vnTRplGj8Q · Jun 17, 2020 at 04:05 PM
Ok, first things first: do not construct a Quaternion using new Quaternion() unless you know what you are doing. The 4 values passed are NOT angle values, they are the complex coefficients that make up a Quaternion. In 99.9% of cases you do not care what these coefficients are, you only care about the angles around each axis that they represent. These angles are called euler angles and you access them like -> myQuaternion.eulerAngles.x;
Similarly to construct a new quaternion using a set of angles, you would use newQuat = Quaternion.Euler(x, y, z)
.
Now as far as smooth rotation there are 2 approaches using Lerp. If you want a constant velocity during the rotation then you want to have a constant start and end rotation and increase your interpolation value every frame until it hits 1 like this
Vector3 startAngles = new Vector3(0, 0, 45);
Vector3 endAngles = new Vector3(0, 0, 90);
Quaternion startRot, endRot;
float interp = 0;
public float speed = 0.5f;
void Start(){
startRot = Quaternion.Euler(startAngles);
endRot = Quaternion.Euler(endAngles);
}
void Update(){
if(Input.GetMouseButton(0)){
if(interp < 1) interp += Time.deltaTime * speed;
transform.rotation = Quaternion.Lerp(startRot, endRot, interp);
}
}
If, on the other hand, you want a rotation that slows down as it approaches the target rotation, you want something like this, which uses the current rotation as a parameter to the Lerp function
Vector3 startAngles = new Vector3(0, 0, 45);
Vector3 endAngles = new Vector3(0, 0, 90);
Quaternion startRot, endRot;
public float speed = 0.5f;
void Start(){
startRot = Quaternion.Euler(startAngles);
endRot = Quaternion.Euler(endAngles);
transform.rotation = startRot;
}
void Update(){
if(Input.GetMouseButton(0)){
transform.rotation = Quaternion.Lerp(transform.rotation, endRot, speed * Time.deltaTime);
}
}
Just to clarify on why your code is not working, understand that Lerp(a, b, c) choose a value between a and b based on c, so if c = 1 it returns b, and if c = 0.5 it will be exactly halfway between the two. Since your start, end, and interpolation value were basically the same every frame lerp was returning the same value every frame, meaning that you kept updating your object rotation to the same value every frame.
Its seems to be working better, but it still snaps the object's rotation and doesn't change it over time. Heres the code I'm using now:
public float rotationSpeed = .1f;
private Vector3 startRot = new Vector3(0f, 0f, 45f);
private Vector3 endRot = new Vector3(0f, 0f, 90f);
Quaternion startRotQuat, endRotQuat;
// Start is called before the first frame update
void Start()
{
startRotQuat = Quaternion.Euler(startRot);
endRotQuat = Quaternion.Euler(endRot);
}
// Update is called once per frame
void Update()
{
if (Input.Get$$anonymous$$ouseButtonDown(0))
{
for (float i = 0; i < 1; i += rotationSpeed)
{
transform.rotation = Quaternion.Lerp(startRotQuat, endRotQuat, i * Time.deltaTime);
}
}
}
The start and end quaterns both are set differently, and I have the for loop to change the i value over time... what is going wrong here?
Don't use a for loop like this in the update function - remember, the for loop will run through completely each frame, meaning that the only value you see is the final value of i. Ins$$anonymous$$d, declare a private variable and do something like this, which changes your i value slightly just once per frame
private float interp = 0;
void Update () {
if (Input.Get$$anonymous$$ouseButton (0)) {
if (interp < 1) {
interp += speed * Time.deltaTime;
}
transform.rotation = Quaternion.Lerp (startRotQuat, endRotQuat, interp);
}
}
Also make sure you are using Get$$anonymous$$ouseButton ins$$anonymous$$d of Get$$anonymous$$ouseButtonDown. Because this will let you rotate every frame the mouse is held down rather than just the first frame you press the button. If you want to restart the rotation every time you click the mouse, you could add a line like this to the start of your update function
void Update () {
if(Input.Get$$anonymous$$ouseButtonDown(0)){
interp = 0;
}
if (Input.Get$$anonymous$$ouseButton(0)) {
blah blah blah....
This is awesome! It works and rotates! But, is there a way to make it rotate by itself once the mouse click is pressed? I would like it to rotate by itself upon Get$$anonymous$$ouseButtonDown() ins$$anonymous$$d of holding the click down for it to swing all the way...
Answer by N-8-D-e-v · Jun 17, 2020 at 11:42 AM
If you use Input.GetMouseButtonDown, it will sense when it is down, and then won't do anything until it is up and back down again. That is why your object is probably only rotating a little. If you use Input.GetMouseButton(0), that will allow you to hold it down and still get input.
It does not seem to work either way. It still snaps the object to the angle -180. (I didn't mention that in the original question.) I think it has something to do with the time or the use of the Quaternions. Thanks for your input though!
happy to help! also I would advise against using the NewQuaternion() statement unless you really know what you're doing
Your answer
Follow this Question
Related Questions
Moving player in an arc, from startPoint to endPoint 2 Answers
Make Lerp or other more fluid or continuous 3 Answers
Collision.contacts? 1 Answer
Stop a Lerp from looping 3 Answers
custom follow script choppy movement 2 Answers