Introduction
Here I’m going to discuss about floating point textures and relative errors you can get using the different internal formats, furthermore I’m going to explain why I don’t really need full floating point precision for my project.
Texture internal formats
When you use a “standard” internal format for a texture, like GL_RGB for example, each component of the texel (usually) has 8 bits and the stored values are floating point values clamped to the range [0.0, 1.0].
So what to do if you need more accuracy and a not-clamped value? You have to use the internal formats defined by the GL_ARB_texture_float extension.
The texture float extensions offers two kind of floating point textures, the first one uses 16 bits for each component and the second one 32. An example of the first kind of format is GL_RGB16F_ARB, this internal format uses 3 components for each textel and 16 bits for each component (so 6 bytes for each texel). An example of the second kind of format is GL_RGB32F_ARB, this internal format uses 3 components for each texel and 32 bits for each component (so 12 bytes for each texel).
Accuracy errors
Usually a floating poit value uses 32 bits, so using less bits means less accuracy so some rounding errors, I’ve run some test so to understand how much this error could be.
I’ve used the following code to generate the texture data
float inc = 0.01;
float val = 0.0;
for(int i = 0; i < n; i++)
{
val += inc;
if(val > 1.0)
val /= ((rand() % 9) + 1);
data[i] = val;
}
This code fills the array data with growing values from the range [0.0, 1.0], the inc variable determines the increment of the values at every iteration, I’ve chosen the value 0.01 because is the lowest value that it’s used in the developed generation algorithms.
Then I’ve created the textures using the array data as image data and after that I’ve retrieved the stored data using the function glGetTexImage, finally, I’ve computed the percentage error using the formula:
rel_err = (100.0 * abs(tex[i] - data[i]) / data[i]);
These are the results of my tests:
GL_RGBA - 8bits components
elements = 40000 - avg err = 0.209%
elements = 160000 - avg err = 0.207%
elements = 360000 - avg err = 0.206%
elements = 640000 - avg err = 0.206%
GL_RGBA16F_ARB - 16bits components
elements = 40000 - avg err = 0.016%
elements = 160000 - avg err = 0.016%
elements = 360000 - avg err = 0.016%
elements = 640000 - avg err = 0.016%
of course the 32-bits format gives a 0% error.
Floating point textures in my project
Do I really need floating point textures? Yes and no.
I don’t need them for the accuracy, because the 8-bits format gives me good results and very short execution times, if I would to analyze the problem better, I can say that the minimum percentage error required to have a wrong pixel is abs(254 - 255) / 255 * 100 = 0.392% and this error is bigger than the average error I got from 8-bits textures, so, on the average, I can’t have wrong pixels in my height-map.
Furthermore my work is based on pseudo-random generations, noise, erosion and etc. so a value that’s slightly different from what it should be can be considered a feature, not a bug
But… I need floating point textures because for some algorithms I need not-clamped values as I’m going to show in my next posts, so all I need is the 16-bits texture because it gives me not-clamped values and an insignificant rounding error.
So the better solution for my project is to use both 8 and 16 bits textures and leave the user the possibility to choose what accuracy he needs for his generations.