- Home /
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?
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" );
}
}
(1,1,1) isn't normalized -- 1 right, 1 forward and 1 up is longer than length one.
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.
@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.
@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!
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();
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.
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.
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; }
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
Follow this Question
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