Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by kramcomposer · Aug 24, 2012 at 09:03 PM · performancedistanceoptimazation

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);
Comment
Add comment · Show 6
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Tct1856 · Aug 24, 2012 at 11:14 PM 2
Share

Why not just profile them ?

avatar image Matt-Downey · Aug 25, 2012 at 12:53 PM 2
Share

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.

avatar image aldonaletto · Aug 25, 2012 at 02:35 PM 1
Share

@$$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.

avatar image ScroodgeM · Aug 25, 2012 at 04:09 PM 1
Share

transform.forward internally is

public Vector3 forward
{
    get
    {
        return (Vector3) (this.rotation * Vector3.forward);
    }
    set
    {
        this.rotation = Quaternion.LookRotation(value);
    }
}
avatar image aldonaletto · Aug 25, 2012 at 06:03 PM 0
Share

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)

Show more comments

3 Replies

· Add your reply
  • Sort: 
avatar image
7

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)); } }

Comment
Add comment · Show 7 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Aug 26, 2012 at 01:01 PM 0
Share

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 ;)

avatar image ScroodgeM · Aug 26, 2012 at 01:32 PM 0
Share

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.

avatar image aldonaletto · Aug 26, 2012 at 01:42 PM 0
Share

Funny thing: the dot product takes more time than the matrix multiplication! Could it be due to some specialized hardware matrix operation?

avatar image ScroodgeM · Aug 26, 2012 at 01:44 PM 0
Share

where in these tests matrix multiplication is used?

avatar image Bunny83 · Aug 26, 2012 at 11:24 PM 1
Share

@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).

Show more comments
avatar image
2

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

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image aldonaletto · Aug 25, 2012 at 02:19 PM 0
Share

@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).

avatar image ScroodgeM · Aug 25, 2012 at 06:04 PM 0
Share

i've updated the answer with 'hardcode and hardcore' section 8)

avatar image aldonaletto · Aug 25, 2012 at 06:13 PM 0
Share

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)

avatar image Bunny83 · Aug 26, 2012 at 12:36 AM 0
Share

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

avatar image
1

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.

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Matt-Downey · Aug 25, 2012 at 04:29 PM 1
Share

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%"

avatar image aldonaletto · Aug 25, 2012 at 05:52 PM 2
Share

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;

}

avatar image Bunny83 · Aug 26, 2012 at 01:00 AM 1
Share

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.

avatar image aldonaletto · Aug 26, 2012 at 01:21 PM 0
Share

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).

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

12 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Performance problem with AR-App on Android 0 Answers

Simpler mesh over distance 1 Answer

Find closest "item" object by NavMesh navigation distance performantly 0 Answers

increasing shadow distance for a single object? 1 Answer

Cheapest way to get distance detection and triggered events. 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges