Sunday, November 6, 2011

Optimizing methods, Unitizing vectors

Speeding up small but often used functions can have a big result if they're something you're doing many times each frame.

In this post we'll look at a very commonly used technique in 3D game programming, unitizing/normalizing of a 3D vector. Unitizing vectors is needed for all kinds of things like finding distances, angles between directions (dot product), A.I., rendering techniques, finding cross products.
void Vector3::Unitize()
{
    x /= GetLength();
    y /= GetLength();
    z /= GetLength();
}

The above version of Unitize() is easy readable, but about as far from optimized as you can get. The compiler may optimize this a bit for you, but lets do as much as we can ourselves to see what could be faster.

1.) We're calling GetLength()three times, we should call it once and use that result instead. Length is somewhat expensive because it requires using a square root calculation.
2.) Rather than dividing each component by 'length', we could multiply each component by 1.0f / length. Multiplications are almost always faster than division.
3.) Rather than multiplying each component by 1.0f / length we could store 1.0f / length in a variable and use that in place to save 2 extra division calculations.
4.) Declare our function inline, which helps the chances that the compiler will choose to inline the method in the final machine code, which saves a function call. Standard function calls have a small expense to them.

Let's see what we have ended up with:
inline void Vector3::Unitize()
{
    const float inverseLength = 1.0f / GetLength(); 
    x *= inverseLength;
    y *= inverseLength;
    z *= inverseLength;
}

Please note, premature optimization can be wasteful, I prefer to wait until my program is having performance issues, and then I profile to find out what is slow and then target that. Even if a profiler told you that your normalization function was taking up a lot of your program's time, you might find that the compiler has already optimized it to the level we see above. You might be better off finding ways to not call certain functions as often as you are, for example, to help improve performance, rather than optimize the functions themselves. Also, anytime you try and optimize something that is already working you have a chance of causing new bugs, or possibly making performance worse rather than better. But, knowledge is power, if you know an efficient way of doing something, and you know it works, then you might as well do it that way the first time.

No comments:

Post a Comment