通过glm :: unproject实现2D边缘到3D模型空间 - 射线不与模型相交

时间:2016-07-18 14:16:50

标签: c++ opencv opengl 3d back-projection

我尝试通过碰撞进行光线拾取,这意味着屏幕上的2D位置将转换为模型空间中的3D位置。 我的问题是,光线并不总是与模型相交,从而产生有效的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);

执行此操作并查看其显示的3D点后,某些光线不会与模型相交。光线的长度接近远平面的值。 我试图通过查看输入(x,y)周围的一个像素邻域来扩大输入。还有一些光线不会与模型相交。

知道为什么会这样吗?或者如何解决?先前模糊的边缘提取是否对它负责?

Teapot

我附上了可以看到分布的图像。蓝点是不与模型相交的点(光线的长度接近远平面的值),红点是。我使用茶壶模型进行测试。

我不想在这里粘贴我的整个代码以方便阅读。如果需要更多代码或信息来更好地了解可能出现的问题,请告知我们。

1 个答案:

答案 0 :(得分:0)

  

先前模糊的边缘提取是否对它负责?

是的,当然。

我建议您使用边缘提取光栅化片段着色器而不是边缘检测后处理滤镜。它实际上很简单:

将面法线转换为屏幕坐标(每个片段)。如果abs(screenspace_normal.z) < threshold脸部垂直于屏幕,则为边缘。对于不是边缘discard片段的所有片段。剩下的是(接近)边缘并且可以进一步处理的碎片。

请注意,这也会提取&#34;隐藏&#34;的边缘。表面。所以你应该在早期的Z&#34;传递给深度测试,然后是第二次传递,它不会写入深度缓冲区,只发出边缘片段。