In my pet project video memory started to become an issue, therefore I had a look at various techniques to minimize the memory footprint. I tried using GL_INT_2_10_10_10_REV
, but I get lighting artifacts using my packing method. These artifacts seem to be not a result of inaccuracies, because using a normalized char[3]
or short[3]
works flawlessly. Because of otherwise useless padding I would prefer to use the more space efficient GL_INT_2_10_10_10_REV
.
This is the packing code:
union Vec3IntPacked {
int i32;
struct {
int a:2;
int z:10;
int y:10;
int x:10;
} i32f3;
};
int vec3_to_i32f3(const Vec3* v) {
Vec3IntPacked packed;
packed.i32f3.x = to_int(clamp(v->x, -1.0f, 1.0f) * 511);
packed.i32f3.y = to_int(clamp(v->y, -1.0f, 1.0f) * 511);
packed.i32f3.z = to_int(clamp(v->z, -1.0f, 1.0f) * 511);
return packed.i32;
} // NOTE: to_int is a static_cast
If I am reading the spec correctly (section 10.3.8, "Packed Vertex Data Formats" and conversion rules in 2.1 and 2.2), this should work, but well it doesn't.
I should also note, that the above code was tested on multiple OSs (all 64bit though, but int
should still be 32 bit nethertheless) and graphics card vendors to check whether it was a driver related issue.
Furthermore the OpenGL 3.3 core profile is used.
The vertex structure is composed as following:
struct BasicVertex {
float position[3];
unsigned short uv[2];
int normal;
int tangent;
int bitangent;
} // resulting in a 4-byte aligned 28 byte structure
Hopefully I provided sufficient information and someone can shed some light on how to properly pack normals into GL_INT_2_10_10_10_REV
.