12

如图所示

http://oi56.tinypic.com/ifu33k.jpg

我将一组轮廓(多边形)绘制为 GL_LINE_STRIP。现在我想在鼠标下选择曲线(多边形)来删除,移动..等 3D 。

我想知道使用哪种方法:

1.使用OpenGL拾取和选择。( glRenderMode(GL_SELECT) )

2.使用手动碰撞检测,通过使用pick-ray并检查光线是否在每个多边形内。

4

7 回答 7

19

我强烈建议反对 GL_SELECT。这种方法在新的 GL 版本中非常古老且不存在,并且您可能会遇到现代显卡的问题。不要指望它会被硬件支持——可能你会在许多 GPU 上遇到这种模式的软件(驱动程序)回退,只要它可以工作。使用风险自负:)

让我为您提供一个替代方案。

对于坚固的大物体,有一种古老的、很好的选择方法:

  • 在光标位置启用并将剪刀测试设置为 1x1 窗口
  • 在没有照明、纹理和多重采样的情况下绘制屏幕,​​为每个“重要”实体分配唯一的纯色 - 这种颜色将成为用于拾取的对象 ID
  • 调用 glReadPixels 并检索颜色,然后用于识别拾取的对象
  • 清除缓冲区,将剪刀重置为正常大小并正常绘制场景。

这为您提供了一种非常可靠的“按对象”拾取方法。此外,以最少的每像素操作仅绘制和清除 1 个像素不会真正影响您的性能,除非您缺乏顶点处理能力(我认为不太可能)或有很多对象并且可能会占用 CPU-受限于绘制调用的数量(但话又说回来,如果您可以将颜色作为每像素数据传递,我相信可以将其优化为单个绘制调用)。

RGB 中的颜色是 3 个无符号字节,但应该可以另外使用帧缓冲区的 alpha 通道作为最后一个字节,因此您总共可以获得 4 个字节 - 足以将任何指向对象的 32 位指针存储为颜色。

或者,您可以为此创建具有特定像素格式(例如GL_R32UI,或者即使GL_RG32UI您需要 64 位)的专用帧缓冲区对象。

对于严格的几何方法,上述方法是一个不错且快速的替代方案(无论是在可靠性方面还是在实施时间方面)。

于 2010-10-30T16:52:13.593 回答
6

我发现在新的 GPU 上,GL_SELECT 模式非常慢。我尝试了几种不同的方法来解决这个问题。

第一个是进行 CPU 碰撞测试,它有效,但没有我希望的那么快。当您将光线投射到屏幕中(使用 gluUnproject)然后试图找到鼠标正在与哪个对象发生碰撞时,它肯定会减慢速度。我获得令人满意的速度的唯一方法是使用八叉树来减少碰撞测试的数量,然后进行边界框碰撞测试 - 但是,这导致了一种不是像素完美的方法。

我确定的方法是首先找到鼠标下的所有对象(使用 gluUnproject 和边界框碰撞测试),这通常非常快。然后,我将后缓冲区中可能与鼠标碰撞的每个对象渲染为不同的颜色。然后我使用 glReadPixel 获取鼠标下的颜色,并将其映射回对象。glReadPixel 是一个缓慢的调用,因为它必须从帧缓冲区中读取。但是,它每帧执行一次,最终花费的时间可以忽略不计。如果您愿意,可以通过渲染到 PBO 来加速它。

贾瓦

于 2010-10-31T00:15:25.987 回答
3

umanga,看不到如何在线回复...也许我应该注册:)

首先,我必须为给你错误的算法道歉——我做了背面剔除一个。但是您需要的非常相似,这就是我感到困惑的原因……哦。

如前所述,将相机位置获取到鼠标矢量。

对于每个轮廓,循环遍历其中的所有坐标 (0-1, 1-2, 2-3, ... n-0),并像以前一样从它们中生成一个 vec。即走轮廓。

现在做这两个(轮廓边缘到鼠标vec)的交叉刺激,而不是像我之前说的那样在对之间做,对所有对做这个,向量把它们加起来。

最后找到结果向量的大小。如果结果为零(考虑到舍入误差),那么你的形状就在外面 - 无论面对。如果您对面感兴趣,那么您可以使用鼠标矢量而不是 mag 来做那个点刺,以找到面并测试符号 +/-。

它之所以有效,是因为算法依次找到从矢量线到每个点的距离量。当你总结它们并且你在外面时,它们都被抵消了,因为轮廓是封闭的。如果你在里面,那么它们都会总结出来。它实际上是物理学中的高斯电磁场定律......

请参阅:http://en.wikipedia.org/wiki/Gauss%27s_law 并注意“等式的右侧是由 S 包围的总电荷除以电常数”,注意“封闭”一词 - 即零表示不封闭。

您仍然可以使用边界框进行优化以提高速度。

于 2010-11-01T15:04:49.177 回答
1

过去,我使用 GL_SELECT 来确定哪些对象贡献了感兴趣的像素,然后在需要时使用计算几何来获得与对象的准确交集。

于 2010-10-28T08:07:12.973 回答
1

您希望通过单击轮廓(在边缘上)还是多边形内部来进行选择?您的第二种方法听起来像您希望在内部单击以选择最紧密的包含多边形。我不认为GL_SELECT渲染后GL_LINE_STRIP会使内部响应点击。

如果这是一个真正的等高线图(从我认为不是的图像来看,边缘似乎相交),那么可以使用更简单的算法。

于 2010-10-30T16:50:23.050 回答
1

如果您留在线条上,则不能使用选择,因为您必须单击渲染的线条像素,而不是线条内的空间,我将其读取为您希望执行的操作。

您可以使用 Kos 的答案,但为了渲染您需要填充的空间,这将涉及将所有轮廓转换为凸面类型,这很痛苦。所以我认为这有时会起作用,并且在某些情况下会给出错误的答案,除非你这样做。

你需要做的是使用CPU。您有来自视口和透视矩阵的视图范围。使用鼠标坐标,生成鼠标指针矢量的视图。您还拥有轮廓的所有坐标。

取第一个轮廓的第一个坐标,并为第二个坐标制作一个向量。用它们制作一个向量。取第三个坐标并制作一个从 2 到 3 的向量,并在轮廓周围一直重复,最后使最后一个从坐标 n 再次回到 0。对于序列中的每一对,找到叉积并总结所有结果。当您拥有最终的求和向量时,请保持并与鼠标指针方向向量进行点积。如果它的 +ve 则鼠标在轮廓内,如果它的 -ve 则它不在,如果为 0,那么我猜轮廓的平面和鼠标方向是平行的。

对每个轮廓执行此操作,然后您将知道其中哪些是被鼠标尖刺的。由您决定要从该集合中选择哪一个。最高 Z ?

听起来工作量很大,但还不错,会给出正确的答案。您可能还想保留所有轮廓的边界框,然后您可以通过对完整向量执行相同的数学运算,但仅在 4 边上,如果不在内部,则轮廓不能在里面任何一个。

于 2010-10-31T19:34:13.517 回答
0

第一个易于实施和广泛使用。

于 2010-10-28T07:45:57.597 回答