- Home /
InverseTransformPoint vs Vector3.Distance which is cheaper?
If I already have an object looking at something, I'm just wondering which is cheaper on the CPU.. If I do:
distance = myTransform.InverseTransformPoint(target.transform.position).z
or...
distance = Vector3.Distance(myTransform.position,target.position);
He might not have a profiler. If you want, kramcomposer, you can download the Unity Pro trial if you haven't already and run each function 1 million times and see which is proven to be faster in milleseconds. If I had to guess though, InverseTransformPoint is going to be far faster, although it weirds me out that you used .z, it'll work well if myTransform is looking at the target, but it'll break apart in all other cases afaik.
[edit:] he can use the lesser known ways of profiling:
"Debug.Log(string.Format("Is high resolution: {0}, accuracy: {1} ns", Stopwatch.IsHighResolution, 1e9 / Stopwatch.Frequency));"
from: http://forum.unity3d.com/threads/147661-Square-Root-runs-1000-times-in-0.01ms
But he probably wouldn't have known about this method, since I figured it out a week ago and I've been program$$anonymous$$g 2 years.
@$$anonymous$$att Downey, maybe you're right: @Scroodge and me showed fast ways to find the distance, but all of them used transform.forward; since this is a property, it's possible that Unity actually calculates its value on the fly each time we read it, what probably would mean an internal InverseTransformPoint operation.
transform.forward internally is
public Vector3 forward { get { return (Vector3) (this.rotation * Vector3.forward); } set { this.rotation = Quaternion.LookRotation(value); } }
Well, this lets things more equal: vector rotation with quaternion takes about the same time as a vector by matrix multiplication (at least that's what $$anonymous$$ Eberly says in his books)
Answer by ScroodgeM · Aug 26, 2012 at 11:32 AM
new, correct answer:
Vector3 v1 = t1.position; Vector3 v2 = t2.position; Vector3 vector = new Vector3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); result = (float)System.Math.Sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
after all that was wrote here i made a simple test for calculation speed. here is results for 10M calculations:
* Vector3.Dot | time taken (ms):2579.1475 * InverseTransformPoint(...).z | time taken (ms):2239.1281 * Vector3.Dot with RotatedForward | time taken (ms):2192.1254 (my optimization of Vector3.Dot) * (v1-v2).magnitude | time taken (ms):1461.0836 * Vector3.Distance | time taken (ms):1393.0797 * custom(above) | time taken (ms):1313.0751
i don't understand why sqrt is so fast... may be somebody want to repeat this test? below the script i used for test, all you need is attach it to camera in empty scene and run.
DistanceCalculatorCheck.cs
using UnityEngine; using System.Collections;
public class DistanceCalculatorCheck : MonoBehaviour { public int iterations = 10000000; void Start() { Transform t1 = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform; Transform t2 = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform; t1.position = Random.insideUnitSphere 1000f; t2.position = Random.insideUnitSphere 1000f; t1.LookAt(t2); //declare variables System.DateTime start; System.TimeSpan difference; float result = 0;
//begin test 1 start = System.DateTime.Now; for (int i = 0; i < iterations; i++) { result = Vector3.Distance(t1.position, t2.position); } difference = System.DateTime.Now - start; Debug.Log(string.Format("type:{0} | time taken (ms):{1} | result:{2}", "Vector3.Distance", difference.TotalMilliseconds, result));
//begin test 2 start = System.DateTime.Now; for (int i = 0; i < iterations; i++) { result = (t1.position - t2.position).magnitude; } difference = System.DateTime.Now - start; Debug.Log(string.Format("type:{0} | time taken (ms):{1} | result:{2}", "(v1-v2).magnitude", difference.TotalMilliseconds, result));
//begin test 3 start = System.DateTime.Now; for (int i = 0; i < iterations; i++) { result = t1.InverseTransformPoint(t2.transform.position).z; } difference = System.DateTime.Now - start; Debug.Log(string.Format("type:{0} | time taken (ms):{1} | result:{2}", "InverseTransformPoint.z", difference.TotalMilliseconds, result));
//begin test 4 start = System.DateTime.Now; for (int i = 0; i < iterations; i++) { result = Vector3.Dot(t2.position - t1.position, t1.forward); } difference = System.DateTime.Now - start; Debug.Log(string.Format("type:{0} | time taken (ms):{1} | result:{2}", "Vector3.Dot", difference.TotalMilliseconds, result));
//begin test 5 start = System.DateTime.Now; for (int i = 0; i < iterations; i++) { result = 2f * Vector3.Dot(t2.position - t1.position, RotatedForward(t1.rotation)); } difference = System.DateTime.Now - start; Debug.Log(string.Format("type:{0} | time taken (ms):{1} | result:{2}", "Vector3.Dot with RotatedForward", difference.TotalMilliseconds, result));
//begin test 6 start = System.DateTime.Now; for (int i = 0; i < iterations; i++) { Vector3 v1 = t1.position; Vector3 v2 = t2.position; Vector3 vector = new Vector3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); result = (float)System.Math.Sqrt(vector.x vector.x + vector.y vector.y + vector.z vector.z); } difference = System.DateTime.Now - start; Debug.Log(string.Format("type:{0} | time taken (ms):{1} | result:{2}", "custom", difference.TotalMilliseconds, result)); } public static Vector3 RotatedForward(Quaternion rotation) { return new Vector3( rotation.x rotation.z + rotation.w rotation.y, rotation.y rotation.z - rotation.w rotation.x, 0.5f - (rotation.x rotation.x + rotation.y * rotation.y)); } }
I've made a $$anonymous$$athf.Sin benchmark just a few days ago. I've implemented a lookup table for Sin, but the $$anonymous$$athf version was 1.5 times faster than the lookup :D. The $$anonymous$$ath functions are quite fast in modern PCs due to the great hardware implementation.
I run your script and got this result on my quite old Pentium D
Vector3.Dot | 5359.375
InverseTransformPoint.z | 4640.625
Vector3.Dot with RotatedForward | 4265.625
(v1-v2).magnitude | 3109.375
custom | 2921.875
Vector3.Distance | 2812.5
edit
I repeated it, but i started it from OnGUI (with a button) to prevent hicups of background threads during game start.
Vector3.Dot | 5171.875
InverseTransformPoint.z | 4593.75
Vector3.Dot with RotatedForward | 4281.25
(v1-v2).magnitude | 3125
custom | 2875
Vector3.Distance | 2859.375
Well, the result is almost the same ;) Strangely Vector3.Distance is still a little faster than your custom implementation. That's indeed strange since it's essential the same and Vector3.Distance has function call overhead, but maybe it's better for the cache?!?
$$anonymous$$aybe we should just ignore this difference since our time accuracy is really bad ;)
Vector3.Distance internally implemented as
public static float Distance(Vector3 a, Vector3 b) { Vector3 vector = new Vector3(a.x - b.x, a.y - b.y, a.z - b.z); return $$anonymous$$athf.Sqrt(((vector.x * vector.x) + (vector.y * vector.y)) + (vector.z * vector.z)); }
$$anonymous$$athf.Sqrt internally implemented as
public static float Sqrt(float f) { return (float) $$anonymous$$ath.Sqrt((double) f); }
so i don't understand why Vector3.distance is faster then custom implementation without any calls between methods... btw, i know now that Vector3.Distance is really faster that any other calculations without square root.
Funny thing: the dot product takes more time than the matrix multiplication! Could it be due to some specialized hardware matrix operation?
@Scroodge$$anonymous$$: Even the quaternion - vector multiplication is a matrix multiplication ;) The quaternion is "converted" into a 3x3 rotation matrix. InverseTransformPoint uses all parts of the object matrix (position and rotation / scale).
Answer by ScroodgeM · Aug 25, 2012 at 01:26 PM
more accuracy:
Vector3.Dot(target.position - myTransform.position, myTransform.forward);
dot product for two Vector3 is x1x2+y1y2+z1z2
less accuracy and needs check for x!=0:
(target.position - myTransform.position).x / myTransform.forward.x;
hardcode and hardcore
let's try to optimize this:
Vector3.Dot(target.position - myTransform.position, myTransform.forward);
transform.forward is
public Vector3 forward { get { return (Vector3) (this.rotation * Vector3.forward); } set... }
so, distance is
Vector3.Dot(target.position - myTransform.position, myTransform.rotation * Vector3.forward);
now, what is Quaternion * Vector3:
public static Vector3 operator *(Quaternion rotation, Vector3 point) { Vector3 vector; 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; vector.x = (((1f - (num5 + num6)) * point.x) + ((num7 - num12) * point.y)) + ((num8 + num11) * point.z); vector.y = (((num7 + num12) * point.x) + ((1f - (num4 + num6)) * point.y)) + ((num9 - num10) * point.z); vector.z = (((num8 - num11) * point.x) + ((num9 + num10) * point.y)) + ((1f - (num4 + num5)) * point.z); return vector; }
we have vector3 (0,0,1), so we can optimize it to:
public static Vector3 RotatedForward(Quaternion rotation) { return 2f * new Vector3( rotation.x * rotation.z + rotation.w * rotation.y, rotation.y * rotation.z - rotation.w * rotation.x, 0.5f - (rotation.x * rotation.x + rotation.y * rotation.y)); }
and now really fastest distance calculator is:
Vector3.Dot(target.position - myTransform.position, RotatedForward(myTransform.rotation));
absolutely unclear to understand, but really fast 8)
addon:
remove '2f*' from RotatedForward method and multiply to 2f final Vector3.Dot result. this will save 2 more multiplications
@Scroodge, the first alternative seems a smart and fast way to find the distance strictly in the forward direction - more than 16 times faster than InverseTransformPoint().z: it uses a single vector3 dot product, while a 4x4 matrix multiplication requires 16 vector4 dot products.
The math-magic behind this: a dot product between vectors A and B is equal to A.magnitude B.magnitude cos(angle between A and B). Since myTransform.forward (A$$anonymous$$A vector B) has length 1, the result is A.magnitude * cos(angle between A and B), which is the distance in the forward direction (A$$anonymous$$A vector B).
i've updated the answer with 'hardcode and hardcore' section 8)
Wow! This looks fast enough! It's hard to understand, of course, but that's how a good optimization always looks like (as the John Carmack's InverseSqrt algorithm mentioned in this question)
Actually it would be great when the Transform properties (forward, right, up) would be implemented like this ;). A lot people use those and it would be great to have them that way.
Well, we still could write extension methods which can be used ins$$anonymous$$d of forward, right, up.
+1 nice work
Answer by aldonaletto · Aug 25, 2012 at 01:57 PM
I suppose that the fastest alternative is none of above:
distance = (target.position - myTransform.position).magnitude;
Unity does a vector subtraction and calculates the magnitude of the result, which requires 3 subtractions, 3 multiplications, 2 additions and a square root. Vector3.Distance does about the same thing, but is a little slower, according to some users that tested it. The other alternative, InverseTransformPoint(...).z, doesn't give the same result: it measures the distance strictly in the forward direction - if the target is at 45 degrees, for instance, the value returned will be 0.707 times the actual distance. This operation also requires a 4x4 matrix multiplication, which means lots of multiplications and additions - probably taking way more time than a single square root in any machine.
CONCLUSION: If you want to measure the distance of something strictly in the object's forward direction, use InverseTransformPoint(...).z. If you want the actual distance calculated in the fastest way, use the (pointA - pointB).magnitude alternative (also recommended when you need to calculate the direction vector pointB->pointA or pointA->pointB for other purposes too). If you prefer to write a more self documented code, use Vector3.Distance(pointA, pointB).
EDITED: @Scroodge won the prize: the dot product method is the best one to find distance in the forward direction, with 3 subtractions, 3 multiplications, 2 additions and NO square root. By the way, I missed the "already have an object looking at something" part of the question.
This square root is supposedly 63% faster than the built-in one with little accuracy changes: http://blog.alladvanced.net/2011/02/21/square-root-calculation-speed-in-flash-and-unity3d/
you'll have to scroll to near the bottom or search for "63%"
Oh yes, this is the famous InverseSqrt algorithm, apparently due to John Carmack (it was first seen in the Quake source code, and calculated 1/sqrt much faster than the math processor could do with regular operations). This algorithm relies on the internal floating point format, treating the float argument as if it was a 32 integer. The crazy operation 0x5f3759df - (i >> 1) generates a good approximation of the square root, which is refined by one single iteration of the Newton numeric algorithm and produces a reasonably precise value (about 5 iterations would be necessary to reach the same precision without that hack).
EDIT: According to the link provided by @Bunny83, this magic algorithm was created probably at Sylicon Graphics in the early 1990s, and used some years after in Quake III Arena - the source code is as follows, with its original funny comments:
float Q_rsqrt( float number ) { long i; float x2, y; const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the fuck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y ( threehalfs - ( x2 y * y ) ); // 2nd iteration, this can be removed
return y;
}
Actually i don't think Vector3.Distance would be any slower ;) It's implemented like this:
Vector3 vector = new Vector3(a.x - b.x, a.y - b.y, a.z - b.z);
return $$anonymous$$athf.Sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
which is the same as your code but just one function call (+ vector3 constructor)
The subtraction operator in your case also uses the vector3 constructor and magnitude looks exactly like the second line in Distance(), but it's an additional function call. It would really be strange if Distance is slower. Sometimes it's hard to wrap your head around how the cache affects such a simple sequence of instructions.
Oh, the test case used for the fast inverse sqrt might not be representative since he uses the same value in each iteration. That's a case where the cache might "optimise" the calculation in a way that wouldn't apply to a real application. However, usually you shouldn't over-optimise everything, just when you really have issues with speed. And even then first profile what consumes the most time.
This makes sense: a good Distance implementation should be a little faster than the (v1-v2).magnitude alternative. I had not compared them myself - just read somewhere in UA that Distance was a little slower, what could be explained by a poor implementation (like the original transform.forward, for instance).