将 OGRE 图形引擎集成到您的 WPF 项目中






4.85/5 (27投票s)
将一流的图形引擎集成到您的 WPF 应用程序中。
我将演示项目分成了两部分上传。(抱歉 :-( OGRE 太大了,无法只上传一个文件。)
在运行演示之前,请将两个 zip 文件解压到同一个位置。
例如,在 WinZip 中点击“提取” -> “c:\temp”(两个文件都执行相同的操作)
完成后,您的目录结构应该如下所示:
..\OgreInWpf\DemoApps
..\OgreInWpf\Libraries
..\OgreInWpf\Media (必须存在)
..\OgreInWpf\Release (请转到此文件夹运行演示)
通过这个,你可以… 10 秒概览
- 将一流的图形引擎与一流的演示系统融合。
- 看到您的 UI 外观有多酷,您可能会激动得把咖啡洒在键盘上。
参考文献
- OGRE 1.4.8 (面向对象图形引擎) (http://www.ogre3d.org)
- MOGRE 1.4.8 (OGRE 的 .NET 受管包装器) (http://mogre.sourceforge.net)
- .NET Framework 3.5 SP 1 中的新
D3DImage
类 (D3DImage.aspx)
要求
- Visual Studio 2008
- .Net framework 3.5 (Service Pack 1)
- 一张性能不错的显卡。此项目可能无法在所有计算机上运行。我只在 NVidia 显卡上进行了测试。
引言
WPF 中的 Viewport3D
控件非常有用,但它缺乏专业的图形引擎那种酷炫的性能,例如
- 性能关键功能,如场景分页和“细节层次”网格,允许使用不同的配置显示大型网格;当靠近摄像机时使用高多边形版本,以便在高清很重要时;当远离摄像机时使用低多边形版本。
- 用于 **DirectX 像素着色器** 的 **GPU** (图形处理器) 脚本,以实现场景模糊或模拟夜视镜。我说的不是 GPU 代码本身,因为新的 3.5 SP1 框架拥有 GPU 位图效果,我指的是通过脚本资源机制轻松且可维护地应用这些花哨的功能,这样您甚至不需要编写一行代码就能在场景中包含炫酷的一流材质功能。(好吧,一行 ;-)这允许您轻松更改对象的材质,而无需重新编译。干净利落。
- 为纹理、脚本、GPU 着色器、动画等提供良好的程序集资源管理。
- 还有许多其他您需要的东西,甚至在您接触物理、声音、AI 和实际游戏方面之前…
正如您所见,现代游戏和动画效果确实涉及大量技术。现在,抛开图形不谈,如何在您的桌面上处理所有这些行为,阅读办公文档,允许用户在一个时髦、可主题化、支持数据绑定、Web 服务、华丽的烟雾效果等的界面中工作…
怀念吃豆人和 DOS 的好时光?那时一切似乎都简单多了。我知道我有时会…嗯,想念 DOS,而不是觉得它简单。尽管我知道有些人可能会对此持不同意见。

还不信服…好吧,好吧,假设您的老板来找您说,“弗兰克”(因为这是您的名字…您知道,或者鲍勃)。
“弗兰克,”他说,“我们需要为‘烟熏芝士公司’写一个应用程序,这个程序,哦,听好了,在主屏幕上有一个快速的小烟雾效果,您看,冒着烟——”(您对自己说,我可以做到,您知道,图形并不难)…“老板继续说,‘——在他们滚动的标志上,并显示一个来自 Web 服务的列表,用户可以点击——”
好的,现在突然有点难度了,因为图形引擎没有很好的 UI 控件(顺便说一句,老板还没停下来说话)
“…哇啦哇啦,周五之前!”老板说完。
不幸的是,鲍勃去喝茶了。
厄运毛茸茸的兔子综合症。
这些任务本身是否都可以完成?集成,我的意思是集成。
进入舞台(左):OgreImage 类
OgreImage
类与其他 WPF ImageSource
类一样。图像源可以用作背景、文本的画笔,或者显示在 Image
控件中,而 OgreImage
也不例外,除了它拥有了一流图形引擎的所有功能。它基于 .NET Framework 3.5 SP 1 更新中的新 D3DImage
(system.windows.interop.d3dimage.aspx) 类。
我以最简单的方式实现了在 D3DImage
类的 DirectX 上下文中托管 OGRE 引擎的过程。也就是说,您仍然需要像其他 .NET OGRE 应用程序一样通过 MOGRE 库与 OGRE 库进行交互,但不必处理屏幕重置大小和 DirectX 设备丢失/管理问题。我实现的一件事是 OGRE 资源的异步加载,并包含了一个进度事件系统,允许实现进度指示器(见示例)。我这样做是因为 OGRE 引擎启动可能需要一些时间。
目前还没有实现类似 Viewport3D
的控件,但我希望在此项目的基础上进行扩展,并使其更多地“Xaml 化”,以便可以在 XAML 中构建整个场景。
如何使用它
就像您可能在 Image
控件中显示位图一样,您可以这样做:
ImageSource
<Image x:Name="RenterTargetControl"
Stretch="Fill"
SizeChanged="RenterTargetControl_SizeChanged"
MouseDown="RenterTargetControl_MouseDown"
<Image.Source>
<OgreLib:OgreImage x:Name="_ogreImage"
Initialised="_image_InitScene"
PreRender="_image_PreRender"
ResourceLoadItemProgress=
"OgreImage_ResourceLoadItemProgress"/>
</Image.Source>
</Image>
这将通过 Image
控件在您的页面中包含 OgreImage
类。相关的事件是:
-
ResourceLoadItemProgress
事件,该事件会在每个资源加载时被调用。在这里,您可以获取资源的名称和一个标量(0 -> 1),表示整个加载过程的进度。private void OgreImage_ResourceLoadItemProgress (object sender, ResourceLoadEventArgs e) { _progressName.Text = e.Name; // scale the progress bar _progressScale.ScaleX = e.Progress; }
-
Initialised
事件。该事件在所有资源加载完成后(并在第一个帧渲染之前)被调用。在此事件中可以构建场景。
有关如何使用 OgreSceneManager
本身的信息,请参阅 Ogre wiki。void _image_InitScene(object sender, RoutedEventArgs e) { // start the scene fade in animation var sb = (Storyboard)this.Resources["StartEngine"]; sb.Begin(this); // get the Ogre scene manager SceneManager sceneMgr = _ogreImage.SceneManager; // create a light Light l = sceneMgr.CreateLight("MainLight"); // Accept default settings: point light, white diffuse, just set position // NB I could attach the light to a SceneNode // if I wanted it to move automatically with // other objects. l.Position = new Vector3(20F, 80F, 50F); // load the "ogre head mesh" resource. _ogreMesh = sceneMgr.CreateEntity ("ogre", "ogrehead.mesh"); // create a node for the "ogre head mesh" _ogreNode = sceneMgr.RootSceneNode.CreateChildSceneNode ("ogreNode"); _ogreNode.AttachObject(_ogreMesh); // Create shared node for the particle effects _fountainNode = sceneMgr.RootSceneNode.CreateChildSceneNode(); // Set nonvisible timeout ParticleSystem.DefaultNonVisibleUpdateTimeout = 5; // update the partical systems _cb_Click(null, null); }
-
PreRender
事件。该事件在帧渲染之前被调用。在这里,您可以更新或更改任何场景节点。void _image_PreRender(object sender, System.EventArgs e) { // if the viewport has changed reload the special effects if (_ogreImage.Camera.Viewport != _viewport) { _viewport = _ogreImage.Camera.Viewport; _cbCompositor_Click(_cbBloom, null); _cbCompositor_Click(_cbGlass, null); _cbCompositor_Click(_cbOldTV, null); } // rotate the "ogre head" _ogreNode.Rotate(new Vector3(0, 1, 0), new Degree(0.1f)); }
调整 Ogre 视口大小
另外,要使 Ogre 视口在 Image
大小改变时自行调整大小,您需要在 Image
的大小事件上手动调整 OgreImage
的大小。
private void RenterTargetControl_SizeChanged
(object sender, SizeChangedEventArgs e)
{
if (_ogreImage == null) return;
_ogreImage.ViewportSize = e.NewSize;
}
为了在窗口拖动时保持应用程序的响应能力,我让 OgreImage
类延迟处理大小调整。这将使图像等待几毫秒(默认为 200 毫秒),直到大小稳定下来。请查看 ResizeRenderTargetDelay
属性。
启动一切。“图形,你拥有了它们。”
还有一件事要做,那就是启动引擎。目前这是通过手动调用 InitOgreAsync
方法来完成的。引擎无法自动启动的原因是它需要一个有效的窗口句柄才能初始化自己,而在页面 XAML 加载过程中这个句柄是不可用的。我确信想出一个巧妙的解决方案并不难,但我把这个留给你们来完成。;-)
控件可以在窗口的 Loaded
事件上初始化。
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_ogreImage = (OgreImage)RenterTargetControl.Source;
_ogreImage.InitOgreAsync();
}
绑定到 OGRE 库和媒体
OGRE 库对于设置项目来说是一个庞然大物。在此文章的下载中,我只包含了必要的 DLL 和媒体,因为完整的 MOGRE 设置相当大。如果您想使用 MOGRE 进行开发,则需要下载完整的 SDK,它大约有 40 兆。
此项目中的可执行文件已编译到文章下载的“Release”文件夹中,其中包含所有 OGRE/MOGRE “Release” DLL 和资源配置文件。它们相当大,所以只有一个实例。也就是说,所有 VS 项目都已配置为将它们的生成输出直接发送到 Release 文件夹。
如果您想重新编译 MogreWpf.Interop.dll(一个 c++ 项目),您需要在 Windows 中设置 MOGRE_HOME 环境变量,以包含“<..>\MogreSDK”路径…下载 MOGRE SDK 后。另外,请在“Release”模式下编译它,以匹配此项目下载中的 Ogre 和 Mogre DLL。
关注点
- WPF 现在支持 GPU 位图效果 (a-series-on-gpu-based-effects-for-wpf)
本文不使用它们,只是让您知道现在可以在 WPF 中实现炫酷的功能,这可能会让您感兴趣。 - Ogre 是一个非常好的面向对象图形库。如果您喜欢图形编程,应该了解一下它。它是一个成熟的库,使用起来很有趣,并且拥有良好的纹理材质和粒子效果脚本语言。
结论
就这样,一个 3D 图形引擎集成到了您的 WPF 窗口中。哇哦…闪闪发光!
好的,这并不是创建每秒 2000 帧游戏的最佳方式。最好让 OGRE 引擎使用其原生窗口系统,但这会让您的老板在您的日常工作中对您赞不绝口。;-)
注意:在向“上述”老板做出任何承诺之前,请先阅读 OGRE 和 MOGRE 的许可证,并且我也不确定 OgreImage
的实现是否始终 100% 可靠。我遇到过一些奇怪的崩溃,但在我最后一次调整代码后(毛茸茸的兔子除外),它似乎相当稳定。但是,它应该为您开启“下一级别”图形之旅提供一个很好的起点。
历史
- 2008-09-09 - 初始发布