恒大新城二期怎么样:OGRE教程 - 场景管理器
来源:百度文库 编辑:偶看新闻 时间:2024/04/25 18:01:00
OGRE教程 - 场景管理器
上次,我们讲了初始化OGRE,写完以后对自己很不满意,觉得写出来的东西没有什么实质内容,大家学不了什么东西.这次就讲点实际的吧.
首先讲解一点图形学知识.
基本变换
所谓变换,就是指物体的平移,旋转,缩放这几个最基本的操作. 而在3D的世界,这几个操作都是源于矩阵的乘法.(大家会不会问:平移怎么会是乘法呢?明明是加法啊?这个后面讲)
首先来讲讲矩阵的意义吧.
一个物体在一个三维坐标系中有一个固定的位置或者说是坐标 (x,y,z), 这就是一个1*3的矩阵.
平移
那么要使物体的位置发生变化,例如向X方向移动5个单位,实际上只需要简单的执行x+5即可,那么反映在矩阵上就是加上一个平移矩阵
旋转
绕z轴旋转α度后的坐标转换为矩阵乘法:
缩放
缩放实际上就是让每个点的坐标乘以一个拉伸系数,如果把一个平面的四个点都乘以系数,那么体系在平面上的效果就是平面被缩放了
讲完了最基本的三种变化以后,我讲讲变化的合成
例如,我们想让一个物体绕空间中任意轴旋转
那么我们需要做的要分几步:
第一步: 通过平移和旋转建立一个新的坐标轴,使新的坐标系的z轴和任意轴重合.
第二步: 在新的坐标系中,把物体绕新的z轴旋转(实际上就是绕k旋转)
第三步: 通过反向平移和旋转把物体恢复到以前的坐标系.
这个有点不好理解,大家多实践吧.
最开始我讲了在3D游戏中,一个物体往往既要平移,又要旋转等,而大量的矩阵乘法运算会极大的影响系统的速度,所以我们需要把矩阵乘法合并,即我们需要把平移矩阵和旋转缩放矩阵合并成一个矩阵来提高效率.可是我们的平移矩阵和源坐标执行的是加运算,怎么能合并呢?
我们的解决方案是齐次坐标系,把原先的三维矩阵扩展成四位从而实现平移矩阵和源矩阵相乘.
齐次坐标转换:
那么在齐次坐标系下的平移,缩放,旋转分别如下:
平移
缩放:
旋转:
合成三个操作只需要简单的把三个矩阵先乘起来即达到目的.
好,理论就到这里: 来点实际的.
今天我们讲OGRE的场景管理器
从数据管理上理解,场景管理器就是一个存放众多游戏单位的容器.从数据结构上讲,就是一个树的结构.之所以用树状结构,是因为在3D游戏中,对父节点的矩阵变化会应用到子结点.想像一个人在走动,人的身体这个根节点上挂接了手脚,人的平移会带动手脚的平移.
那么我介绍一个OGRE管理器的主要功能吧:
·在场景中创建和放置活动物体、灯光以及摄像机,并维护他们的在场景图中的变换。
·载入和布置世界地图(World geometry,与活动实体不同,世界地图是巨大且可以延伸的,通常情况下是不可移动的,比如一个完整的BSP地图 – 这个概念后面讲到)。
·对场景查询(Scene Queries)的支持,比如回答“在世界的某个原型空间内,都包含了那些物体”。
·剔除不可见物体并且将可见物体放入渲染队列。
·根据当前和渲染物体的透视图,对无方向的光源(Nondirectional Light)进行组织和排序(按由近到远)。
·设置并且渲染场景中的阴影。
·渲染场景中的其他物体,如背景和天空盒
·发送组织好的内容到渲染系统执行渲染
以前我们讲过,OGRE的优势是把场景管理器作为插件的形式载入.所以我们会和很多管理器打交道,但是有人会问,问什么需要很多管理器呢?不就是存游戏单位的容器吗?实际上,一个庞大的3D游戏,例如地牢围攻,即包含了广阔的平原,又包括了室内空间,而渲染这两种场景,需要不同的算法来进行渲染优化.
OGRE提供了两种管理器:
OctreeSceneManager,八叉树
这个以前znnren师兄在版上讲过
TerrainSceneManager
这个我还没有搞懂
这是OGRE场景管理器的树状结构图.
当我们在创建管理器的时候,我们会得到一个总的父节点Root Scene Node,用来挂接我们自己的节点.
讲完了层次关系,我们来讲讲坐标系这个概念:
在OGRE中,我们要和以下几个坐标系打交道:
物体坐标系:
如果你创建了一个物体(不论是通过3D模型工具产生还是手动构造),物体的顶点都会被放置在世界空间中。我们在这里举个例子:我们在这里是用3DSMax工具来进行模型的制作,在编辑场景的原点(0,0,0)建立一个边长为1的立方体,这样他的顶点都在类似(0.5,0.5,0.5)的范围内。我们所用的坐标,都是处在物体坐标系中的.当OGRE载入了这个物体之后,所有顶点的位置仍然何在3DSMax编辑空间内相同。换句话说,一个在3D工具中设置在点(1,1,1)的顶点,在导出到Ogre系统中,这个顶点相对于它挂接的场景节点的位置仍然是(1,1,1)。
当物体被挂接到场景节点上的时候,这个场景节点上的世界空间转换矩阵就会应用到这个物体上面的所有顶点上,从而把物体转换到世界空间的绝对位置,这也是确定物体在3D空间位置、缩放以及方向的原理。事实上这些转换并不是直接施加在物体顶点上面的,所以这些操作也不会影响物体上面所顶点到所挂接场景节点位置的距离。
本地空间
这个概念没什么可说的,只需要注意:对于物体的旋转和缩放来说,“本地空间”的概念就是绕着自己的轴旋转;相对于自己的中心点进行缩放。
父节点空间(Parent Space)
想像地球围着太阳转动吧.太阳就是地球的父节点
世界空间(World Space)
我们的摄像机所在空间就在世界空间中,相信这个概念也很好理解
其他的关于场景管理器的内容我们下次讲解
下面我给出一些代码
这是有Root创建场景管理器的代码,字符串表示创建的管理器类型标示
mSceneMgr = mRoot->createSceneManager(“TerrainSceneManager”);
接下来我们完善这个空的场景
void createScene(void)
{
//设置环境光
mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
// Create a point light 创建点光源
Light* l = mSceneMgr->createLight(“MainLight”);
l->set Position(20,80,50);
//创建一个场景内容(注意我们建立的是内容,不是一个场景节点,因为OGRE的理念是场景 //内容和场景节点分离,从而提高扩展性),读取.mesh文件,上一章讲过mesh,可以理解成一个//素材
Entity * ent = mSceneMgr->createEntity(“head”, “ogrehead.mesh”);
// 设置材质
Ent->setMaterialName(“Examples/EnvMappedRustySteel”);
// 建立一个子场景节点,在该节点上挂接场景内容
mSceneMgr->gerRootSceneNode()->createChildSceneNode()->attachObject(ent);
}
接下来我们从代码上来了解平移变化:
OGRE非常友善的封装了矩阵乘法(实际上从DirectX和OpenGL层面上就已经封装了,只不过我们还是要和矩阵打交道,因为我们没有场景管理器:p),所以你只需要说明你想要平移的单位,例如x方向100个单位,y方向10个单位.下面的代码同样是在场景节点上进行变化,产生的结果是导致挂接在节点上的场景内容发生平移.节点和内容分离万岁
mSceneNode->translate(100.0, 10.0, 0.0);
其他的实例:
注意,TS_PARENT是声明使用的坐标系.顾名思义,PARENT表示使用父节点坐标系.说到这里,让我想起来刚才我们讲的矩阵变化的合成,如果没有场景管理器,你将自己解决所谓的LACAL和WORLD坐标系这些概念.你需要PUSH压栈,POP出栈你的矩阵来实现这一切.
// 对象绕自己的Y轴旋转一弧度,大约57角度
mSceneNode->yaw(Ogre::Radian(1.0));
// 对象绕父节点的X轴旋转一弧度,大约57角度
mSceneNode->pitch(Ogre::Radian(1.0), TS_PARENT);
// 对象绕世界的Z轴旋转一弧度,大约57角度
mSceneNode->roll(Ogre::Radian(1.0),TS_WORLD);
// 在X轴缩放两倍,其他轴不缩放
mSceneNode->scale(2.0, 1.0, 1.0);