使用GLM + Answer将屏幕转换为3D世界坐标后效果不佳

时间:2014-05-07 18:03:38

标签: c++ opengl-es 3d renderer glm-math

我正在开发一款3D安卓游戏,我是新手。我正在使用GLM,Android NDK,Opengl ES 2.0。

当我触摸屏幕时,我想在世界空间中获得3D点。

我的部分代码:

//Camera data
float eye[3]  = {0.0f, 11.0f, -2.0f};
float look[3] = {0.0f, -1.0f, 3.0f};
const float up[3] = {0.0f, 1.0f, 0.0f};

glViewport(0, 0, width, height);
...
const float ratio = (float) width / height;
mViewMatrix = glm::lookAt(glm::make_vec3(eye), glm::make_vec3(look), glm::make_vec3(up));
mProjMatrix = glm::perspective(30.0f, -ratio, near, far); // near = 1.0f; far = 100.0f;
mMVPMatrix = mProjMatrix * mViewMatrix;
....

我试过这个:

glm::vec3 worldXYZ = glm::unProject(glm::vec3(x, height - y, 1.0f), mViewMatrix, mProjMatrix, glm::vec4(0, 0, width, height));

其中x和y是像素中的屏幕坐标,但我得到了奇怪的结果。当我触摸示例原始文件时,结果应该类似于(0,0,0),但我得到了这个:(0.5, -89.6, 16)

我在哪里弄错了?


更新我的回答:

Andon M. Coleman是对的,我根据他的回答改变了我的代码。我没有使用glm::unProject方法,因为我最终得到了不好的结果,所以我退后一步,我自己计算了一些东西。

float xx = (2.0f * x) / width - 1.0f; // between [-1;+1]
float yy = (2.0f * (height - y)) / height - 1.0f;  // between [-1;+1]
float zzN = 0.0f; // near
float zzF = 1.0f; // far

glm::mat4 invM = glm::inverse(mMVPMatrix);

glm::vec4 mmN = invM * glm::vec4(xx, yy, zzN, 1.0f);
glm::vec4 mmF = invM * glm::vec4(xx, yy, zzF, 1.0f);

规范化向量:

glm::vec3 nn = glm::vec3(mmN[0] / mmN[3], mmN[1] / mmN[3], mmN[2] / mmN[3]);
glm::vec3 ff = glm::vec3(mmF[0] / mmF[3], mmF[1] / mmF[3], mmF[2] / mmF[3]);

然后我需要光线(从nn到ff)。我使用了这个线方程:

x = x1 +(x2-x1)* t

y = y1 +(y2-y1)* t

z = z1 +(z2-z1)* t

其中P(x,y,z)是光线中的点,nn =(x1,y1,z1),ff =(x2,y2,z2)是定义光线的2个点。我对y = 0(光线和平面正在相遇)的点感兴趣,所以我最终计算出x和z世界坐标,如下所示:

float t = nn[1] / (nn[1] - ff[1]);
float wx = nn[0] + (ff[0] - nn[0]) * t;
float wz = nn[2] + (ff[2] - nn[2]) * t;

1 个答案:

答案 0 :(得分:2)

窗口空间(“屏幕坐标”)Z = 1.0 是您的远平面

您已解决投射到(x, height - y) 最远 点。这在大多数时候都不是特别有用。

无法从 2D 窗口空间坐标中获取世界空间中的 点;投影不起作用。

你也应该解决 最近的 点(Z = 0.0 ),然后你可以投射穿过这两点的光线。生成的光线将代表投射到(x,y,*)的无限数量的点。