0

我尝试通过碰撞进行光线拾取,这意味着屏幕上的 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) 周围的一个像素邻域来扩大输入。仍然有一些光线不与模型相交。

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

茶壶

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

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

4

1 回答 1

0

具有先前模糊的边缘提取是否负责?

是的,当然。

我建议您实现边缘提取光栅化片段着色器,而不是边缘检测后处理过滤器。其实很简单:

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

请注意,这也会提取“隐藏”表面的边缘。因此,您可能应该执行“早期 Z”传递到深度测试,然后进行第二次传递,该传递不写入深度缓冲区并且只发出边缘片段。

于 2016-07-18T17:12:11.003 回答