'OpenGL fixed pipeline rendered colour GL_FLOAT not precise enough
I'm using the OpenGL fixed pipeline to render 3D models where vertices are coded with GL_FLOAT RGB values. An example of vertex data in Wavefront OBJ format is shown below:
v -705.39 31.35 82.34 0.9780448 0.9807401 0.1518212
v -705.19 30.53 81.32 0.9780985 0.9799018 0.1514152
v -706.78 32.83 87.36 0.9776751 0.9822390 0.1538261
v -706.73 32.60 86.36 0.9776898 0.9820088 0.1534263
v -706.65 32.29 85.36 0.9777099 0.9816957 0.1530257
v -706.55 31.87 84.35 0.9777372 0.9812685 0.1526239
where each line starting with 'v' is a vertex, followed by its 3D positional coordinates, and then its RGB value in the range [0,1].
Below is a snippet of the rendering code:
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(ww, wh); // Viewport is ww by wh in dimensions
glutInitWindowPosition(0, 0);
glutCreateWindow("Rendered");
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
glClearColor(0.0, 0.0, 0.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluPerspective(vfov, (GLdouble)ww / (GLdouble)wh, 500, 5000);
gluLookAt(cam_x, cam_y, cam_z, centre_x, centre_y, centre_z, up_x_norm, up_y_norm, up_z_norm);
display_object(); // Generates GL_TRIANGLES
// Read out colour pixels
cv::Mat output_img(wh, ww, CV_32FC3);
glReadPixels(0, 0, ww, wh, GL_RGB, GL_FLOAT, (GLvoid *)output_img.data);
Upon inspecting some non-zero entries of output_img, they appear as follows:
0.003922 0.556863 0.525490
0.003922 0.552941 0.525490
0.003922 0.552941 0.525490
0.003922 0.552941 0.521569
0.003922 0.552941 0.521569
0.003922 0.552941 0.521569
0.003922 0.552941 0.521569
0.003922 0.552941 0.521569
0.003922 0.552941 0.521569
0.003922 0.552941 0.521569
0.003922 0.552941 0.521569
0.003922 0.552941 0.521569
0.003922 0.552941 0.521569
0.003922 0.549020 0.517647
0.003922 0.549020 0.517647
0.003922 0.549020 0.517647
0.003922 0.549020 0.517647
0.003922 0.549020 0.517647
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.552941 0.521569
0.007843 0.552941 0.521569
0.007843 0.552941 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
0.007843 0.549020 0.521569
It seems that there are multiple entries of the same colour due to insufficient intermediate precision in the fixed pipeline.
What are the necessary settings to compute the rendered colour values to a higher precision?
Solution 1:[1]
The colors of the fragments are stored in the framebuffer. The format of the Default Framebuffer is (probably) 1 byte for each color channel. So it doesn't matter which type you use when you read the color from the buffer. The precision is lost when the color is written into the buffer.
If you want to store the colors with a higher precision, then you've to render to a Framebuffer, that uses a Renderbuffer or Texture with a format that can store the values with an higher precision.
See Image Format.
If you want to render to a framebuffer, then I recommend to read a tutorial like Framebuffers or Render To Texture respectively Khronos wiki - Framebuffer Object Extension Examples.
Solution 2:[2]
The obvious suggestion here is to use an FBO with a 32bit floating point RGB colour target (rather than relying on the 8bits per channel default used for the default frame buffer).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | robthebloke |
