转载:OGRE一起学(七)场景节点和实体

第七章 场景节点和实体

示例代码 :

点击下载本节示例代码 

运行截图 : 这个示例很简单,读取并显示一个模型。 Image:Yanchen71.jpg

预备知识 :

OGRE 的场景组织方式,就像一棵树,树有根、有枝干、有叶子和果实。最基本的两个概念,是 场景节点 (SceneNode) 和 实体 (Entity) 。场景节点就像树枝,实体就像枝头的果实。我们可以画个概念图:

场景节点就像根、树干和树枝,它可以再分枝,或者挂上果实(实体); 实体就像果实,它总是被绑定 (Attach) 在一个场景节点上并且总是处于分枝的末端;

场景节点控制实体的位置、方向、缩放等空间属性; 实体具有自己所使用的模型、材质、阴影、骨骼、动画、渲染状态等各种个体属性;

整个场景节点拥有唯一的一个根场景节点(RootSceneNode),如果一个实体不是根场景节点的“后代”,也就是所谓的“游离”实体或被绑定在一个"游离"节点上的实体,它不会被显示。

场景节点类 Ogre:: SceneNode 在头文件 OgreSceneNode.h 中定义,下面是它的关联图表:

点击看大图

实体类 Ogre:: Entity 在头文件 OgreEntity.h 中定义,下面是它的关联图表:

点击看大图

示例解说 :

这个示例的核心代码,在源文件 SceneNodeAndEntity.cpp 的

void SceneNodeAndEntityApplication::createScene( void ) 方法定义中。 
  • (1)
// 设置环境光 
mSceneMgr->setAmbientLight(ColourValue(1.0f, 1.0f, 1.0f)); 

mSceneMgr 是在公用示例基类 OGRE::ExampleApplication 中已经定义好的一个保护成员,作为场景管理器 (SceneManager) 的一个实例来使用。 场景管理器类 Ogre:: SceneManager 在头文件 OgreSceneManager.h 中定义,场景管理器,顾名思义,它是整个 OGRE 场景的总管,管理整个场景中的所有场景节点 (SceneNode) 、实体 (Entity) 、光源 (Light) 、镜头 (Camera) 、材质 (Material) 、阴影 (Shadow) 、公告板 (Billboard) 、动画 (Animation) 、天空 (Sky) 、雾 (Fog) 、盖层 (Overlay) 等等大量元素。下面是它的关联图表:

点击看大图

setAmbientLight() (设置环境光) 的作用是给整个场景设置一个统一的散射光,散射光没有光源,没有方向性,不会在物体表面留下阴影,仅仅是照亮场景。默认的环境光颜色是黑色,所以我们要设置一个较亮的颜色,要不模型看上去漆黑一团。

setAmbientLight() 方法的原型在头文件 OgreSceneManager.h 中定义:

void Ogre::SceneManager:: setAmbientLight ( const ColourValue & colour ) 

其中的 ColourValue (颜色值)是 OGRE 颜色类,在头文件 OgreColourValue.h 中定义:

ColourValue (Real red=1.0f, Real green=1.0f, Real blue=1.0f, Real alpha=1.0f) 

除了直接用 RGBA 值来表示颜色, ColourValue 还具有几个预先设定好的颜色值:

ColourValue Black = ColourValue(0.0,0.0,0.0) 

ColourValue White = ColourValue(1.0,1.0,1.0) 

ColourValue Red = ColourValue(1.0,0.0,0.0) 

ColourValue Green = ColourValue(0.0,1.0,0.0) 

ColourValue Blue = ColourValue(0.0,0.0,1.0) 



// 设置环境光 

mSceneMgr->setAmbientLight(ColourValue(1.0f, 1.0f, 1.0f)); 

现在你可以试着为 ColourValue 更换不同的颜色值来看看实际效果。

  • (2)
// 获取场景根节点 

SceneNode* rootNode = mSceneMgr->getRootSceneNode(); 

getRootSceneNode() (获取根节点) 的作用是获取并返回当前场景的根节点的对象指针,它作为 SceneManager 类的一个成员函数:

SceneNode * Ogre::SceneManager:: getRootSceneNode ( void ) const [virtual] 
  • (3)
// 创建模型实体 

Entity* entObject = mSceneMgr->createEntity("object", "ogrehead.mesh"); 

createEntity() (创建实体) 在当前场景中创建一个实体实例并返回它的对象指针,作为 SceneManager 类的一个成员函数,它有两个重载:

Entity * Ogre::SceneManager::createEntity  (

  const String &  entityName,      // 实体名称(同一场景中不能有相同的实体名称)

  PrefabType  ptype                // 预制类型(不需要读取模型,直接在程序中创建简单几何体,

                                  // 目前只有平面 PT_PLANE 一种预制类型)

)  [virtual] 



Entity * Ogre::SceneManager::createEntity  ( 

 const String &  entityName,      // 实体名称(同一场景中不能有相同的实体名称)

  const String &  meshName         // 模型名称(需要从硬盘上读取的模型的文件名)

)  [virtual] 

这里用的是第二个重载,也就是从硬盘上读取模型,模型文件名 "ogrehead.mesh" ,这个文件在 OGRE\Samples\Media\models 目录下。查看一下这个目录,里面有一些 *.mesh 文件,还有一些 *.skeleton 文件 。

  • .mesh 文件包含了静态模型和材质的信息,*.skeleton 文件对应一个同名的 *.mesh 文件,保存这个模型的骨骼和动画信息(如果有)。使用 createEntity() 方法,不管是不是带骨骼带动画的 *.mesh ,都一样读取,但是要想播放模型的动画,还需要做一些别的工作,如果现在你直接读取 ninja.mesh 这个带骨骼动画的模型,它不会动。

到了这里,还有一个问题,就是 OGRE 是怎么找到的这个 *.mesh 文件?它怎么知道这个 *.mesh 文件是放在 OGRE\Samples\Media\models 目录下的?还有我们在示例中看到的模型是带纹理贴图的,那么纹理贴图都在哪里呢? OGRE 又是怎么找到这个模型需要的纹理贴图的呢?

在 E:\Desktop\Learning\OGRE\Samples\Common\bin 目录、还有这个目录的 Debug 和 Release 两个子目录下,存在着一系列的 *.cfg 文件,它们都是些配置文件, OGRE 程序在打开以后,第一件事情就是检查并读取这些配置文件,从中了解一些关键信息。其中的 resources.cfg 就是用来指定所有的游戏资源所在的目录路径, OGRE 要读取一些资源,就会从这些路径中搜索。

resources.cfg 文件的内容: 

FileSystem=http://www.cnblogs.com/../Media

FileSystem=http://www.cnblogs.com/../Media/fonts                   // 字体

FileSystem=http://www.cnblogs.com/../Media/materials/programs      // 材质程序 (CG、HLSH、GLSL 等)

FileSystem=http://www.cnblogs.com/../Media/materials/scripts       // 材质定义脚本

FileSystem=http://www.cnblogs.com/../Media/materials/textures      // 纹理贴图

FileSystem=http://www.cnblogs.com/../Media/models                  // 模型

FileSystem=http://www.cnblogs.com/../Media/overlays                // 盖层(界面)定义脚本

FileSystem=http://www.cnblogs.com/../Media/particle                // 粒子定义脚本

Zip=http://www.cnblogs.com/../Media/packs/cubemap.zip

Zip=http://www.cnblogs.com/../Media/packs/cubemapsJS.zip

Zip=http://www.cnblogs.com/../Media/packs/dragon.zip

Zip=http://www.cnblogs.com/../Media/packs/fresneldemo.zip

Zip=http://www.cnblogs.com/../Media/packs/OgreCore.zip

Zip=http://www.cnblogs.com/../Media/packs/ogretestmap.zip

Zip=http://www.cnblogs.com/../Media/packs/skybox.zip

你可能会留意到每一条语句前面有 FileSystem 和 Zip 的区别,查看一下 OGRE\Samples\Media\packs 里面的那些 *.zip 文件,用 WinRAR 把它们打开来看,比方说打开 dragon.zip ,可以看到里面有这样几个文件:

dragon.mesh 
body.jpg 
head4.jpg 
legs.jpg 

一个模型,带三张贴图,就是这么简单。 这个意味着,OGRE 在搜索所需资源的时候,不但能搜索系统目录 (FileSystem) ,还能在压缩文件 (Zip) 中搜索。

最后是模型的纹理贴图,这个在 *.mesh 文件自身中定义,我们在使用 3dsmax 、 Maya 等输出 *.mesh 模型的同时,纹理贴图的相对路径也会被同时包含输出。

// 创建模型实体 
Entity* entObject = mSceneMgr->createEntity("object", "ogrehead.mesh"); 

现在你可以试着让它读取不同的模型,就把这个示例当作一个模型浏览器来用吧 ,几个 *.zip 文件里的资源也试试,比方说,读取 "dragon.mesh" 。

  • (4)
// 在场景根节点下创建一个子节点用于绑定这个模型实体 
SceneNode* objectNode = rootNode->createChildSceneNode(); 

createChildSceneNode() (创建子场景节点) 为当前节点创建一个子节点并返回它的对象指针,作为 SceneNode 类的成员函数,它也有两个重载:

SceneNode * Ogre::SceneNode::createChildSceneNode  (

 const Vector3 &  translate = Vector3::ZERO,           // 移动向量(相对于父节点)

 const Quaternion &  rotate = Quaternion::IDENTITY     // 旋转向量(相对于父节点)

)  [virtual] 



SceneNode * Ogre::SceneNode::createChildSceneNode  (

 const String &  name,                                 // 场景节点名称(同一场景中不能有相同的节点名称)

 const Vector3 &  translate = Vector3::ZERO,           // 移动向量(相对于父节点)

 const Quaternion &  rotate = Quaternion::IDENTITY     // 旋转向量(相对于父节点)

)  [virtual] 

这里采用的是第一个重载,创建了一个“无名节点”,并且接受了默认的初始化参数:零位移、零旋转。

其中的 Vector3 (三维向量) 是 OGRE 向量类,在头文件 OgreVector3.h 中定义,有若干重载:

 Vector3 (Real fX, Real fY, Real fZ) 

 Vector3 (Real afCoordinate[3]) 

 Vector3 (int afCoordinate[3]) 

 Vector3 (const Real *const r) 

 Vector3 (const Vector3 &rkVector) 

和颜色类 ColourValue 一样它还有一些预置三维向量:

   const Vector3 Vector3::ZERO( 0, 0, 0 );

   const Vector3 Vector3::UNIT_X( 1, 0, 0 );

   const Vector3 Vector3::UNIT_Y( 0, 1, 0 );

   const Vector3 Vector3::UNIT_Z( 0, 0, 1 );

   const Vector3 Vector3::NEGATIVE_UNIT_X( -1,  0,  0 );

   const Vector3 Vector3::NEGATIVE_UNIT_Y(  0, -1,  0 );

   const Vector3 Vector3::NEGATIVE_UNIT_Z(  0,  0, -1 );

   const Vector3 Vector3::UNIT_SCALE(1, 1, 1);

还有 Quaternion (四元数) ,是 OGRE 的四元数类,在头文件 OgreQuaternion.h 中定义,也有若干重载:

 Quaternion (Real fW=1.0, Real fX=0.0, Real fY=0.0, Real fZ=0.0) 

 Quaternion (const Quaternion &rkQ) 

 Quaternion (const Matrix3 &rot)     // 由旋转矩阵构成的四元数

  Quaternion (const Radian &rfAngle, const Vector3 &rkAxis)     // 由 角-轴 对构成的四元数

  Quaternion (const Vector3 &xAxis, const Vector3 &yAxis, const Vector3 &zAxis)     // 由三个正交轴构成的四元数

  Quaternion (Vector3 *akAxis)        // 由三个正交轴构成的四元数

它也有两个预置四元数:

   const Quaternion Quaternion::ZERO(0.0,0.0,0.0,0.0);

   const Quaternion Quaternion::IDENTITY(1.0,0.0,0.0,0.0);
   // 在场景根节点下创建一个子节点用于绑定这个模型实体

   SceneNode* objectNode = rootNode->createChildSceneNode();

现在你可以给 createChildSceneNode() 试试各种不同的参数。但是因为没有参照物,只有一个模型,现在我们还不能明显地看到这些参数的影响,学完本章你可以试着多放置几个模型。

  • (5)
// 把模型实体绑定到这个子节点 objectNode->attachObject(entObject); 
attachObject (绑定对象) 绑定实体到场景节点,作为 SceneNode 类的成员函数: 
void Ogre::SceneNode:: attachObject ( MovableObject * obj ) [virtual] 

其中, MovableObject 是一个包含了 Entity 的大类, 我们看它的世系图谱,可以看到 Entity 也是它的一个继承类,包括公告板、光源、镜头视锥、可移动面、风景、地形等等都是 MovableObject 的继承类:

最后,如果觉得程序中镜头移动太快或太慢,请参照 OGRE 一起学 (6) —— 最简单的游戏窗口代码 ,修改 OGRE\Samples\Common\include\ ExampleFrameListener.h :

mMoveSpeed = 500; // 镜头移动速度 

建议 100 。

posted @ 2009-06-08 13:18  回忆1919  阅读(3247)  评论(0编辑  收藏  举报