在3D视图中实现操作手柄的方法

4
我正在构建一个简单的实体建模应用程序。用户需要能够在正交和透视视图中操作对象。例如,当屏幕上有一个盒子并且用户单击它选择它时,它需要在角落和中心处获得“手柄”,以便用户可以将鼠标移动到这样的手柄上并拖动它以扩大或移动盒子。
有哪些策略可以做到这一点,哪一种是最好的?我可以想到两个明显的方法:
1)将手柄视为3D对象。即对于一个盒子,在“主”盒子的角落添加小盒子。问题:这在透视视图中不起作用,我需要确定盒子的大小与当前缩放级别相关(无论用户缩放多少,手柄都需要具有相同的大小)
2)在场景渲染后添加手柄。渲染到离屏缓冲区,以某种方式确定角落的2D位置,并使用常规的2D绘图技术绘制手柄。问题:如何进行命中测试?我需要采用两阶段命中测试方法;如何在3D渲染的图像上进行2D绘制?退回到GDI?
这两种方法可能还存在更多问题。是否有行业标准的解决此问题的方法?
如果使用OpenGL,是否会有所不同?
4个回答

2
首先,将手柄/角落坐标投影到相机平面上(有效地将它们转换为屏幕上的2D坐标;将其与屏幕尺寸进行归一化)。
以下是一些简单的代码,用于启用正交/2D叠加绘图:
void enable2D()
{

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    int wind[4];
    glGetIntegerv(GL_VIEWPORT,wind);
    glOrtho(0,wind[2],0,wind[3],-1,1);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
}


void disable2D()
{
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
}

enable2D() 函数缓存当前的模型视图/投影矩阵,并用一个归一化到屏幕大小(即屏幕的宽度/高度)的投影矩阵替换原有的投影矩阵,同时将模型视图矩阵恢复为单位矩阵。

调用该函数后,您可以使用屏幕/像素坐标进行 glVertex2f() 调用,从而实现 2D 绘图!(这也将使您能够进行命中测试,因为您可以轻松获取鼠标的当前像素坐标。)

完成绘图后,请调用 disable2D 函数以恢复旧的模型视图/投影矩阵 :)

最困难的部分是计算 2D 平面上的碰撞框位置并处理重叠(如果两个项目映射到同一位置,则在单击时选择哪个?)

希望这有所帮助 :)


这看起来是一个非常有用的技巧,我可以在我的代码中使用它的许多其他地方,谢谢!我对OpenGL还很陌生,所以我仍在学习绳索,像这样的技巧似乎很难得到。谢谢! - Roel

2
我会将手柄视为三维对象。这样做有很多优点,例如更加一致,表现良好,易于进行点击测试等。
如果您希望手柄保持恒定大小,您仍然可以将它们视为三维对象,但是您需要根据与相机的距离适当地缩放它们的大小。虽然这可能有点麻烦,但由于通常只有几个手柄,并且这些通常是小对象,因此在性能方面应该没问题。
然而,我建议让手柄随着场景缩放。只要选择一个使它们突出的渲染样式(例如:明亮的橙色框等),透视效果(背景中较小的手柄)可以在许多方面为最终用户更轻松地处理它们提供更多的视觉线索。从三维场景中获得深度感是困难的 - 手柄的透视效果有助于提供更多关于手柄如何“浸入”屏幕的视觉线索。

我理解你关于透视角度增加视觉线索的观点。但我还不确定这是否会让用户感到自然;例如,如果手柄被其他物体遮挡怎么办?我会检查一些其他的3D建模软件来看看它们是如何处理的,并在我的测试应用程序中尝试两种方法。感谢你抽出时间来回答我的问题。 - Roel
一个选项是允许透视保持,但在深度测试关闭时渲染它们。它们始终可见(即使在其他对象的上面)。我不会将其作为默认方式,但这是一个不错的选项,因此您可以切换打开/关闭以始终显示手柄,即使“穿过”对象。 - Reed Copsey
我仍需要弄清楚深度缓冲区是如何工作的,但我想那应该会起作用。我还有很多试错要做 :) 谢谢。 - Roel
在这种情况下,您将关闭写入和测试深度缓冲区 - 基本上,它将始终绘制您的对象(在其他所有内容之上)。 这不太直观,但作为切换/选项非常有用。 - Reed Copsey
我们在我之前作为3D应用程序编写者时使用了这种方法,效果很好。不过我不会关闭深度测试。 - ChrisF
我都做过。关闭深度测试是一个不错的选择,如果你有很多其他可能会遮挡你的控制柄的对象,但它需要成为一个选项。作为默认值,这真的很令人困惑。 - Reed Copsey

1

1

我已经为一个3D编辑软件编写了带有手柄的操作器,并遇到了许多相同的问题。

首先,有一个开源的操作器。我在最近的搜索中找不到它,可能是因为这些东西有很多名称 - 3D小部件、小工具、操作器、万向节等等。

无论如何,我的做法是将一个操作器对象添加到场景中,在绘制时绘制所有手柄。它对于边界框计算和选择也是一样的。

Reed关于保持它们相同大小的想法对于存在于对象上的手柄是有趣的,可能在那里起作用。但对于操作器来说,我发现它更像是一个3D用户界面元素,如果它不改变大小,它会更加易用。我有一个错误,其中大小仅基于活动视口确定,导致其他视口中出现非常巨大/微小的操作器,非常无用。如果您要将它们添加到场景中,您可能需要按视口添加它们,或者使它们实际上具有固定的大小。


你能解释一下你的“操作器”是做什么的吗?它似乎与我在问题中描述的“手柄”不同? - Roel
当然.. manipulator 是一个小工具,它提供了转换几何图形的控制杆。通常它是对象、顶点、边缘、面或其他组件。这是 Maya manipulator 的一张图片:http://www.imanishi.com/mayablog/mayaPolygon/pC1.jpg - tfinniga

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接