Hey. I’m interested in improving the packing of my vertex data to reduce its size further. In some cases I have stuff like HDR colors that don’t necessarily need 32 bits of precision. 16-bit half-floats would work just as well and save quite a bit of precision. The problem is converting 32-bit float values to 16-bit values on the Java side. My Google-fu tells me that this is more complicated than I expected if I’m going to handle special values like infinities, NaN and denormals. Has anyone already implemented this perhaps?
yes i made a port of a nvidia gameworks sample (https://github.com/NVIDIAGameWorks/OpenGLSamples/blob/master/samples/es3aep-kepler/HDR/HDRImages.cpp).
http://pastebin.java-gaming.org/dafa48a6f331b
works perfect for me. [icode]HFloat.convertFloatToHFloat(value)[/icode], short output into a buffer and a [icode]GL30.GL_HALF_FLOAT[/icode] glVertexAttribPointer for instance works as you’d expect it.
i tried the simpler half conversion like
@Deprecated @SuppressWarnings ( "FloatingPointEquality" )
public static short toHalfFloat(final float v)
{
if(Float.isNaN(v)) throw new UnsupportedOperationException("NaN to half conversion not supported!");
if(v == Float.POSITIVE_INFINITY) return(short)0x7c00;
if(v == Float.NEGATIVE_INFINITY) return(short)0xfc00;
if(v == 0.0f) return(short)0x0000;
if(v == -0.0f) return(short)0x8000;
if(v > 65504.0f) return 0x7bff; // max value supported by half float
if(v < -65504.0f) return(short)( 0x7bff | 0x8000 );
if(v > 0.0f && v < 5.96046E-8f) return 0x0001;
if(v < 0.0f && v > -5.96046E-8f) return(short)0x8001;
final int f = Float.floatToIntBits(v);
return(short)((( f>>16 ) & 0x8000 ) | (((( f & 0x7f800000 ) - 0x38000000 )>>13 ) & 0x7c00 ) | (( f>>13 ) & 0x03ff ));
}
and
@Deprecated @SuppressWarnings ( "UnnecessaryExplicitNumericCast" )
public static float toFloat(final short half)
{
switch((int)half)
{
case 0x0000 :
return 0.0f;
case 0x8000 :
return -0.0f;
case 0x7c00 :
return Float.POSITIVE_INFINITY;
case 0xfc00 :
return Float.NEGATIVE_INFINITY;
// @TODO: support for NaN ?
default :
return Float.intBitsToFloat((( half & 0x8000 )<<16 ) | ((( half & 0x7c00 ) + 0x1C000 )<<13 ) | (( half & 0x03FF )<<13 ));
}
}
but that’s not how opengl likes it.
just ran into https://github.com/g-truc/glm/blob/master/glm/detail/type_half.inl which looks pretty similar.