I'm working on a program that draws a 100x100 grid and allows the user to click on a cell and change the color.
Clicking also works currently, however only when looking at the grid face on (i.e. camPos.z
equal to camLook.z
) and when the grid is positioned in the center of the screen.
What I've been stuck on the last few days is selecting the correct cell when looking at the grid from a different camera position or different area on the screen.
My only guess would be that somehow the depth buffer does not reflect the current position of the camera or that there is some inconsistency between the buffer depth range and the near and far values of the camera. Or that the way I'm applying the projection/view matrix is ok for displaying the image, but something is going wrong when going back through the pipeline. But I can't quite figure it out.
(code updated/refactored since originally posting)
Vertex Shader:
#version 330
layout(location = 0) in vec4 position;
smooth out vec4 theColor;
uniform vec4 color;
uniform mat4 pv;
void main() {
gl_Position = pv * position;
theColor = color;
}
Camera class (result of projectionViewMatrix()
is the pv
uniform above):
Camera::Camera()
{
camPos = glm::vec3(1.0f, 5.0f, 2.0f);
camLook = glm::vec3(1.0f, 0.0f, 0.0f);
fovy = 90.0f;
aspect = 1.0f;
near = 0.1f;
far = 1000.0f;
}
glm::mat4 Camera::projectionMatrix()
{
return glm::perspective(fovy, aspect, near, far);
}
glm::mat4 Camera::viewMatrix()
{
return glm::lookAt(
camPos,
camLook,
glm::vec3(0.0f, 1.0f, 0.0f)
);
}
glm::mat4 Camera::projectionViewMatrix()
{
return projectionMatrix() * viewMatrix();
}
// view controls
void Camera::moveForward()
{
camPos.z -= 1.0f;
camLook.z -= 1.0f;
}
void Camera::moveBack()
{
camPos.z += 1.0f;
camLook.z += 1.0f;
}
void Camera::moveLeft()
{
camPos.x -= 1.0f;
camLook.x -= 1.0f;
}
void Camera::moveRight()
{
camPos.x += 1.0f;
camLook.x += 1.0f;
}
void Camera::zoomIn()
{
camPos.y -= 1.0f;
}
void Camera::zoomOut()
{
camPos.y += 1.0f;
}
void Camera::lookDown()
{
camLook.z += 0.1f;
}
void Camera::lookAtAngle()
{
if (camLook.z != 0.0f)
camLook.z -= 0.1f;
}
Specific function in the camera class where I am trying to get world coordinates (x
and y
are screen coordinates):
glm::vec3 Camera::experiment(int x, int y)
{
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
GLfloat winZ;
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
printf("DEPTH: %f\n", winZ);
glm::vec3 pos = glm::unProject(
glm::vec3(x, viewport[3] - y, winZ),
viewMatrix(),
projectionMatrix(),
glm::vec4(0.0f, 0.0f, viewport[2], viewport[3])
);
printf("POS: (%f, %f, %f)\n", pos.x, pos.y, pos.z);
return pos;
}
Initialization and display:
void init(void)
{
glewExperimental = GL_TRUE;
glewInit();
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LESS);
glDepthRange(0.0f, 1.0f);
InitializeProgram();
InitializeVAO();
InitializeGrid();
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CW);
}
void display(void)
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(theProgram);
glBindVertexArray(vao);
glUniformMatrix4fv(projectionViewMatrixUnif, 1, GL_FALSE, glm::value_ptr(camera.projectionViewMatrix()));
DrawGrid();
glBindVertexArray(0);
glUseProgram(0);
glutSwapBuffers();
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH);
glutInitContextVersion(3, 2);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutInitWindowSize(500, 500);
glutInitWindowPosition(300, 200);
glutCreateWindow("testing");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse);
glutMainLoop();
return 0;
}