- Home /
Efficiency of transform.forward, up, and right
When you are moving around a game object, does anyone know if the transform vectors are updated every time rotation or local rotation is, or if the property calculates the rotated vector every time you access it?
If I need to call the global forward vector numerous times per update without changing the rotation in between, I'd rather store transform.forward in a separate Vector3 rather than having Unity calculate transform.rotation*Vector3.forward every time I call transform.forward.
I don't have Unity Pro, otherwise I'd benchmark it with the profiler myself . . .
I know I can always just take the precaution anyways, but it'd be nice to know for reference anyways. Thanks in advance!
You don't need Unity Pro to run benchmarks. Just use some kind of timer; Time.realtimeSinceStartup is fine. Or the Stopwatch class.
But I just ran a quick test of three different methods using a single game object doing 10,000,000 iterations of each. $$anonymous$$ultiple runs average out to around:
v3 = transform.forward: 625 miliseconds
v3 = transform.TransformDirection(Vector3.forward): 550 miliseconds
v3 = v3Forward: 25 miliseconds
I'm guessing thats because of certain performance differences when using properties ins$$anonymous$$d of functions. 600ms is really not much for 10mil iterations, so it does seem like very $$anonymous$$or performance differences should scale to a 75ms difference
Eric, I suppose that's true. I'll keep the stopwatch class in $$anonymous$$d if I need tests in the future.
Rorbertbu, thanks for going through the trouble of testing it out some for me.
Answer by Bunny83 · Oct 21, 2013 at 10:07 PM
Well, for example the forward property is defined as:
public Vector3 forward
{
get { return this.rotation * Vector3.forward; }
set { this.rotation = Quaternion.LookRotation(value); }
}
So when reading the forward vector Unity reads the rotation property and multiplies it with (0,0,1)
"rotation" is defined as
public Quaternion rotation
{
get
{
Quaternion result;
this.INTERNAL_get_rotation(out result);
return result;
}
set
{
this.INTERNAL_set_rotation(ref value);
}
}
and the Quaternion - Vector multiplication looks like:
public static Vector3 operator *(Quaternion rotation, Vector3 point)
{
float num = rotation.x * 2f;
float num2 = rotation.y * 2f;
float num3 = rotation.z * 2f;
float num4 = rotation.x * num;
float num5 = rotation.y * num2;
float num6 = rotation.z * num3;
float num7 = rotation.x * num2;
float num8 = rotation.x * num3;
float num9 = rotation.y * num3;
float num10 = rotation.w * num;
float num11 = rotation.w * num2;
float num12 = rotation.w * num3;
Vector3 result;
result.x = (1f - (num5 + num6)) * point.x + (num7 - num12) * point.y + (num8 + num11) * point.z;
result.y = (num7 + num12) * point.x + (1f - (num4 + num6)) * point.y + (num9 - num10) * point.z;
result.z = (num8 - num11) * point.x + (num9 + num10) * point.y + (1f - (num4 + num5)) * point.z;
return result;
}
So what happens on the managed side is quite clear and not that much calculations. However we don't know what happens in "INTERNAL_get_rotation" since it's a native code function. It might request an update of all parents to actually calculate the quaternion. We simply don't know.
So in general if you use one of these properties multiple times inside the same function, store it in a local variable. As you already said that of course makes only sense if the value doesn't change between the different uses inside the function.
Global positions and rotations are most likely calculated with a recursive function that goes up the hierarchy, so thats probably what INTERNAL_get_rotation
does
I was wondering how you got such detailed code, but I managed to figure it out: I had no idea you could go to the declaration of Unity's defined functions and check out the internal Unity code. Doing so tells me exactly what I wanted to know! Thanks!
@LunaArgenteus:
Well, just use ILSpy ;)
@Benproductions:
Well, i'm pretty sure that Unity will cache the result internally, but you will never know unless we would get some insight from UT (which is very unlikely to happen) ;)
You did miss off the fact that transform
itself is not cached. Unity, rather counter-intuitively, uses a GetComponent call to find the Transform attached to a GameObject each time you refer to the transform
property, which is where I suspect a lot of the overhead is going.
@Hoeloe Yep! Thats why I presume they aren't caching anything else either. They provide the base functionality and allow the user to expand. In some cases I don't want/need to cache, so I don't ;)
Answer by Benproductions1 · Oct 21, 2013 at 10:03 PM
Hello,
Although I am presuming some design decisions about Unity, this is what it should be like.
transform.forward
is the same as doing transform.TransformDirection(Vector3.foward)
, which is the same as doing transform.rotation*Vector3.forward
Doing transform.eulerAngles = angles
is the same as doing transform.rotation.Set(Quaternion.Euler(angles))
Any global properties such as position
and rotation
are defined as so:
function get rotation() : Quaternion {
if (parent) {
return localRotation * parent.rotation;
}
return localRotation;
}
function get position() : Vector3 {
if (parent) {
return parent.TransformPoint(localPosition);
}
return localPosition;
}
function TransformPoint() : Vector3 {
return rotation * Vector3.Scale(lossyScale, position);
}
I know that I'm not 100% right, but the general idea stands. Unless you are accessing local spacial information, you are recursively calculating it. Every time.
Hope this helps,
Benproductions1
PS: I'm going to keep this as a community Wiki so people can fix my code ;)