我上周左右一直致力于将屏幕转换为世界坐标(之前但无关的问题:Depth Component of Converting from Window -> World Coordinates)。
自从那篇帖子以来,我在简化代码方面取得了很多进展,但现在我正在采用光线投射方法进行对象选择,更具体地说,首先通过绘制一条直线来显示光线(它已被绘制但是没有正确的坐标。)
(这4行显示点击方块的每个角落+相机已旋转以更好地查看线条时会发生什么。)
代码:
顶点着色器:
#version 330
layout(location = 0) in vec4 position;
layout(location = 1) in vec4 rcolor;
smooth out vec4 theColor;
uniform vec4 color;
uniform mat4 pv;
void main() {
gl_Position = pv * position;
theColor = color;
}
^其中pv是投影矩阵和&的组合。视图矩阵。 Camera类的相关代码:
Camera::Camera()
{
camPos = glm::vec3(0.0f, 5.0f, 1.0f);
camLook = glm::vec3(0.0f, 0.0f, 0.0f);
fovy = 90.0f;
aspect = 1.0f;
near = 0.1f;
far = 100.0f;
}
glm::mat4 Camera::projectionMatrix()
{
return glm::perspective(fovy, aspect, near, far);
}
glm::mat4 Camera::viewMatrix()
{
return glm::lookAt(
camPos,
camLook,
glm::vec3(0, 1, 0)
);
}
glm::mat4 Camera::projectionViewMatrix()
{
return projectionMatrix() * viewMatrix();
}
点击后我初始化一个Ray对象:
void initializeRay(int x, int y)
{
Ray rayObj(
camera.getWorldNear(x, y),
camera.getWorldFar(x, y)
);
rays.push_back(rayObj);
}
(来自Camera类的相关功能) - 可能是问题所在
glm::vec3 Camera::getWorldNear(int x, int y)
{
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glm::vec3 worldNear = glm::unProject(
glm::vec3(x, viewport[3] - y, near),
viewMatrix(),
projectionMatrix(),
glm::vec4(0.0f, 0.0f, viewport[2], viewport[3])
);
printf("near: (%f, %f, %f)\n", worldNear.x, worldNear.y, worldNear.z);
return worldNear;
}
glm::vec3 Camera::getWorldFar(int x, int y)
{
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glm::vec3 worldFar = glm::unProject(
glm::vec3(x, viewport[3] - y, far),
viewMatrix(),
projectionMatrix(),
glm::vec4(0.0f, 0.0f, viewport[2], viewport[3])
);
printf("far: (%f, %f, %f)\n", worldFar.x, worldFar.y, worldFar.z);
return worldFar;
}
并构建对象....
Ray::Ray(glm::vec3 worldNear, glm::vec3 worldFar)
{
float temp[] = {
worldNear.x, worldNear.y, worldNear.z,
worldFar.x, worldFar.y, worldFar.z,
};
vertexData.resize(6);
for (x = 0; x < 6; x++)
vertexData[x] = temp[x];
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(float), &vertexData[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
每次调用显示功能时,都会绘制所有光线:
void drawRays()
{
for (int x = 0; x < rays.size(); x++) {
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, rays[x].vbo);
glVertexAttribPointer(
0,
2,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
glUniform4f(colorUniform, 1.0f, 0.0f, 0.0f, 0.0f);
glDrawArrays(GL_LINES, 0, 2);
glDisableVertexAttribArray(0);
}
}
我最初的想法是我以错误的方式使用glm::unProject
函数,但我也尝试将光线的起点和终点位置更改为camPos
&amp; camLook
(相机位置和相机看位置)没有任何运气(再次,光线似乎都聚集在广场的顶部)。
修改
我还创建了一个获取光线方向的函数,但目前我的代码中仍未使用该函数:
glm::vec3 Camera::getRay(int x, int y)
{
glm::vec3 worldNear = glm::unProject(
glm::vec3(x, screenHeight - y, near),
viewMatrix(),
projectionMatrix(),
glm::vec4(0.0f, 0.0f, screenWidth, screenHeight)
);
glm::vec3 worldFar = glm::unProject(
glm::vec3(x, screenHeight - y, far),
viewMatrix(),
projectionMatrix(),
glm::vec4(0.0f, 0.0f, screenWidth, screenHeight)
);
glm::vec3 direction = worldFar - worldNear;
direction - glm::normalize(direction);
printf("(%f, %f, %f)\n", direction.x, direction.y, direction.z);
return direction;
}
答案 0 :(得分:1)
要绝对清楚,这些光线在哪里可视化应该来源?我想你正在点击 window-space 中的某个任意位置,并希望光线从那里开始?
glm::UnProject (...)
需要窗口空间中的坐标,但实际上您提供 和 远 目前在 view-space 中定义。很容易忘记转换到窗口空间由视口定义(NDC x,y - &gt; Win x ,y ) 和 也是深度范围(NDC z - &gt; Win z 子>)。
near
= 0.1 且far
= 100.0 (查看空间)
near
= -1.0 且far
= 1.0 (NDC空间)
near
= 0.0 且far
= 1.0 (窗口空间)
* GL使用的 默认 深度范围为[ 0.0 , 1.0 ]
这意味着在投影和视口转换后,近平面 0.0 ,远平面 1.0 。