我有一个我认为是最基本的需求:从“鼠标在屏幕上的2D位置”,我需要得到“在3D世界中最近的3D点”。看起来像光线跟踪常见的问题(即使它不是我的)。
我在谷歌上搜索/阅读了很多:看起来这个主题很混乱,很多事情很快就变得很复杂。我最初的问题/需求涉及到很多我不知道的三维点(网格或点云从互联网上),所以,这是不可能的理解什么结果,你应该期待!因此,我决定创建简单的形状(三角形、四边形、立方体)与我 * 知道 * 的点(每个点的每个坐标在局部帧中为0.f或0.5f),并且,尝试查看当我在屏幕上移动鼠标光标时,我是否可以从鼠标光标“恢复”3D点位置。
注:所有形状的所有点的坐标均为已知值,如0.f或0.5f。例如,the triangle:
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
我的工作
我有一个3D OpenGL渲染器,其中我添加了一个GUI,以便在渲染的场景上进行控制
- 变形:
tx
、ty
、tz
、rx
、ry
、rz
是用于更改model
矩阵的控件。在代码中
// create transformations: model represents local to world transformation
model = glm::mat4(1.0f); // initialize matrix to identity matrix first
model = glm::translate(model, glm::vec3(tx, ty, tz));
model = glm::rotate(model, glm::radians(rx), glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, glm::radians(ry), glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::rotate(model, glm::radians(rz), glm::vec3(0.0f, 0.0f, 1.0f));
ourShader.setMat4("model", model);
model
只改变形状在世界中的位置,与摄像机的位置无关(这是我从tutorials中理解的)。
- Camera:从here开始,我最终创建了一个camera类,它包含
view
和proj
矩阵。
// get view and projection from camera
view = cam.getViewMatrix();
ourShader.setMat4("view", view);
proj = cam.getProjMatrix((float)SCR_WIDTH, (float)SCR_HEIGHT, near, 100.f);
ourShader.setMat4("proj", proj);
摄像头是一个类似苍蝇的摄像头,可以在移动鼠标或使用键盘箭头时移动,它 * 不 * 作用于model
,而 * 只 * 作用于view
和proj
(这是我从tutorials中理解的)。
然后,着色器以如下方式使用model
、view
和proj
:
uniform mat4 model;
uniform mat4 view;
uniform mat4 proj;
void main()
{
// note that we read the multiplication from right to left
gl_Position = proj * view * model * vec4(aPos.x, aPos.y, aPos.z, 1.0);
- 屏幕到世界:由于使用
glm::unProject
并不总是返回我所期望的结果,我添加了一个不使用它的控件(back-projecting by-hand)。
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouseCursorCallback(GLFWwindow* window, double xposIn, double yposIn)
{
// screen to world transformation
xposScreen = xposIn;
yposScreen = yposIn;
int windowWidth = 0, windowHeight = 0; // size in screen coordinates.
glfwGetWindowSize(window, &windowWidth, &windowHeight);
int frameWidth = 0, frameHeight = 0; // size in pixel.
glfwGetFramebufferSize(window, &frameWidth, &frameHeight);
glm::vec2 frameWinRatio = glm::vec2(frameWidth, frameHeight) /
glm::vec2(windowWidth, windowHeight);
glm::vec2 screen2DPos = glm::vec2(xposScreen, yposScreen);
glm::vec2 frame2DPos = screen2DPos * frameWinRatio; // window / frame sizes may be different.
frame2DPos = frame2DPos + glm::vec2(0.5f, 0.5f); // shift to GL's center convention.
glm::vec3 frame3DPos = glm::vec3(0.0f, 0.0f, 0.0f);
frame3DPos.x = frame2DPos.x;
frame3DPos.y = frameHeight - 1.0f - frame2DPos.y; // GL's window origin is at the bottom left
frame3DPos.z = 0.f;
glReadPixels((GLint) frame3DPos.x, (GLint) frame3DPos.y, // CAUTION: cast to GLint.
1, 1, GL_DEPTH_COMPONENT,
GL_FLOAT, &zbufScreen); // CAUTION: GL_DOUBLE is NOT supported.
frame3DPos.z = zbufScreen; // z-buffer.
然后我可以根据GUI中的控件调用或不调用glm::unProject
(back-projecting by-hand
glm::vec3 world3DPos = glm::vec3(0.0f, 0.0f, 0.0f);
if (screen2WorldUsingGLM) {
glm::vec4 viewport(0.0f, 0.0f, (float) frameWidth, (float) frameHeight);
world3DPos = glm::unProject(frame3DPos, view * model, proj, viewport);
} else {
glm::mat4 trans = proj * view * model;
glm::vec4 frame4DPos(frame3DPos, 1.f);
frame4DPos = glm::inverse(trans) * frame4DPos;
world3DPos.x = frame4DPos.x / frame4DPos.w;
world3DPos.y = frame4DPos.y / frame4DPos.w;
world3DPos.z = frame4DPos.z / frame4DPos.w;
}
问题:glm::unProject
文档中说Map the specified window coordinates (win.x, win.y, win.z) into object coordinates
,但是,我不确定什么是对象坐标。对象坐标是指here描述的局部、世界、视图还是剪辑空间?
- 无论形状是2D(三角形、四边形)还是3D(立方体),都 * 始终 * 允许Z缓冲。
glEnable(GL_DEPTH_TEST); // Enable z-buffer.
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // also clear the z-buffer
在图片中我得到
摄像头位于(0.,0.,0.)并“向前看”(front = -z
,因为z轴从屏幕到我是正的)。(使用tx
、ty
、tz
、rx
、ry
、rz
)“在摄影机前面”与tz = -5
(5个单位跟随摄影机的front
矢量)
我得到的
三角形处于初始设置
我在世界框架中有正确的xpos
和ypos
,但zpos = 0.
不正确(允许z缓冲)。我预期的是zpos = -5
(作为tz = -5
)。
问题:为什么zpos
不正确?
如果不使用glm::unProject
,则会得到外太空结果
问题:为什么手工“反投影”与glm::unProject
相比没有返回一致的结果?这合乎逻辑吗?它们是不同的操作吗?(我认为它们应该是等效的,但显然不是)
三角形随平移移动
在平移了大约tx = 0.5
之后,我仍然得到了相同的坐标(局部框架),我希望之前的坐标沿着x轴平移。不使用glm::unProject
也会在这里返回外空间结果...
问题:为什么忽略转换(由model
应用,而不是view
或proj
)?
立方体处于初始设置
x1c4d 1x指令集
我得到了正确的xpos
,ypos
和zpos
?!...那么为什么这与“2D”三角形的工作方式不一样(对我来说是“3D”三角形,所以,它们应该表现相同)?
立方体随平移移动
沿着ty
平移这次似乎没有效果(仍然获得相同的坐标-局部帧)。
问题:就像三角形一样,为什么忽略平移?
∮我想得到的
主要问题是为什么忽略model
变换?如果这是意料之中的,我想知道为什么。如果有一种方法可以从鼠标光标的位置恢复形状在世界中的“真实”位置(包括model
变换),我想知道如何恢复。
1条答案
按热度按时间6qftjkof1#
问题:glm::unProject doc说将指定的窗口坐标(win.x,win.y,win.z)Map到对象坐标,但是,我不确定什么是对象坐标。对象坐标是指这里描述的局部、世界、视图还是剪辑空间?
由于我是OpenGL新手,我没有从
glm::unProject
文档中得到对象坐标是引用局部空间的另一种方式。将view*model
传递给glm::unProject
并再次应用model
,或者将view
传递给glm::unProject
,如下所述:Screen Coordinates to World Coordinates。这修复了我观察到的所有怪异行为。