@ , @26sramirez6 , here are the fundamentals.
Every GameObject has a Transform. We will only consider 3D here, so it’s a plain old Transform.
The Transform has THREE key elements: a Vector3 .position
, a Quaternion .rotation
, and an optional Transform .parent
. Just about everything else is just window dressing to make it easier to work with these three things.
So the Vector3 position is pretty obvious to figure out that it is considered the position in 3D space of the object. But we know we will not be working with atom-sized objects, but instead whole models which take up some bulky 3D space, right? Which means its orientation is important. One part of the orientation puzzle is that Quaternion .rotation, but we will get back to that later.
For now, let’s JUST focus on the model of an ogre or spaceship or poker card which you just imported in from another program. I’ll go with the ogre, please.
In the 3D modeling program called Blender, they have set up certain conventions, or arbitrary choices which users will tend to agree with, although everyone also agrees they’re arbitrary and you can overcome them with mental energy. In Blender, vectors like (0, 0, +1) are “upward” and a grid is drawn in the X/Y plane to reinforce that convention.
The same thing goes with Unity, but they chose a different set of arbitrary conventions. In Unity, (0, 0, +1) is “forward”, not upward. In Unity, (0, +1, 0) is “upward” instead. And since Unity works in a left-hand coordinate system, then (+1, 0, 0) must be perpendicular to the other two in the “rightward” direction. A grid is drawn in the X/Z plane to reinforce that mental idea that +Y is up.
Before we tackle Transform’s similar members, the Vector3 class in Unity has some helper methods/properties to get useful constant vectors:
Vector3.zero
is (0, 0, 0)
Vector3.one
is (1, 1, 1)
Vector3.right
is (1, 0, 0)
Vector3.up
is (0, 1, 0)
Vector3.forward
is (0, 0, 1)
Vector3.left
is (-1, 0, 0)
Vector3.down
is (0, -1, 0)
Vector3.back
is (0, 0, -1)
They just added all these for your convenience, and you can use them for anything but they reinforce their conventions pretty strongly with those names. They could have called them “north” or “blue” but they didn’t.
With those conventions, most Unity users work hard to ensure that their models will be rotated appropriately in the import process, so that your ogre’s nose is facing in the +Z direction while standing with the feet near (0, 0, 0) and the head somewhere in the +Y direction, depending on how bad the ogre’s hunchback has been bent.
Now back to Transform.rotation. This is a Quaternion, which you may understand from that name, represents a rotation in 3D space. It’s a hypercomplex number (xi+yj+zk+w), but we won’t get into the details. What you need to know is that a Vector3 multiplied by a Quaternion will rotate the vector in 3D space by a specific amount in a specific arc.
As a convenience, Transform simply adds similar methods/properties based on the Vector3 standards.
- Transform.forward has been calculated for you as
Vector3.forward * Transform.rotation
.
- Transform.up has been calculated for you as
Vector3.up * Transform.rotation
.
- Transform.right has been calculated for you as
Vector3.right * Transform.rotation
.
That’s all there is to Transform.forward. It’s a handy way to get a 1-unit-long vector that faces in the same direction as your imported ogre’s facing. If you want to move the ogre one giant ogre step forward, Transform.position += Transform.forward * one_giant_ogre_step
.
If you rotate the ogre, or move the ogre, away from its original arrangement, well, now you have opened up a whole ball of worms. Let’s say you rotate the ogre by 45 degrees toward his right hand. Now his nose points in the northeast direction, not north as before. If you want to put a hat on the ogre’s head, you will now need to think in the ogre’s local space where ogre.transform.forward no longer matches the world space of Vector3.forward. The Transform now has to maintain two whole coordinate systems, to let you work in either world space or local space, depending on which is convenient. Well, Transform didn’t have to do that, but Transform does that so that your code does not have to take on the burden and the bug-fighting involved in constantly calculating such things for yourself. So look at Transform.localPosition
and Transform.localRotation
. You can modify EITHER set, and the OTHER set will get updated auto-magically, according to the appropriate transform math. Pretty neat.
What about that Transform.parent
? Well, when you first add a new GameObject, the .parent is null. If you set the parent of the ogre’s hat’s transform to be the ogre’s transform, then the ogre’s hat will MOVE with the ogre without a single line of code to be written. It’s attached, joined, locked together.
To calculate the ogre’s hat’s position in world space, you would need to do the math that combines the ogre’s hat’s position in local space relative to the ogre, and the ogre’s rotation, and the ogre’s position in local space relative to the mine cart that the ogre is riding in, and so on. It’s a huge stack of transformation math. Good thing that the Transform class does all this behind the scene, giving you both .localPosition and .position, and also .localRotation and .rotation.