Я пытаюсь выбрать лучи при столкновении, что означает, что 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). Тем не менее, некоторые лучи не пересекаются с моделью.
Есть идеи, почему это так? Или как это решить? За это отвечает извлечение кромки с предыдущим размытием?
Я прикрепил изображение, где можно увидеть распределение. Синие точки — это те, которые не пересекаются с моделью (длина луча близка к значению дальней плоскости), а красные -. Я использовал модель чайника для моего тестирования.
Я не хотел вставлять весь свой код сюда для удобства чтения. Если вам нужно больше кода или информации, чтобы лучше понять, что может быть не так, пожалуйста, дайте мне знать.
За это отвечает извлечение кромки с предыдущим размытием?
Да, конечно.
Я полагаю, что вместо фильтра постобработки при обнаружении кромок вы используете растровый фрагментный шейдер для выделения кромок. На самом деле все просто:
Преобразуйте нормаль лица в экранные координаты (для фрагмента). Если abs(screenspace_normal.z) < threshold
лицо перпендикулярно экрану, следовательно, ребро. Для всех фрагментов, которые не являются ребром discard
фрагмент. То, что осталось, это фрагменты, которые (близко) к краю и могут быть дополнительно обработаны.
Имейте в виду, что это также извлечет края «скрытых» поверхностей. Таким образом, вы, вероятно, должны выполнить «ранний Z» проход к тесту глубины, затем второй проход, который не записывает в буфер глубины и только испускает фрагменты ребер.
Других решений пока нет …