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
0
Question by Halcyon2518 · Oct 19, 2011 at 07:05 PM · vector3performancenormalize

Does Vector3.Normalize() check to see if a vector is already normalized?

I tend to call Vector3.Normalize() on any direction vector after passing it to one of my functions, regardless of whether it is already normalized. (Just to be safe, and so the calling code can be flexible without having to worry about normalizing beforehand.) As I recall, though, normalizing requires the costly square root operation. I'm not sure how anyone would know, but I'd like to try asking anyway: Does the default Normalize() function check the length of a vector before proceeding, or do I need to be a little more careful about performance?

Comment
Add comment
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

4 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Veehmot · Oct 19, 2011 at 08:22 PM

With these things, the best way to be sure is to try for yourself!

I created an already normalized vector (1,1,1) and performed 2 operations:

  • myVect.Normalize();

  • if (myVect.magnitude != 1) myVect.Normalize();

These cover your question, but I added 2 operations more:

  • vectToSet = myVect.normalized;

  • if (vectToSet.magnitude != 1) vectToSet = myVect.normalized;

vectToSet being another already normalized vector (also 1, 1, 1).

Results

 +-----------------------------------+-------------------+
 |             Operation             | Time (in seconds) |
 +-----------------------------------+-------------------+
 | No Checking:                      | 0.6968285         |
 | Checking:                         | 0.2933789         |
 | No Checking (Vector3.normalized): | 0.7552377         |
 | Checking (Vector3.normalized):    | 0.2898996         |
 +-----------------------------------+-------------------+

So, seeing the results we can say that no, it doesn't check if it's normalized.

The code


 using UnityEngine;
 using System.Collections;
 public class NormalizeCheckTest : MonoBehaviour {
     // Use this for initialization
     void Start () {
         
         int iterations = 9999999;
         
         float s;
         float e;
         
         Vector3 myVect = new Vector3(1, 1, 1);
         Vector3 vectToSet = new Vector3(1, 1, 1);
         
         /////////////////////////////////////////////  No Checking
         
         s = Time.realtimeSinceStartup;
         
         for (int i = 0; i < iterations; i++) {
             myVect.Normalize();
         }
         
         e = Time.realtimeSinceStartup;
         e -= s;
         
         Debug.Log("No Checking: "+e.ToString() + " seconds" );
         
         ///////////////////////////////////////////// Checking
         
         s = Time.realtimeSinceStartup;
         
         Vector3 newVect = new Vector3(1,1,1);
         for (int i = 0; i < iterations; i++) {
             if (myVect.magnitude != 1) myVect.Normalize();
         }
         
         e = Time.realtimeSinceStartup;            
         e -= s;
         
         Debug.Log("Checking: "+e.ToString() + " seconds" );
         
         /////////////////////////////////////////////  No Checking (Vector3.normalized)
         
         s = Time.realtimeSinceStartup;
         
         for (int i = 0; i < iterations; i++) {
             vectToSet = myVect.normalized;
         }
         
         e = Time.realtimeSinceStartup;
         e -= s;
         
         Debug.Log("No Checking (Vector3.normalized): "+e.ToString() + " seconds" );
         
         ///////////////////////////////////////////// Checking (Vector3.normalized)
         
         s = Time.realtimeSinceStartup;
         
         for (int i = 0; i < iterations; i++) {
             if (vectToSet.magnitude != 1) vectToSet = myVect.normalized;
         }
         
         e = Time.realtimeSinceStartup;            
         e -= s;
         
         Debug.Log("Checking (Vector3.normalized): "+e.ToString() + " seconds" );
         
     }
 }
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 Owen-Reynolds · Oct 19, 2011 at 11:57 PM 3
Share

(1,1,1) isn't normalized -- 1 right, 1 forward and 1 up is longer than length one.

avatar image Halcyon2518 · Oct 20, 2011 at 02:16 AM 1
Share

I hope you didn't write all that just for me, lol. Whatever the case, thank you! Benchmarks like that are not something I'm in the habit of doing; I'll be sure to run future tests myself, though. It would appear that I must be a little more cautious about what I demand from calling code when direction vectors are concerned.

avatar image Veehmot · Oct 20, 2011 at 02:47 AM 0
Share

@Owen Reynolds: Indeed! You are correct. Either way, the test will serve the same purpose, just in the first iteration of the check operation will have to actually normalize the vector.

avatar image Veehmot · Oct 20, 2011 at 02:49 AM 0
Share

@Halcyon2518: Yes I did write it for this answer, I thought it would be something good to be stored in this knowledge base. Just remember not to optimize if it involves to adopt a complex system. Follow the $$anonymous$$ISS rule!

avatar image
1

Answer by OrkhanAlikhanov · Jul 08, 2016 at 01:13 PM

From decompiled UnityEngine.dll we have this:

 public Vector3 normalized
 {
     get
     {
         return Vector3.Normalize(this);
     }
 }

Where Vector3.Normalize() methods are defined as:

 public static Vector3 Normalize(Vector3 value)
 {
     float num = Vector3.Magnitude(value);
     if (num > 1E-05f)
     {
         return value / num;
     }
     return Vector3.zero;
 }
 public void Normalize()
 {
     float num = Vector3.Magnitude(this);
     if (num > 1E-05f)
     {
         this /= num;
     }
     else
     {
         this = Vector3.zero;
     }
 }

Where Vector3.Magnitude() decompiled into:

 public static float Magnitude(Vector3 a)
 {
     return Mathf.Sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
 }

And Vector3.magnitude has also the same Mathf.Sqrt() implementation:

 public float magnitude
 {
     get
     {
         return Mathf.Sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
     }
 }

From the above decompiled codes it is obvious that the Vector3.Normalize() method does call the Vector3.Magnitude() method which uses Mathf.Sqrt(). So Unity does not check whether vector is already normalized or not. Never use this:

 if (myVect.magnitude != 1.0f) myVect.Normalize();

Because Vector3.Normalize() and Vector3.magnitude both calls Mathf.Sqrt() and calling Mathf.Sqrt() twice is awful. so use either this:

 myVect.Normalize();

which you would call Mathf.Sqrt() just once.

Or this, depending on your choice:

 if (myVect.sqrMagnitude != 1.0f) myVect.Normalize();

Above can be improved by using Mathf.Approximately() :

 if (!Mathf.Approximately(myVect.sqrMagnitude, 1.0f)) myVect.Normalize();
Comment
Add comment · 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
0

Answer by Owen-Reynolds · Oct 20, 2011 at 12:29 AM

A general rule for "check to skip this step" is to consider: 1) how often will the check save me time vs. waste time, 2) how cheap is the check compared to what I might skip.

For normalizing, the check will almost never save you time (how many random Vectors happen to be length 1?) and the time to check adds an extra maybe 10%(?) (sqrMagnitude is x*x+y*y+z*z, plus two compares for Approximate.)

If you have something taking two sources of Vectors: normalized and random, most people use two front ends: "DoStuff" and "DoStuffWithNormedVector," where doStuff normalizes then calls the other one.

Comment
Add comment · Show 1 · 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 Halcyon2518 · Oct 20, 2011 at 02:15 AM 1
Share

I was more or less referring to having nested utility functions, so that one method normalizes before passing, then the next normalizes again before finally using the vector. I didn't intend to set up a check myself; I was asking if there was any sort of internal check in Vector3.Normalize(). But you're right, it would be inefficient for it to do that; I should have realized.

avatar image
0

Answer by michidk · Jul 06, 2016 at 09:06 PM

A quick update on this topic: Unity now does the check: public void Normalize() { float magnitude = this.magnitude; if ((double) magnitude > 9.99999974737875E-06) this = this / magnitude; else this = Vector2.zero; }

Comment
Add comment · Show 1 · 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 · Jul 06, 2016 at 09:48 PM 0
Share

Nothing has changed since 2011. Normalize always has done this. This is not a check if it's already normalized but if the vector is too close to "0.0f". If it's too close to zero the vector can't be normalized reliably and it simply return Vector3.zero (0,0,0) in this case.

The most expensive operation during the normalizing operation is getting the magnitude as it does $$anonymous$$athf.Sqrt(x*x + y*y + z*z). The results in the accepted answer are pretty nonsense as most of the "time" is consumed by calling overhead. Also "realtimeSinceStartup" is a bad choice for measuring time critical things.

The square root isn't that bad as most people think. If you don't call it literally thousands of times per frame you shouldn't even think about it.

If you want to check if it's already normalized you should check the "sqr$$anonymous$$agnitude" which also should be "1.0f" / "close to 1.0f". The sqr$$anonymous$$agnitude just does (x*x + y*y + z*z)

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

8 People are following this question.

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

Related Questions

Normalizing vector doesn't give a constant direction. 2 Answers

Normalizing a cube made up of 24 meshes into a Sphere 0 Answers

Lerping Issue 1 Answer

Ball not rolling fast on first movement 0 Answers

Vector2 vs Vector3 performance? 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