glm::unProject 不起作用,屏幕上的光线位置不正确
glm::unProject doesn't work and incorrect ray position on screen
我尝试在 GLM 函数上实现光线拾取方法 glm::unProject。我在屏幕上错误的光线位置和错误的视角的问题。下面是一些简化的代码...
我的 LookAt 函数:
glm::mat4 ViewMatrix()
{
Front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
Front.y = -sin(glm::radians(Pitch));
Front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
Right = glm::normalize(glm::cross(Front, WorldUp));
Up = glm::normalize(glm::cross(Right, Front));
glm::vec3 PositionPan = RightPan + UpPan;
Position += PositionPan;
return glm::lookAt((Position + radius * (Front)), Position , Up);
}
您会注意到我的函数包含错误的参数,但我想制作免费相机(类似于 3ds max 等),目标为 0,0,0,可能进行平移(位置为 PositionPan)和缩放(半径)。我花了很多时间来正确地工作,而且我不知道有什么其他方法可以使它成为另一种方式。我怀疑这些功能是错误使用 GLM 的 Ray 功能的原因。如果您发现有问题请告诉我。
我的转换函数:
glm::mat4 view = ViewMatrix();
glm::mat4 projection = glm::perspective(1.0f,
(float)screenWidth / (float)screenHeight, 0.1f, 100.0f);
我的光线函数:
void Ray(posx, posy, glm::mat4 view, glm::mat4 projection )
{
x = (posx / screenWidth - 0.5f) * 2.0f;
y = (posy / screenHeight - 0.5f) * -2.0f;
worldSpaceNear = glm::unProject(glm::vec3(x, y, 0.0),
view, projection,
glm::vec4(0.0, 0.0, screenWidth, screenHeight));
worldSpaceFar = glm::unProject(glm::vec3(x, y, 1.0),
view, projection,
glm::vec4(0.0, 0.0, screenWidth, screenHeight));
}
接下来,我在 VAO 中传递 worldSpaceNear/Far 参数,并在几何着色器中生成一个从近到远平面开始的长平行六面体。从屏幕 space 到剪辑 space 的转换是正确的,但在调试时射线从左下角开始并立即消失。鼠标在屏幕上的位置对光线影响不大。
但是!
如果我将 Ray 函数更改为经典方法:
void mRay(glm::mat4 view, glm::mat4 projection
{
x = (posx / screenWidth - 0.5f) * 2.0f;
y = (posy / screenHeight - 0.5f) * -2.0f;
glm::vec4 localNear{ x, y, 0.0, 1.0 };
glm::vec4 localFar{ x, y, 1.0, 1.0 };
auto wsn = glm::inverse(projection * view) * localNear;
worldSpaceNear = glm::vec3(wsn.x, wsn.y, wsn.z);
auto wsf = glm::inverse(projection * view) * localFar;
worldSpaceFar = glm::vec3(wsf.x, wsf.y, wsf.z);
}
几乎一切正常。跟随鼠标的射线,但它的视角不正确。光线必须根据透视分散,但在我的例子中,它向往 Far 平面的中心。我该如何修复它,或者我如何在 GLM 上解决它?
德哈斯更新
在 mRay() 之后,我发送 worldSpaceNear/Far 到渲染循环。
我知道通常是有方向的,但我这样做了:
renderLine(glm::vec3 worldSpaceNear, glm::vec3 worldSpaceFar,
glm::mat4 view, glm::mat4 projection, glm::vec3 colorOverlay,
Shader shader)
{
...
//Create VAO, VBO
...
GLfloat vertices[] ={
worldSpaceNear.x - 0.01, worldSpaceNear.y + 0.01, worldSpaceNear.z,
worldSpaceFar.x - 0.01, worldSpaceFar.y + 0.01, worldSpaceFar.z,
worldSpaceNear.x - 0.01, worldSpaceNear.y - 0.01, worldSpaceNear.z...
// Long box from near to far
...
glDrawArrays(GL_LINE_LOOP, 0, 8);
}
在顶点着色器中:
gl_Position = projection * view * model * vec4(position, 1.0f);
现在我想可能是我忘记从线的视图矩阵中删除旋转组件,反之亦然以从相机添加旋转。
glm::unProject
将点从 window sapce 取消投影到眼睛 space(或您放入其中的任何矩阵)。但是,您未投影的点是
x = (posx / screenWidth - 0.5f) * 2.0f;
y = (posy / screenHeight - 0.5f) * -2.0f;
这不是 window space。您实际上在这里将其转换为规范化的设备坐标。 unproject 函数将在内部完成该转换(这就是您需要传递四个视口参数的原因)。这也解释了为什么光线移动不多,因为当这些值被解释为 window space.
时,在整个屏幕上移动鼠标只会改变它两个像素。
您唯一需要自己做的就是在 y 方向进行镜像,因为 GL 的 window space 原点在左下角:
x = posx;
y = screenHeight - 1.0f - posy;
我尝试在 GLM 函数上实现光线拾取方法 glm::unProject。我在屏幕上错误的光线位置和错误的视角的问题。下面是一些简化的代码...
我的 LookAt 函数:
glm::mat4 ViewMatrix()
{
Front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
Front.y = -sin(glm::radians(Pitch));
Front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
Right = glm::normalize(glm::cross(Front, WorldUp));
Up = glm::normalize(glm::cross(Right, Front));
glm::vec3 PositionPan = RightPan + UpPan;
Position += PositionPan;
return glm::lookAt((Position + radius * (Front)), Position , Up);
}
您会注意到我的函数包含错误的参数,但我想制作免费相机(类似于 3ds max 等),目标为 0,0,0,可能进行平移(位置为 PositionPan)和缩放(半径)。我花了很多时间来正确地工作,而且我不知道有什么其他方法可以使它成为另一种方式。我怀疑这些功能是错误使用 GLM 的 Ray 功能的原因。如果您发现有问题请告诉我。
我的转换函数:
glm::mat4 view = ViewMatrix();
glm::mat4 projection = glm::perspective(1.0f,
(float)screenWidth / (float)screenHeight, 0.1f, 100.0f);
我的光线函数:
void Ray(posx, posy, glm::mat4 view, glm::mat4 projection )
{
x = (posx / screenWidth - 0.5f) * 2.0f;
y = (posy / screenHeight - 0.5f) * -2.0f;
worldSpaceNear = glm::unProject(glm::vec3(x, y, 0.0),
view, projection,
glm::vec4(0.0, 0.0, screenWidth, screenHeight));
worldSpaceFar = glm::unProject(glm::vec3(x, y, 1.0),
view, projection,
glm::vec4(0.0, 0.0, screenWidth, screenHeight));
}
接下来,我在 VAO 中传递 worldSpaceNear/Far 参数,并在几何着色器中生成一个从近到远平面开始的长平行六面体。从屏幕 space 到剪辑 space 的转换是正确的,但在调试时射线从左下角开始并立即消失。鼠标在屏幕上的位置对光线影响不大。 但是! 如果我将 Ray 函数更改为经典方法:
void mRay(glm::mat4 view, glm::mat4 projection
{
x = (posx / screenWidth - 0.5f) * 2.0f;
y = (posy / screenHeight - 0.5f) * -2.0f;
glm::vec4 localNear{ x, y, 0.0, 1.0 };
glm::vec4 localFar{ x, y, 1.0, 1.0 };
auto wsn = glm::inverse(projection * view) * localNear;
worldSpaceNear = glm::vec3(wsn.x, wsn.y, wsn.z);
auto wsf = glm::inverse(projection * view) * localFar;
worldSpaceFar = glm::vec3(wsf.x, wsf.y, wsf.z);
}
几乎一切正常。跟随鼠标的射线,但它的视角不正确。光线必须根据透视分散,但在我的例子中,它向往 Far 平面的中心。我该如何修复它,或者我如何在 GLM 上解决它?
德哈斯更新
在 mRay() 之后,我发送 worldSpaceNear/Far 到渲染循环。 我知道通常是有方向的,但我这样做了:
renderLine(glm::vec3 worldSpaceNear, glm::vec3 worldSpaceFar,
glm::mat4 view, glm::mat4 projection, glm::vec3 colorOverlay,
Shader shader)
{
...
//Create VAO, VBO
...
GLfloat vertices[] ={
worldSpaceNear.x - 0.01, worldSpaceNear.y + 0.01, worldSpaceNear.z,
worldSpaceFar.x - 0.01, worldSpaceFar.y + 0.01, worldSpaceFar.z,
worldSpaceNear.x - 0.01, worldSpaceNear.y - 0.01, worldSpaceNear.z...
// Long box from near to far
...
glDrawArrays(GL_LINE_LOOP, 0, 8);
}
在顶点着色器中:
gl_Position = projection * view * model * vec4(position, 1.0f);
现在我想可能是我忘记从线的视图矩阵中删除旋转组件,反之亦然以从相机添加旋转。
glm::unProject
将点从 window sapce 取消投影到眼睛 space(或您放入其中的任何矩阵)。但是,您未投影的点是
x = (posx / screenWidth - 0.5f) * 2.0f;
y = (posy / screenHeight - 0.5f) * -2.0f;
这不是 window space。您实际上在这里将其转换为规范化的设备坐标。 unproject 函数将在内部完成该转换(这就是您需要传递四个视口参数的原因)。这也解释了为什么光线移动不多,因为当这些值被解释为 window space.
时,在整个屏幕上移动鼠标只会改变它两个像素。您唯一需要自己做的就是在 y 方向进行镜像,因为 GL 的 window space 原点在左下角:
x = posx;
y = screenHeight - 1.0f - posy;