I am looking into packing some stuff more compactly for OpenGL, but I have some problems coding that. For normals, it's recomended to use GL_INT_2_10_10_10_REV​ format, which is basically 10bits per normal (x,y,z) and 2 bits left over. Right now all normals are floats, 32bit per normal. This packing would reduce the size by 2/3. This is how I tried it:
normal_t val = 0.0f; val = val | (0 << 30); val = val | ((unsigned int)((nz+1.0f)*0.5f*1023) << 20); val = val | ((unsigned int)((ny+1.0f)*0.5f*1023) << 10); val = val | ((unsigned int)((nx+1.0f)*0.5f*1023) << 0); Where normal_t is just a 32bit structure like color_t is right now:
template<int x> struct intmatch { }; template<int x> struct uintmatch { }; template<> struct intmatch<1> { typedef int8_t type; }; template<> struct intmatch<2> { typedef int16_t type; }; template<> struct intmatch<4> { typedef int32_t type; }; template<> struct intmatch<8> { typedef int64_t type; }; template<> struct uintmatch<1> { typedef uint8_t type; }; template<> struct uintmatch<2> { typedef uint16_t type; }; template<> struct uintmatch<4> { typedef uint32_t type; }; template<> struct uintmatch<8> { typedef uint64_t type; }; typedef uintmatch<sizeof(gs_scalar)>::type color_t; typedef intmatch<sizeof(gs_scalar)>::type uv_t; typedef intmatch<sizeof(gs_scalar)>::type normal_t; I use 1023, because that is the biggest number you can hold it 10bits. All normals are from -1 to +1, so what I do is offset it (add +1.0) and scale (multiply by 0.5), then I multiply by 1023 and move the bits in place. I don't know how to really unpack it to see if it's correct though. I tried this:
printf("Normal before packing %f, %f, %f after unpacking %f, %f, %f\n", nx,ny,nz,(double)(val & 1023)/1023.0-1.0,(double)((val & 1023)>>10)/1023.0-1.0,(double)((val & 1023)>>20)/1023.0-1.0); But it shows 1.0 for ny and nz when it shouldn't. nx is also incorrect. I know there will be a slight loss of precision, but it shouldn't matter for normals.
The second thing that is encouraged to pack is UV coordinates. I see recommendations for them being SHORT. I can't seem to pack them either. Then there is the problem that UV's are not limited to +-1.0. Normally they are, but if you want the texture to repeat, you give values out of this range. If we pack SHORT as in integer, then we cannot have that (as it will normalize and change to +-1.0 when sending to GPU). A half-float could work though. But I don't know how to pack half-floats either.
tl;dr - How to pack 3 floats in 1 float by having 10bit integer each? How to pack 2 floats in 1 float having 16bit float each?
|