3DHelper






4.61/5 (9投票s)
用于显示 3D 数据的辅助类

引言
是否曾遇到过显示与 3D 相关的数据的问题?例如,在 Windows 对话框窗口中显示 3D 曲线?不喜欢实现整个 DirectX/OpenGL 类层次结构?
有一个解决方案:3DHelper
类!
可以在我的 主页 上找到更多工具。
背景
如果您熟悉 3D 编程,可能已经使用过免费/非免费的库来执行将 3D 对象渲染到屏幕上的任务。
这种方法的一个很大(在我看来!)的缺点是:您的代码变得越来越复杂,难以维护甚至难以理解。更不用说可移植性了。
只需要将一些文件包含到您的项目中,即可执行所有必要的数学运算以“获得 3D”听起来太好了,不像是真的?现在它实现了!
解决方案
本文中描述的 API 的目的是简单地帮助您将 3D 数据投影到您的 2D 窗口中。
给定一个 3D 点(例如,作为 nurbs 曲面的一部分的点、一个 3D 函数值等),API 会转换此点并返回一对坐标,表示您窗口中的一个点。
而且最好的是 - 没有涉及复杂的 OpenGL/DirectX。这是一个纯粹的软件解决方案。
使用代码
为了让 API 帮助您,它需要执行一些基本步骤
- 将类型为
CMF3DHelper
的变量添加到您的项目中。 - 在启动时(以及每次调整大小事件后)调用您的变量的
CMF3DHelper::Initialize()
函数。(参见 1.)
此Initialize()
函数需要参数- 指向您的窗口的设备上下文 (DC) 的指针(用于获取窗口大小)
- 代表您数据的“立方体”,由两个向量表示:
vmin
和vmax
。
您的所有数据点都应位于该立方体内。想象一下类似一个边界立方体,覆盖您的所有数据点。
2D 示例: 您需要显示形式为 y=sin(x) 的曲线,其中 x 在 [-PI] 和 [+PI] 之间。该函数的结果在 [-1] 到 [+1] 的范围内。
因此,您必须使用两个角定义边界框(2D!)
(-1, -PI),即左上角,
(+1, +PI) 类似于右下角。 - 一个标志 (
bSupportTrackBall
) 告诉 API 是否执行由鼠标控制的旋转。
- 对于要计算的每个数据点,调用
RenderPoint()
函数。它返回您的 3D 数据点对应的屏幕(=窗口)坐标。
最好检查 3DHelperDemoSimple
项目。我将代码减少到最少(无检查代码)以阐明这些步骤。
打开 3DHelperDemoSimple
项目,然后选择 OnInitDialog
方法。
只有以下几行被添加到向导生成的代码中:
// Initialize the 3D system
initialize();
initialize
函数本身在下面几行实现。
执行的步骤
- 初始化 API。
- 启动更新计时器,用于刷新鼠标(=旋转)信息。在我们的例子中,整个场景将每 25 毫秒重绘一次。
// Set up initial 3D system
void CMy3DHelperDemoSimpleDlg::initialize()
{
CWnd *pTarget = GetDlgItem(IDC_STATIC_PLACEHOLDER);
m_c3DHelper.Initialize(pTarget->GetDC(), NeHe::Vector(-2.0f, -2.0f, -2.0f),
NeHe::Vector(2.0f,2.0f,2.0f), TRUE);
// Timer used to refresh "trackball" information
SetTimer(1, 25, NULL);
}
由计时器触发,每 25 毫秒将进入 OnTimer
函数。
在内部,将更新轨迹球位置 (UpdateTrackBall
,这再次需要当前 DC 作为参数),并且将重绘场景 (redraw()
)。
void CMy3DHelperDemoSimpleDlg::OnTimer(UINT nIDEvent)
{
// Timer is used to refresh trackball information
if(nIDEvent == 1) {
KillTimer(nIDEvent); // Prevent timer "overlapping"
m_c3DHelper.UpdateTrackBall
(GetDlgItem(IDC_STATIC_PLACEHOLDER)->GetDC());
redraw();
SetTimer(1, 25, NULL); // Start timer for next redrawing round
}
CDialog::OnTimer(nIDEvent);
}
Redraw
再次很简单。只需逐点获取您的数据点,为每个点调用 RenderPoint()
并使用例如 SetPixel()
函数显示结果。
3DHelperDemo
项目实现了更复杂的示例。
兴趣点
我决定不亲自实现整个数学运算 (认为那不是一个独特的任务...)。因此,我从 NeHe(一个与 OpenGL 相关的 GREAT 站点,我得到了 5 分!)中获取了一些矩阵/向量代码。
为了更好地了解 OpenGL 的实现方式,我仔细研究了免费的 mesa 实现。对于每个对 3D 实现感兴趣的人来说,这都是必须的!
注释
欢迎任何反馈!
在 SoftwareHive 上查看更多工具和更新。
历史
- 2009/02/14 - 初始发布