I have colored pixel 1,1 with 0.0f 0.0f 1.0f 1.0f (blue) and i got the same response as white. Can someone tell me what I did wrong?
Code:
GL11.glReadBuffer(GL11.GL_FRONT);
ByteBuffer rgb = BufferUtils.createByteBuffer(3);
glReadPixels(X, Y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, rgb);
System.out.println((rgb.get(0) & 0xFF) + ", " + (rgb.get(1) & 0xFF) + ", " + (rgb.get(2) & 0xFF));
Can you show some more of your code, where you render things?
Also keep in mind that when using double-buffering then the GL_BACK buffer is the one being rendered to, before you call glfwSwapBuffers().
Also, are you maybe rendering to a Framebuffer Object?
Code: (whole loop beware)
private void loop() {
GL.createCapabilities();
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 600, 600, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
ArrayList<Shape> shapes = new ArrayList<>();
Shape shape = new Shape();
Color color = new Color();
color.setColor(0.0f, 0.0f, 0.0f, 1.0f);
shape.setShape(7, 20.0f, 15.0f, 100.0f, 100.0f, color);
shapes.add(shape);
Points temp;
square.setUp();
while (glfwWindowShouldClose(window) == GLFW_FALSE) {
sync(60);
frameTrack++;
glfwPollEvents();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClear(GL_COLOR_BUFFER_BIT);
switch (togglePage) {
case "login":
drawShape(shapes);
if (usernameOn) {
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
} else {
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
}
Username.draw();
if (connectError != null) {
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
temp = drawString(connectError, 260, 260);
temp.draw();
}
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
login.draw();
temp = drawString(username, 260, 300);
temp.draw();
if (passwordOn) {
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
} else {
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
}
Password.draw();
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
String passwordTemp = "";
for (int i = 0; i < password.length(); i++) {
passwordTemp = passwordTemp + "*";
}
temp = drawString(passwordTemp, 260, 340);
temp.draw();
if ((mouseX >= 251 && mouseX <= 350) && mouseY >= 348 && mouseY <= 366) {
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
} else {
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
}
Login.draw();
glColor3f(0.0f, 0.0f, 1.0f);
GL11.glBegin(GL11.GL_POINTS);
GL11.glVertex2f(1, 1);
GL11.glEnd();
new boardCreate().read(1, 1);
break;
case "conectionInfo":
if ((mouseX >= 251 && mouseX <= 350) && mouseY >= 348 && mouseY <= 366) {
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
} else {
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
}
Login.draw();
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
conectionInfo.draw();
if (hostOn) {
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
} else {
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
}
Username.draw();
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
temp = drawString(host, 260, 300);
temp.draw();
if (portOn) {
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
} else {
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
}
Password.draw();
temp = drawString(Port + "", 260, 340);
temp.draw();
break;
default:
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
square.draw();
break;
}
glfwSwapBuffers(window);
new boardCreate().read(1, 1);
}
And when/where do you make the glReadPixels call there? I mean it's clearly your glClearColor which you read.
Also beware that glReadPixels takes "window coordinates". They have their Y axis point downwards.
So the y co-ordinate 0 is at the top of the window. <-- wrong. See further post.
new boardCreate().read(1, 1);
And I know about the 0,0 being in the top corner. The whole thing is a 600x600 window.
Okay, that looks about right then. The only thing I can think of now is that the pixel (1, 1) (the second pixel along +X and the second along +Y) does not contain that color, but the clearcolor. Are you absolutely sure that your rendered output at pixel (1, 1) is not the clear color (white)? Can you maybe post an image of the render result?
glColor3f(0.0f, 0.0f, 1.0f);
GL11.glBegin(GL11.GL_POINTS);
GL11.glVertex2f(1, 1);
GL11.glEnd();
In code and I will send a pic in ~8min.
Okay, I was wrong. Window coordinates in OpenGL have their origin at the bottom-left...
So you could either switch the top and bottom arguments of glOrtho or use glReadPixels(1, height-2, ...)
Also noted here: https://www.opengl.org/sdk/docs/man/html/glReadPixels.xhtml
Quotex, y
Specify the window coordinates of the first pixel that is read from the frame buffer. This location is the lower left corner of a rectangular block of pixels.
Here (I cropped it to make it easier to see)
Quote from: Kai on April 25, 2016, 19:41:29
Okay, I was wrong. Window coordinates in OpenGL have their origin at the bottom-left...
So you could either switch the top and bottom arguments of glOrtho or use glReadPixels(1, height-2, ...)
Also noted here: https://www.opengl.org/sdk/docs/man/html/glReadPixels.xhtml
Quotex, y
Specify the window coordinates of the first pixel that is read from the frame buffer. This location is the lower left corner of a rectangular block of pixels.
The project relies on 0,0 being top-Left though... And it works...
Quote from: Moocow9m on April 25, 2016, 19:45:24
The project relies on 0,0 being top-Left though...
Quote from: Kai on April 25, 2016, 19:41:29
or use glReadPixels(1, height-2, ...)
This is also possible, if supported by your driver: https://www.opengl.org/registry/specs/ARB/clip_control.txt
Quote from: Kai on April 25, 2016, 19:46:43
Quote from: Moocow9m on April 25, 2016, 19:45:24
The project relies on 0,0 being top-Left though...
Quote from: Kai on April 25, 2016, 19:41:29
or use glReadPixels(1, height-2, ...)
This is also possible, if supported by your driver: https://www.opengl.org/registry/specs/ARB/clip_control.txt
glReadPixels(X, Y - 2, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, rgb); gave 0,0,0...
Quote from: Moocow9m on April 25, 2016, 19:52:45
glReadPixels(X, Y - 2, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, rgb); gave 0,0,0...
Not Y - 2 .... height-2, where height is the height in pixels of your viewport.
Generally: your glReadPixels(X, Y, ...) becomes: glReadPixels(X, height-Y-1, ...)
Quote from: Kai on April 25, 2016, 19:53:54
Quote from: Moocow9m on April 25, 2016, 19:52:45
glReadPixels(X, Y - 2, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, rgb); gave 0,0,0...
Not Y - 2 .... height-2, where height is the height in pixels of your viewport.
Generally: your glReadPixels(X, Y, ...) becomes: glReadPixels(X, height-Y-1, ...)
height-Y-1 == 1-1-1.... They all equal 1 in this situation and -3 is not displayed....
Quote from: Moocow9m on April 25, 2016, 19:59:57
height-Y-1 == 1-1-1....
No. "height" is the height of your viewport/render area. Your window is NOT 1 pixel in height. According to your code it is 600 Pixels.
So please understand that glReadPixels(1, 1, ...) translates to glReadPixels(1, height-1-1, ...) = glReadPixels(1, height-2) = glReadPixels(1, 600-2,...) = glReadPixels(1, 598, ...)
Ok. Now returning 255,255,255 again though... glReadPixels(X, 600-Y-1, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, rgb);
I see. The general problem here is that rasterizing a point at (1, 1) does not lead to the pixel (1, height-2) being rendered to, due to OpenGL's point rasterization rules. Rendering (1, 1) will fill pixel (1, height-1).
And likewise (0, 0) does not fill pixel (0, height-1), but no pixel at all.
This is because (0, 0) does not denote the top-left pixel but rather the top-left corner of the viewport, which is the top-left corner of the top-left pixel. It is NOT the CENTER of the pixel.
If you want to make absolutely sure that the pixel is hit when rasterizing a point with GL_POINTS, then you must use glVertex2f(0.5f, 0.5f) or in your case glVertex2f(1.5f, 1.5f), that is, add a 0.5f offset to the position, which is just the half-size of a pixel. The former would hit pixel (0, height-1) and the latter would hit pixel (1, height-2)
(I just tested it with a demo program myself):
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.*;
import java.nio.ByteBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFWKeyCallback;
import org.lwjgl.opengl.GL;
public class ForumDemo {
public static void main(String[] args) {
int width = 600;
int height = 600;
glfwInit();
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
long window = glfwCreateWindow(width, height, "", NULL, NULL);
GLFWKeyCallback keyCallback;
glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
public void invoke(long window, int key, int scancode, int action, int mods) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
glfwSetWindowShouldClose(window, true);
}
});
glfwMakeContextCurrent(window);
GL.createCapabilities();
glClearColor(1, 1, 1, 1);
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, height, 0, -1, +1);
glColor3f(0.0f, 0.0f, 1.0f);
glBegin(GL_POINTS);
glVertex2f(1.5f, 1.5f); // <- make sure pixel (1, height-1-1) is rendered to
glEnd();
glfwSwapBuffers(window);
glReadBuffer(GL_FRONT);
ByteBuffer rgb = BufferUtils.createByteBuffer(3);
glReadPixels(1, height-1-1, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, rgb);
System.out.println((rgb.get(0) & 0xFF) + ", " + (rgb.get(1) & 0xFF) + ", " + (rgb.get(2) & 0xFF));
glfwPollEvents();
}
}
}
Just to make sure, add .5 to all points if I want to read them?
Quote from: Moocow9m on April 25, 2016, 20:26:07
Just to make sure, add .5 to all points if I want to read them?
Yes, but I would rather do the translation as part of the projection matrix. You can do the following right after glOrtho():
glTranslatef(0.5f, 0.5f, 0);
Since you are setting up a pixel-perfect projection anyway, this will not hurt.
Afterwards, when you glVertex2f(x, y) with integer coordinates then this will correctly hit the corresponding pixel.
So: no need to add a 0.5f offset to each vertex.
Quote from: Kai on April 25, 2016, 20:37:49
Quote from: Moocow9m on April 25, 2016, 20:26:07
Just to make sure, add .5 to all points if I want to read them?
Yes, but I would rather do the translation as part of the projection matrix. You can do the following right after glOrtho():
glTranslatef(0.5f, 0.5f, 0);
Since you are setting up a pixel-perfect projection anyway, this will not hurt.
Afterwards, when you glVertex2f(x, y) with integer coordinates then this will correctly hit the corresponding pixel.
So: no need to add a 0.5f offset to each vertex.
So not in the while loop?
Correct. :) Not in the while loop. Just once directly after glOrtho().
Thanks I will try when I get home in ~2 hours.