9

我正在创建一个建模软件。我的模型都是由平面多边形组成的,它们只是我用 OpenGL 显示的一组有序的顶点。我已经做了很多搜索,令我惊讶的是,我没有找到很多关于我正在寻找的应用程序的信息。

我正在尝试使用矩形框来选择曲面。这听起来很简单,但我希望它的工作方式与此方法在许多程序中的工作方式相同。这些是我正在寻找的要求:

  1. 我想要一个从左边开始向右走的矩形,只选择那些完全包含在框内的对象。
  2. 从右边开始向左走的矩形应该选择任何被触摸的表面(它不必完全封闭。
  3. 应选择矩形中/接触矩形的所有对象。换句话说,我想选择是否可见的对象。所有适合盒子的东西,即使被另一个表面覆盖,仍然应该被选中。

名单上的第 3 位是最重要的。最好同时拥有选项 1 和 2,但如果证明实施它们过于困难,我只能接受其中一个。

我查看了有关 3D 拾取的各种其他帖子,似乎大多数建议颜色拾取或光线投射。我将颜色拾取用于正常单击选择,但因为我希望框选择包括不可见的表面,所以这不是一个选项。似乎光线投射仅适用于单击点而不是框。那么有没有其他方法可以相当简单地实现我的目标?我认为这将是一项相当普遍的任务,因为它似乎存在于许多建模软件中,但不幸的是我一直无法找到适合我需要的方法。

算法的伪代码将受到赞赏,但不是必需的。至少我正在寻找一种我能够自己研究并找到一些例子的方法;我根本不知道该看的地方。

4

3 回答 3

7

在 CPU 上执行您自己的交集计算当然是一种选择。但根据我对您的要求的理解,我认为您也可以让 OpenGL 来完成这项工作,这应该更容易、更高效。

方法概述

想到的机制是遮挡查询。它们允许您计算已渲染的像素。如果将此与使用剪刀测试相结合,则可以计算在选择矩形内呈现的像素。

应用到用例

用例 2 是这种方法更简单的一个。您将选择矩形设置为剪刀矩形,并为每个表面使用遮挡查询渲染所有表面。然后检查查询的结果,查询结果大于 0 的所有表面在选择矩形内都有像素。

用例 1 稍微复杂一些。要知道曲面是否完全包含在矩形内,您需要通过两次。在启用剪刀测试的情况下,您可以像上面那样使用遮挡查询进行一次渲染。然后你第二次做同样的事情,禁用剪刀测试。如果一个表面在两次传递中具有相同的查询结果,则它完全在矩形内。

执行

我不会为此提供完整的代码。这一切都应该很简单。但这里有一些指针和代码片段。调用显示为 C 绑定。我希望它在 Python 绑定中看起来很明显。

首先,由于您想在选择中包含隐藏的表面,您需要禁用深度测试:

glDisable(GL_DEPTH_TEST);

由于您实际上并不需要产生输出,并且可能不想干扰视觉渲染输出,因此您可能还想禁用颜色输出:

glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

如果您启用了背面剔除,您可能还想禁用它:

glDisable(GL_CULL_FACE);

然后,对于上面提到的只想计算选择矩形内的像素的通道,设置剪刀矩形,并启用剪刀测试:

glScissor(selectionLeft, selectionBottom, selectionWidth, selectionHeight);
glEnable(GL_SCISSOR_TEST);

对于使用遮挡查询的渲染,您需要每个表面的查询对象:

GLuint queryIds[surfaceCount];
glGenQueries(surfaceCount, queryIds);

然后对于每个表面,k用作循环索引:

glBeginQuery(GL_SAMPLES_PASSED, queryIds[k]);
// render surface k
glEndQuery(GL_SAMPLES_PASSED);

渲染完所有表面后,可以得到查询结果:

GLint pixelCounts[surfaceCount];
// for all surfaces k
glGetQueryObjectiv(queryIds[k], GL_QUERY_RESULT, &pixelCounts[k]);

然后评估像素数以决定应该为每个用例选择哪些表面,如上一节所述。

完成后不要忘记重置所有状态以准备再次渲染。深度测试、彩色蒙版、剪刀测试等

于 2015-08-22T03:59:46.703 回答
5

我可以直截了当地告诉你,挑选颜色是行不通的。您必须为每个对象执行一次才能满足要求(3),因为只有一个像素会进入帧缓冲区。

至于光线投射,它确实只测试一个点,但您实际上可以通过取消投影选择矩形的四个角来创建一个测试体积。Win_Z = 0您将在近平面 ( ) 和远平面 ( )找到世界空间中的坐标,Win_Z = 1并使用它从 2D 选择区域构建 3D 体积。

您将从中获得的体积称为截锥体(假设透视投影),它看起来像一个顶部被切掉的金字塔。平截头体相交测试有很好的文档记录,任何讨论“平截头体剔除”的内容都应该为您提供足够的背景来实现这一点。如果您可以使用轴对齐的边界框和/或球体来近似这些对象的边界,您的生活将会轻松很多。

很好地说明了这个测试卷:

   在此处输入图像描述

于 2015-08-21T17:44:53.543 回答
0

我知道我迟到了,但实际上颜色选择可以通过变通方法来选择深层对象,同时表现出色:按下 shift + 鼠标滚动时进行选择剥离。

或者换句话说,当您进行第一次矩形测试时,记住矩形位置,然后让用户按下 shift +鼠标滚动,当用户滚动时,从渲染中临时移除已选择的对象(因此剥离)(仅在渲染到选择缓冲区时)并添加任何新的选定对象到选定的阵列。继续,直到用户停止滚动或按 shift。

需要注意的是,一旦您移动或旋转相机,此方法将无法正常工作,但是当用户这样做时,您可以使最后一个矩形无效或临时将相机的增量矩阵应用于整个世界,当用户没有使最后一个选择无效时,用户执行 shift+鼠标滚动但出于这个原因,除非您卡在非常旧的硬件或移动设备上,否则最好还是坚持使用遮挡查询(opengl es 2 没有扩展名)

另一个是对于小于 1 像素的对象,颜色拾取失败但很少出现问题(尽管对于矩形拾取,根据用例选择“不可见”对象可能是有意义的)

于 2020-10-31T01:33:51.143 回答