Я пытаюсь реализовать систему подбора объектов, и пока она работает, если я не двигаю свою камеру.
Если я не перемещаю камеру, она правильно показывает положение мыши в мировых координатах. Я не могу захватить мышь на скриншоте, но она внутри белого «круга», а координаты находятся в верхнем левом углу изображения.
Но если я немного опущу камеру, она снова будет показывать (0, 0) в центре экрана.
То, что я хочу и ожидаю, это (0, -5) или что-то в этом роде.
Вот мой код:
double mouse_x, mouse_y;
glfwGetCursorPos(window, &mouse_x, &mouse_y);
vec3 mouse_pos = vec3(float(mouse_x), float(mouse_y), 0.0f);
world_mouse_pos = unProject(mouse_pos, view, projection, vec4(0, 0, window_width, window_height));
mouse_offset.x = last_mouse_pos.x - world_mouse_pos.x;
mouse_offset.y = last_mouse_pos.y - world_mouse_pos.y;
last_mouse_pos.x = world_mouse_pos.x;
last_mouse_pos.y = world_mouse_pos.y;
m_state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_MIDDLE);
if (m_state == GLFW_PRESS){
view = translate(view, vec3(-mouse_offset, 0.0f));
glUniformMatrix4fv(view_loc, 1, GL_FALSE, &view.data[0][0]);
}
Отпроектировать функцию:
inline vec3 unProject(const vec3 &pos, const mat4 &modelview, const mat4 &proj, const vec4 &viewport){
mat4 inv = inverse(proj * modelview);
vec4 temp = vec4(pos, 1.0f);
temp.x = ((temp.x - viewport.x) / viewport.z);
temp.y = ((temp.y - viewport.y) / viewport.w);
temp = temp * 2 - 1;
temp.y = - temp.y;
vec4 obj = inv * temp;
return vec3(obj.x, obj.y, obj.z);
}
Я использую ортографическую проекцию. По сути, unProject всегда возвращает одни и те же значения, несмотря на то, что камера находится в другом положении.
Что мне не хватает?
Если у других такая же проблема, я разобрался. Поэтому я забыл, что мои матрицы являются основными по строкам, поэтому моя функция unProject была неправильной, вот правильная функция:
inline vec3 unProject(const vec3 &pos, const mat4 &modelview, const mat4 &proj, const vec4 &viewport){
mat4 inv = inverse(modelview * proj);
vec4 temp = vec4(pos, 1.0f);
temp.x = ((temp.x - viewport.x) / viewport.z);
temp.y = ((temp.y - viewport.y) / viewport.w);
temp = temp * 2 - 1;
temp.y = -temp.y;
vec4 obj = transpose(inv) * temp;
obj /= obj.w;
return vec3(obj.x, obj.y, obj.z);
}
В основном я изменил порядок первого умножения и транспонировал обратную матрицу, чтобы иметь возможность умножить ее на vec4. Я также разделил окончательный vec4 obj на obj.w, просто чтобы быть более универсальной функцией и работать в перспективной проекции, в ортогональной проекции нет никакой разницы.
Я также внес небольшие изменения в другой код.
double mouse_x, mouse_y;
glfwGetCursorPos(window, &mouse_x, &mouse_y);
vec3 mouse_pos = vec3(float(mouse_x), float(mouse_y), 0.0f);
world_mouse_pos = unProject(mouse_pos, view, projection, vec4(0, 0, window_width, window_height));
mouse_offset.x = last_mouse_pos.x - world_mouse_pos.x;
mouse_offset.y = last_mouse_pos.y - world_mouse_pos.y;
last_mouse_pos.x = world_mouse_pos.x;
last_mouse_pos.y = world_mouse_pos.y;
mouse_offset = -mouse_offset;
m_state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_MIDDLE);
if (m_state == GLFW_PRESS){
view = translate(view, vec3(mouse_offset*0.5, 0.0f));
glUniformMatrix4fv(view_loc, 1, GL_FALSE, &view.data[0][0]);
}
Я умножаю mouse_offset на -1, чтобы получить инвертированные элементы управления, что является просто предпочтением, но я также умножаю его на 0,5, что в основном является скоростью панорамирования камеры.
Других решений пока нет …