8
\$\begingroup\$

Alas, I have searched, and have found no definitive answer.

When would you normalize the vertex data in OpenGL using the following command:

glVertexAttribPointer(index, size, type, normalize, stride, pointer);

I.e when would normalize == GL_TRUE; what situations, and why would you choose to let the GPU do the calculations instead of preprocessing it? All examples I have ever seen, have this set to GL_FALSE; and I cannot personally see a use for it. But Khronos aren't stupid, so it must be there for something useful (and probably common).

\$\endgroup\$

3 Answers 3

9
\$\begingroup\$

The "normalized" parameter affects the use of fixed point values.

This doc says the parameter "Specifies whether fixed-point data values should be normalized (GL_TRUE) or converted directly as fixed-point values (GL_FALSE) when they are accessed."

Further, this one states "For glVertexAttribPointer, if normalized is set to GL_TRUE, it indicates that values stored in an integer format are to be mapped to the range [-1,1] (for signed values) or [0,1] (for unsigned values) when they are accessed and converted to floating point. Otherwise, values will be converted to floats directly without normalization."

In summary, if you're not using fixed point values, you don't need to care. If you do, this flag controls whether (for example) byte value 128 should be 0.5 or 128.0.

\$\endgroup\$
4
  • 3
    \$\begingroup\$ This doesn't really answer the question, I already understood what it does, but I wanted to know when it would actually be applicable to a 'common' implementation. \$\endgroup\$ Mar 15, 2011 at 13:53
  • 2
    \$\begingroup\$ I'm pretty sure it was relevant back when many mobile applications used primarily fixed point math and did not want to touch floating point math. Another possibility is that sometimes you might want to store data in a more compact way, say, in bytes, if the precision is enough, and let OpenGL convert the bytes into 0..1 range. \$\endgroup\$ Mar 15, 2011 at 13:57
  • \$\begingroup\$ It's still relevant. Think of UV coords for example. You might not want to waste space and store it as a float2, so you store it as 2 uint8 instead as an optimization and set the normalize flag so that you will get [0, 1] range instead of [0, 256] in the program. \$\endgroup\$
    – void
    Aug 5, 2011 at 13:47
  • \$\begingroup\$ Is 128 going to become 0.5 or 128/255=slightly higher? \$\endgroup\$
    – riv
    Aug 9, 2015 at 0:03
12
\$\begingroup\$

This is an old question, but the current answer doesn't really explain what you would use them for.

It's all about saving space. And with vertex attributes, less space can mean higher performance (if you're vertex transfer bound).

Colors typically don't need much more than 8-bits per component. Sometimes you need 16-bits, if it's a HDR light value or something. But for surface characteristics (which is what most vertex attributes are), 8 bits is fine. So unsigned normalized bytes are a good vertex format.

Texture coordinates do not need 32-bits of floating-point precision. A 16-bit value from [0, 1] is sufficient. So normalized unsigned shorts are a reasonable vertex format.

Normals never need 32-bits of precision. They're directions. 8-bit signed normalized bytes tend to be a bit small, but 10-bit normalized values are good enough most of the time. OpenGL (3.3+) even allows you to use 10-bit normals via a 10/10/10/2 bit packed format, stored in a single 32-bit unsigned integer.

You can even play games with vertex positions, if you find yourself in grave need of more memory.

Without normalization, you would have to waste precious cycles in your shader dividing byte attributes by 255.0. Why do this, when the hardware can do it for free?

\$\endgroup\$
5
  • \$\begingroup\$ A nice answer. But is the overhead of the division floating point math comparable to a decrease of normal size of 50%? (Ie 32bit to say 16bit); on MODERN hardware. Especially since, we don't really need to worry about too much memory (at least in my case anyway). \$\endgroup\$ Aug 5, 2011 at 7:22
  • 1
    \$\begingroup\$ @Daniel: Well, let's think about it. On "MODERN hardware", the overhead of passing normalized values is... zero. The overhead of doing the division in the shader is... non-zero. No matter how vanishingly small it is, it's still larger than zero. Not to mention the bandwidth savings of sending a 32-byte block of vertex data rather than a 64+-byte block. Oh, and the shader doesn't have to be specially programmed; you can use the same shader to take normalized or float values. If you put the division in the shader, now you need new shaders for different sizes of vertex data. \$\endgroup\$ Aug 5, 2011 at 7:43
  • \$\begingroup\$ Thanks for the nice answer. I'll definetly keep it in mind, it isn't necessary at the moment as I'm sending aligned vertex data, but as I add more information it may not be the same, and this might be a great benefit, both in caching and throughput. \$\endgroup\$ Aug 5, 2011 at 9:51
  • \$\begingroup\$ Any strategies on how to convert the normal (stored currently in a sequence of (3x) 32 bit floats) to a 32 bit int (10/10/10/2)? \$\endgroup\$ Sep 5, 2011 at 4:50
  • \$\begingroup\$ @Daniel: If you're asking how to use the ARB_vertex_type_2_10_10_10_rev extension, then I suggest you read the extension spec I just linked to. If you're asking how to personally do the bit manipulation, I'd suggest a C-style struct that contains bit fields. \$\endgroup\$ Sep 5, 2011 at 5:10
0
\$\begingroup\$

Imagine you have a mesh with high-precision normals and another mesh with low. With attribute normalization you can use the same shader but pack the second mesh's normals in bytes.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .