Я работаю над 3D-игрой для Android, и я новичок в ней. Я использую GLM, Android NDK, Opengl ES 2.0.
Когда я касаюсь экрана, я хотел бы получить эту трехмерную точку в мировом пространстве.
Части моего кода:
//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). Я использовал это уравнение линии:
х = х1 + (х2-х1) * т
у = у1 + (у2-у1) * т
z = z1 + (z2-z1) * t
где P (x, y, z) — точки на луче, nn = (x1, y1, z1) и ff = (x2, y2, z2) — две точки, которые определяют луч. Меня интересовала точка, где 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;
Вы решили за самый дальний указать, что проекты (x, height - y)
, Это не особенно полезно в большинстве случаев.
Вы должны решить для ближайший указать также (Z =0.0), тогда вы можете разыграть луч, который проходит через обе точки. Полученный луч будет представлять бесконечное число точек, которые проецируются на (x,y,*)
,