От 2D ребра до пространства трехмерной модели через glm :: unproject — луч не пересекается с моделью

Я пытаюсь выбрать лучи при столкновении, что означает, что 2D-позиция на экране преобразуется в 3D-позицию в пространстве модели.
Моя проблема в том, что луч не всегда пересекается с моделью, чтобы получить правильное трехмерное положение.

Вот что я делаю:

Я создаю текстуру глубины в кадровом буфере, чтобы glReadPixels() из этого позже.

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, screenWidth, screenHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);

cv::Mat_<float> depthCV(screenHeight, screenWidth);
glReadPixels(0, 0, screenWidth, screenHeight, GL_DEPTH_COMPONENT, GL_FLOAT, depthCV.ptr());

Затем я линеаризую глубину и сохраняю ее в cv::Mat_<uchar> для обнаружения края через cv::Canny(): (Не забудьте перевернуть изображение.)

cv::blur(gray, edge, cv::Size(3, 3));
cv::Canny(edge, edge, edgeThresh, edgeThresh * ratio, 3);

… и получить контур через

cv::findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE, cv::Point(0, 0));

2D координаты (x, y) контура (ов) теперь преобразуются в координаты 3D модели посредством:

GLint viewport[4];
GLfloat winX, winY, winZ;
glGetIntegerv(GL_VIEWPORT, viewport);
winX = (float)x;
winY = (float)viewport[3] - (float)(y);
glReadPixels(x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
glm::vec4 viewportvec(viewport[0], viewport[1], viewport[2], viewport[3]);
glm::vec3 winCoords(winX, winY, winZ);

glm::vec3 modelCoords = glm::unProject(winCoords, view*model, proj, viewportvec);

После этого и просмотра трехмерных точек видно, что некоторые лучи не пересекаются с моделью. Длина луча близка к значению дальней плоскости.
Я попытался расширить вход, посмотрев также на окрестность в один пиксель вокруг входа (x, y). Тем не менее, некоторые лучи не пересекаются с моделью.

Есть идеи, почему это так? Или как это решить? За это отвечает извлечение кромки с предыдущим размытием?

Чайник

Я прикрепил изображение, где можно увидеть распределение. Синие точки — это те, которые не пересекаются с моделью (длина луча близка к значению дальней плоскости), а красные -. Я использовал модель чайника для моего тестирования.

Я не хотел вставлять весь свой код сюда для удобства чтения. Если вам нужно больше кода или информации, чтобы лучше понять, что может быть не так, пожалуйста, дайте мне знать.

0

Решение

За это отвечает извлечение кромки с предыдущим размытием?

Да, конечно.

Я полагаю, что вместо фильтра постобработки при обнаружении кромок вы используете растровый фрагментный шейдер для выделения кромок. На самом деле все просто:

Преобразуйте нормаль лица в экранные координаты (для фрагмента). Если abs(screenspace_normal.z) < threshold лицо перпендикулярно экрану, следовательно, ребро. Для всех фрагментов, которые не являются ребром discard фрагмент. То, что осталось, это фрагменты, которые (близко) к краю и могут быть дополнительно обработаны.

Имейте в виду, что это также извлечет края «скрытых» поверхностей. Таким образом, вы, вероятно, должны выполнить «ранний Z» проход к тесту глубины, затем второй проход, который не записывает в буфер глубины и только испускает фрагменты ребер.

0

Другие решения

Других решений пока нет …