- Home /
Implementation behind Transform.forward
I wondering what philosophy stands behind Transform.forward setter. In my opinion it should rotate coordinate system by smallest angle needed to make forward vector equal to new value. So implementation should be something like that:
class Transform
{
private Vector3 _forward;
public Vector3 forward
{
set
{
Vector3 oldForward = _forward;
Vector3 newForward = value;
Vector3 axis = Vector3.Cross(oldForward, newForward).normalized;
float angle = Vector3.Angle(oldForward, newForward);
transform.rotation = transform.rotation * Quaternion.AngleAxis(angle, axis);
}
}
}
right? But I noticed, that Transform.forward setter works exactly in the same way as Transform.LookAt(transform.position + transform.forward).
So my question is: How does Transform.forward setter works? What happen with up and right vectors?
Answer by majak · Mar 10, 2015 at 02:39 PM
I found something in that post: http://answers.unity3d.com/questions/560471/efficiency-of-transformforward-up-and-right.html (Bunny's answer).
public Vector3 forward
{
get { return this.rotation * Vector3.forward; }
set { this.rotation = Quaternion.LookRotation(value); }
}
And now I understand why transform.forward works exactly the same as Transform.LookAt() ;D
...and if you see the pop-up for LookRotation, it has a second slot for the local UP. The way local up defaults to world up in the 1-input version is standard design. People who didn't know what LookAt did would still know it had 2 inputs, but the 2nd one was kind of advanced.
With a setter, there's no good way to supply the second input, or even to say there is a secrete second input. The author is forced to lock it into one particular local up, so it can never work properly.
I'm surprised that this satisfies you, since it really only shows that it does use the same kind of function without saying why it is better than the method you suggested. Notice that the get for this function returns the rotation multiplied by Vector3.forward. This tells you that the directional vectors (Transform.forward/right/up) are all based on the rotation of the Transform. It makes sense then, that in order to define a new forward for the transform, you have to define a new rotation for it (and then the forward/right/up vectors are all relative to that rotation). They key part here is that it is impossible to define a rotation with only one vector, so there is difficulty in setting the Vector3 transform.forward by assigning a single vector value. The Quaternion.LookRotation method defines a rotation with two vectors, one for the direction it is facing, and one to indicate which way is 'up'. When LookRotation() is called with only one parameter as in this post above, it implicitly passes the world vector Vector3.up as the second parameter. This allows transform.forward to be set by a single Vector3 value (since it assumes the second value needed to define a rotation).
This answer satisfies me, because I understand why Transform.forward setter is "mathematically not correct". In my pinion "mathematically correct" setter should use Quaternion.FromToRotation() ins$$anonymous$$d of Quaternion.LookRotation(), because Quaternion.FromToRotation() gives you smallest angle needed to rotate forward to reach new direction.
But Quaternion.LookRotation() is more convenient from the game dev point of view, beucase Quaternion.FromToRotation() will give you unwanted roll angle in your coordinate system, and Quaternion.LookRotation() with default up vector will not (right.y will be always 0.0).
Another way to look at is it that it's just math, and doesn't know how you're using it.
If you use it every frame, making a small change, then respecting current spin seems natural. But someone else might have a 1-time transform.forward=Vector3.forward;
to snap it back to standard facing. They'd be confused if it gave random-see$$anonymous$$g spins. And it can't figure out to work differently each way.
Answer by Owen-Reynolds · Mar 09, 2015 at 07:55 PM
It's a misunderstanding of what these are. transform.forward
is just a simple Vector3. It's a length one direction vector -- your personal blue arrow. It has no right or up vector. It isn't missing. It just can't have one.
LookAt gives a rotation/quaternion. It has an extra part. It aims down a direction, with a local z-spin (the thing which is normally set to UP.) 'LookAt` says "OK, this is a Vector3 direction that has no spin, since directions can't even have spins. I'm going to aim this way and also make-up a spin and add it, to get a Quaternion."
Yes, I know that forward is "just" a simple vector. But please notice, that forward's setter has some logic - when you change forward, then Transform also changes rotation component, with the result that right and up vector also changes.
Ah, I see your point. Having a setter for transform.forward
is just junk. Should be readOnly. I think it's only there because most people will know not to use it, but it sort of works for people who haven't learned LookAt yet (yes, I've seen people use it that way.)
Answer by toddisarockstar · Mar 10, 2015 at 04:10 AM
transform.forward is just an easier way to say it. its a feature that the friendly unity developers gave us that requires a couple less milliseconds time for a cpu to figure if it matters. Transform.LookAt() requests an unnessassary calculation from the game engine and your script waits for a return between TWO points. it may not matter to a lot of projects but if you had a game calculating 100 objects every frame it would matter. think of transform.forward as a shortcut.
you can do really basic stuff with out euler angles but really there is a lot of stuff you cant do without them. so you will eventually need to learn. hopefully before you end up banging your head against the keyboard trying to figure out why you cant get a script to do what you want.
actually, transform.forward is a euler angle. it's an exact abbreviation for Quaderton.Euler(0,0,1)
as you could guess...Quaderton.Euler(0,0,-1) is backwards and so on....
eulers are actually simpler to script and some funtions you need to call rely on them!
Hmm, now I'm totally confused;) What do you mean that transform.forward is a Euler angle? From the user point of view, it is just a vector pointing some direction. And transform.forward IS NOT equal to Quaternion.Euler(0, 0, 1) (I suppose you mean Quaternion, not Quaderton). Quaternion.Euler(0, 0, 1) returns rotation around Z axis by 1 degree
The confusion might be that EulerAngles and Directions are both Vector3s. But directions are added to positions: transform.position+transform.forward
.
If you're facing right, your forward is (1,0,0) and your EulerAngles are (0,90,any).
$$anonymous$$ost people start already know EulerAngles pretty well. Every knows 90,180,270. The hard part is using quaternions directly, and not even trying to think of EulerAngles.
Answer by tanoshimi · Mar 09, 2015 at 06:12 PM
It's unlikely you'll get an authoritative answer, because that would require knowledge of internal workings of Unity that the community at large won't have. However, I doubt that it looks anything like your suggested implementation - to my knowledge, all internal rotation calculations are handled via Quaternions, not very Vector3 Euler angles.
Thanks for your answer. I don't use Euler angles either. What I was trying to say that I don't understand why Transform.forward works exactly the same way as Transform.LookAt()
Your answer
