65.9K
CodeProject 正在变化。 阅读更多。
Home

虚拟轨迹球旋转控制器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (9投票s)

1999 年 12 月 2 日

4分钟阅读

viewsIcon

176517

downloadIcon

3977

  • 下载源文件 - 16 Kb
  • 引言

    这段代码源于我一个(未完成的)项目:一个使用 OpenGL 库的实时 3D 预览的图形曲线编辑器。

    起初,为了让用户从不同视角查看 3D 窗口中正在构建的对象,我只是简单地将鼠标移动与绕两个轴(通常是当相机沿 Z 轴时,绕 X 和 Y 轴)的旋转关联起来。

    这种方法使用一段时间后就不令人满意了,因为它在对象“颠倒”时会产生一个奇怪的效果:鼠标向右移动会导致明显的向左旋转,反之亦然。

    这种奇怪的效果是由于旋转必须相对于局部对象坐标系进行的。在后一种例子中,当对象颠倒时,它实际上是向右转的。

    在计算机图形学文献中,有许多关于“直观”旋转控制器的论文;我认为 K. Shoemake 的 arcball 控制器是最好的解决方案之一:其思想是将鼠标移动投影到一个假设的、充满 3D 窗口的球体上,并在按下鼠标按钮时,将由操纵球体产生的旋转应用于对象。

    内部

    全局旋转在内部使用四元数表示和调整,而不是旋转矩阵,因为这种方法在处理小增量旋转时数值更稳定。

    这个轨迹球融合了原始 arcball C 代码(用面向对象风格重写)以及 J. Childs 的虚拟轨迹球控制器(用于他的 GLcube 项目),而后者又源自 M. J. Kilgard 的 GLUT 库中的一些代码。

    这两段代码有几个相似之处(例如都使用了四元数),但投影算法不同,因此我决定保留两者:J. Childs 的控制器将鼠标移动投影到球体外的一个抛物面片上,而 K. Shoemake 的控制器将鼠标移动投影到平面上;第一种方法(默认方法)有点更自然,因为它效果是连续的,而第二种方法在鼠标离开/进入虚拟球体时会 abrupt 中断。

    在代码中,我(重新)使用了我常用的图形编程工具中的一套数学类,它注释良好,并包含一些可以使用 Doxygen 提取的文档。

    用途

    轨迹球代码在配套文章 CGLEnabledView - 支持 OpenGL 的 MDI 视图类 中得到了演示。

    要在您的程序中使用 CBallController,请按照以下步骤操作:

    1. 在需要的地方包含 BallController.h
    2. 在应用程序中的某个地方(我建议在视图类中)构造一个 CBallController,并在构造时指定虚拟球体的半径,半径范围从 0.1 到 1.0(半径为 1.0 表示球体完全填满窗口)。
    3. [可选] 调用 SetAlternateMethodToggleMethod 成员函数来设置投影到球体的方法。
    4. 在您的窗口大小调整处理程序例程中调用 ClientAreaResize 方法(也应在首次显示窗口之前调用),并将您的客户区大小作为参数传递。
    5. [可选但推荐] 在您的键盘按下处理程序中调用 Key 方法,传递字符代码,以通过键盘进行操作(有关按键绑定,请参阅下文)。
    6. [可选] 通过 UseConstraints 方法设置约束轴,可以通过 SetDrawConstraints 方法控制约束的绘制。
    7. 在您的鼠标处理程序例程中调用 MouseDownMouseMoveMouseMove 方法,传递以本地窗口坐标表示的鼠标坐标(原点在左上角);在鼠标按钮拖动期间捕获窗口外的鼠标移动可能是一个好主意。
    8. 在(重新)绘制场景之前调用 IssueGLrotation 方法。
    9. [可选] 在绘制场景后调用 DrawBall 方法,让 BallController 在使用备用方法进行旋转时显示一些反馈。

    其他方法
    使用 GetDrawConstraints 可以检查约束绘制是否已激活。GetAngleKeyIncrementSetAngleKeyIncrement 分别允许检索和设置键盘交互中使用的角度增量。GetColorVGetColorSetColorSetColorV 指定或检索 DrawBall 方法使用的颜色,颜色可以以 COLORREF 结构或 [0-1] 范围的浮点数向量形式传递。
    密钥

    Esc中断当前旋转操作(每次按下鼠标按钮都会开始一次旋转操作)
    CancNumpad 5重置当前旋转(对应于单位旋转矩阵)
    右箭头Numpad 6绕 X 轴旋转 +keyIncrement 度
    左箭头Numpad 4绕 X 轴旋转 -keyIncrement 度
    上箭头Numpad 8绕 Y 轴旋转 +keyIncrement 度
    下箭头Numpad 2绕 Y 轴旋转 -keyIncrement 度
    Page UpNumpad 9绕 Z 轴旋转 +keyIncrement 度
    HomeNumpad 7绕 Z 轴旋转 -keyIncrement 度
    TAB在约束旋转期间切换约束轴

    历史

    修订 描述
    0.2 首次公开发布
    0.1 个人开发版本
    © . All rights reserved.