本文内容主要参考于页面

http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Ogre+Wiki+Tutorial+Framework

Ogre是一个非常好的开源面向对象的3D引擎,架构合理清晰,源代码总体来说(相对于这么大的项目而言)相当工整,逻辑几乎可算一目了然。很值得学习 3D图形学的同学研究。

作为初入手,应该抓住主要矛盾,对Ogre的框架有一个把握。因此,抛却旁枝,这里只讨论Ogre运行所需要的最小最精炼的步骤。这里将我的学习心得记录如下:

Ogre中必需的类

1 Ogre::Root,这个类是一切的起源。因此,一个Ogre程序,第一件要做的事就应该是new一个Root,并将其保存下来。

创建者: 无,直接new

作用:

Ogre的主干,渲染流程所在的类。但是它并不做具体的事情,它只是定义了抽象的渲染流程。负责调度framelistener。它负责加载所有插件。Ogre中具体的事情都由插件做,诸如场景管理,渲染器等等。而这些散落在各处的具体工作执行者,就由Ogre::Root来创建和组织。

创建之前的条件:

无任何条件

2 Ogre::RenderWindow,这个类代表了被渲染的窗口

创建者:Ogre::Root

创建方式:

Ogre::Root::initialize(true,..);或者Ogre::Root::createRenderWindow

作用:

还用说么?没它你看个蔡国庆。

创建之前的条件:

必须调用了Ogre::Root::initialize,这个函数初始化了渲染器,没渲染器也就没法创建渲染窗口

3 Ogre::SceneManager,这个类代表了场景管理器

创建者:Ogre::Root

创建方式:Ogre::Root::createSceneManager

作用:
通过组织一系列的Ogre::Node,组成了场景,Node中挂着各种物体,从而让3D世界构造起来。

同时,场景中的物体,也通过它来创建。作为生产者,它和Root的不同在于Root创建更底层的类,它则创建鲜活的对象类

4 Ogre::Camera,这个类代表了摄像机

创建者:Ogre::SceneManager

创建方式:Ogre::SceneManager::createCamera

作用:

3D世界的视图矩阵和投影矩阵,有了它,鲜活的3D世界才可以转变成屏幕坐标从而才能显示到屏幕上。

5 Ogre::Viewport,视口,这个类代表游戏窗口中的一个区域,这个区域用来显示渲染结果

创建者:Ogre::RenderWindow

创建方式:Ogre::RenderWindow::addViewport

作用:

定义屏幕上一块区域用于显示某个摄像机的投影和裁剪结果。因此,创建函数中应该传入一个摄像机。

有了这些,Ogre世界将运转起来。

但是仅仅是展现还不够,我们还需要输入进行用户交互。于是我们必须初始化OIS输入设备库。

1 OIS::InputManager OIS的基础类,必须第一个创建,具体的输入设备则由其来创建管理

创建者:无,直接通过类的createInputSystem静态函数创建。创建时需要填写ParamList,ParamList中最重要的是"WINDOW"值,这个值只要把窗口句柄(以Windows为例是HWND,对Ogre,我们可以通过对RenderWindow调用getCustomAttribute方法取得名为"WINDOW"的值,这个值类型为size_t,从而达到跨平台解决)通过%d格式化到一个字符串里即可。这样OIS就和该窗口绑定起来。

创建方式:OIS::InputManager::createInputSystem

作用:

OIS的基础

2 OIS::Keyboard, OIS::Mouse等各种输入输出设备

创建者:OIS::InputManager

创建方式:OIS::InputManager::createInputObject

作用:

具体输入对象的代理,创建以后,即可以向其注册listener来侦听事件

创建了以后还不算完事,必须在游戏大循环的合适位置进行事件分发才行,这个步骤通过在合适的位置调用输入输出设备OIS::Keyboard或OIS::Mouse等的capture方法完成。对Ogre而言,最合适的是放在frameListener的frameRenderingQueued中最合适。

Ogre程序所必须的Listener。

Ogre和OIS输入设备都有其固定的流程,因此我们必须实现它们的listener,从而把我们的处理逻辑插入到它们的固定逻辑中。最小的Ogre程序,应当有如下Listener

1 Ogre::FrameListener

身份:在帧循环的特定时候被调用

推荐重写的函数:

frameRenderingQueued。可以把这个函数看成游戏中的tick,这个函数在cpu向gpu发送了绘图指令以后被调用,此时gpu处于全速运行状态,cpu执行这个函数能够达到cpu和gpu并行工作,提高工作效率的效果。这个函数由于在渲染之后调用,它执行的结果会体现在下一帧,这一般不会对游戏构成影响。

2 Ogre::WindowEventListener

身份:侦听游戏窗口的事件,如Resize move之类

推荐重写的函数:

windowResized。这个函数当窗口Resize时调用,在这里一定要做一件事,设置OIS中Mouse的裁剪区域.

unsigned int width, height, depth;
int left, top;
window->getMetrics(width, height, depth, left, top);
const OIS::MouseState& ms = mouse->getMouseState();
ms.width = width;
ms.height = height;

windowClosed。这个函数中销毁OIS对象。

if (window == w)
{
if (inputManager)
{
inputManager->destroyInputObject(keyboard);
inputManager->destroyInputObject(mouse);
}
OIS::InputManager::destroyInputSystem(inputManager);
}

3 OIS::MouseListener OIS::KeyListener

这两个就没什么好说了,按需编写

最后,总结一下最小ogre程序的流程:

1 创建Ogre::Root

2 用Ogre::Root加载插件,必须载入的是场景管理器和渲染器

3 调用Ogre::ResourceGroupManager::getSingleton().addResourceLocation来设置资源搜索路径(Ogre的资源管理很智能,不需要自己指定路径,只需要给它一个搜索路径,然后所有material等脚本和资源文件按名字会被载入到ResourceManager中(但只对资源来说只是存了一个引用,并没有实际的载入),就可以通过名字来访问。

4 创建渲染窗口,这里我们经常这么写

if (root->showConfigDialog())
{
root->initialise(false);
window = root->createRenderWindow("Window", 800, 600, false);
}
else
{
return false;
}

这样一来会弹一个Ogre的配置窗口,然后还会把配置保存到文件中,配置文件名在创建Root的时候给出,如果不给出,会用默认的名字ogre.cfg。

也可以先来一句root->restoreConfig从配置文件中读取配置,如果返回true表示读取成功,就不需要下一步了。

5 创建场景管理器,顺便设置场景环境光

6 创建摄像机

7 创建视口

8 初始化OIS

9 调用root->startRendering();进入游戏大循环。这个时候游戏进入了这个函数就再也不会出来了,直到窗口销毁。

Ogre的销毁

如何销毁Ogre?非常非常简单,只要一句话
delete root;

所有的工作都在Ogre::Root析构函数中做了。果然省事!

具体代码就不贴了,顶部的链接是ogre官方的,里面有一切,而且这个链接应该永远不会失效。

Ogre初入手:最简单的ogre程序骨架的更多相关文章

  1. OGRE启动过程详解(OGRE HelloWorld程序原理解析)

    本文介绍 OGRE 3D 1.9 程序的启动过程,即从程序启动到3D图形呈现,背后有哪些OGRE相关的代码被执行.会涉及的OGRE类包括: Root RenderSystem RenderWindow ...

  2. 关于OGRE与OSG的简单比较【转】

    关于OGRE与OSG的简单比较 林乃养 lnychina{at}gmail.com 浙江大学CAD&CG实验室 2010年3月27日 1 前言 我曾经细致阅读过OGRE和OSG官方提供的文档, ...

  3. 关于 OGRE 与 OSG 的简单比较 (转)

    关于 OGRE 与 OSG 的简单比较 1   前言 我曾经细致阅读过 OGRE 和 OSG 官方提供的文档,有<Pro OGRE 3D Programming>.OGRE自带手册(man ...

  4. C#编写简单的聊天程序

    这是一篇基于Socket进行网络编程的入门文章,我对于网络编程的学习并不够深入,这篇文章是对于自己知识的一个巩固,同时希望能为初学的朋友提供一点参考.文章大体分为四个部分:程序的分析与设计.C#网络编 ...

  5. 最简单的Windows程序

    准备研究一下vmp 保护,从一个最简单的Windows程序入手似乎是个不错的想法. 如何才最简单呢,仅仅有一个MessageBox 调用好了. 弹出消息.退出,哦也,够简单吧. 祭出法器VC2010. ...

  6. C#编写简单的聊天程序(转)

    这是一篇基于Socket进行网络编程的入门文章,我对于网络编程的学习并不够深入,这篇文章是对于自己知识的一个巩固,同时希望能为初学的朋友提供一点参考.文章大体分为四个部分:程序的分析与设计.C#网络编 ...

  7. Win32简单图形界面程序逆向

    Win32简单图形界面程序逆向 前言 为了了解与学习底层知识,从 汇编开始 -> C语言 -> C++ -> PE文件 ,直至今天的Win32 API,着实学的令我头皮发麻(笑哭). ...

  8. node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理

    一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...

  9. java基础学习02(简单的java程序)

    简单的java程序 一.完成的目标 1. 理解java程序的基本组成 2. 如何对程序代码进行注释 3. java标识符的命名规则 4. 了解java中的关键字 5. 使用java定义变量或声明变量 ...

随机推荐

  1. 怎么判定一个mac地址是multicast还是unicast.

    MAC地址是以太网二层使用的一个48bit(6字节十六进制数)的地址,用来标识设备位置.MAC地址分成两部分,前24位是组织唯一标识符(OUI, Organizationally unique ide ...

  2. html5 canvas 标签

    <canvas id="board" width="500" height="400"></canvas> < ...

  3. [hive小技巧]使用limit查询变成抽样,而不是全盘扫描

    将set hive.limit.optimize.enable=true 时,limit限制数据时就不会全盘扫,而是根据限制的数量进行抽样. 同时还有两个配置项需要注意: 1.hive.limit.r ...

  4. Hark的数据结构与算法练习之鸡尾酒排序

    算法说明 鸡尾酒排序又叫定向冒泡排序,鸡尾酒搅拌排序,搅拌排序,涟漪排序,回来排序,快乐小时排序. 鸡尾酒排序是交换排序的一种,它是冒泡排序的一个轻微的变种.冒泡是从低向高比较排序,鸡尾酒从低向高,从 ...

  5. Hark的数据结构与算法练习之快速排序

    前言 快速排序是最常见,也是面试中最容易考的排序方法,这里做一下总结 算法说明 其实这里说的很清楚了:http://blog.csdn.net/morewindows/article/details/ ...

  6. sprint1的个人总结及《构建之法》8、9、10章读后感

    对sprint1的总结: 我们这次的sprint1做的挺差的,大家原来说好的分工都没有完成,也许是大家这段时间的大作业花了更多的时间,所以对这次团队任务的进度是拖慢了很多,但是团队已经认清了现阶段的问 ...

  7. 数学+高精度 ZOJ 2313 Chinese Girls' Amusement

    题目传送门 /* 杭电一题(ACM_steps 2.2.4)的升级版,使用到高精度: 这次不是简单的猜出来的了,求的是GCD (n, k) == 1 最大的k(1, n/2): 1. 若n是奇数,则k ...

  8. Quartz.Net 配置模板范例

        1.App.config <?xml version="1.0" encoding="utf-8"?> <configuration& ...

  9. POJ2288 Islands and Bridges(TSP:状压DP)

    求一个图的哈密顿路径的最大权及其路径数.显然状态压缩+DP. dp[v][u][S] 表示从v走到当前顶点 u且走过的顶点集合是S的 最大权值和方案数 这题我用记忆化搜索,从终点开始递归进行,感觉这样 ...

  10. BZOJ3488 : [ONTAK2010]Highways

    对于询问(x,y),恰经过一条非树边且不经过树上两点间路径的路径数为: ·若x与y成祖先-孩子关系,假设y是x的祖先,z是y到x方向的第一个节点,则 ans=起点在x的子树里,且终点不在z的子树里的非 ...