【发布时间】:2014-05-06 04:55:28
【问题描述】:
我正在开发一个绘制 100x100 网格并允许用户单击单元格并更改颜色的程序。
目前也可以单击,但仅在查看网格面(即camPos.z 等于camLook.z)并且网格位于屏幕中心时。
过去几天我遇到的问题是从不同的相机位置或屏幕上的不同区域查看网格时选择正确的单元格。
我唯一的猜测是深度缓冲区不反映相机的当前位置,或者缓冲区深度范围与相机的近距和远距值之间存在一些不一致。或者我应用投影/视图矩阵的方式可以显示图像,但是当通过管道返回时出现问题。但我不太清楚。
(自最初发布以来已更新/重构代码)
顶点着色器:
#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;
}
相机类(projectionViewMatrix() 的结果是上面的pv 制服):
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;
}
我试图获取世界坐标的相机类中的特定函数(x 和 y 是屏幕坐标):
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;
}
初始化和显示:
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;
}
【问题讨论】:
-
您现在在顶点着色器中手动应用的
offset确实应该是您的模型视图矩阵的一部分。现在,您有一个 View 矩阵,它执行 World->View 并以glm::unProject (...)不知道的方式手动应用 Object->World 平移,因为它不在您的转换矩阵中。您目前拥有的方式对于任何非零偏移量都不应正常工作。 -
@AndonM.Coleman 好的,这真的很有帮助。谢谢!我想我现在对这个问题有了一个想法。基本上,我重复使用相同的 VBO 来绘制每个单元格(每个单元格具有相同的坐标),并在每次调用显示函数时为每个单元格设置统一的偏移量(这是一个非常老套的解决方案)。我接下来要尝试的是为每个单元创建一个单独的 VBO(将其保存在具有正确顶点位置的 Cell C++ 对象中)并完全删除该偏移均匀。希望我明天有时间来实施。