OGRE学习系列三:基础教程1 你的第一个场景

来源:互联网 发布:linux 修改文件时间戳 编辑:程序博客网 时间:2024/06/11 04:14

本文翻译自官网基础教程一,由于本人英文水平有限,翻译出错难以避免,因此英文水平较高者可直接查看英文原文。

教程介绍:

        第一节教程将包含构建OGRE场景的一些基础要素。首先需要关注的就是SceneManager,SceneNode,和Entity。一个实体(Enitity)就是以三维网格表示的任何东西。一个场景节点(SceneNode)用来连接目标到场景中,场景管理器(SceneManager)组织管理所有的内容,它跟踪场景中的实体和节点,并决定如何显示他们。

        我们从解释OGRE中的一些基本概念开始。别着急,第一节教程比其余教程多一些概念解释,一旦你开始后续的教程,就变得更快了。我们将构建足够多的东西,我们只是需要先打一下基础,我们才能够在后续的学习中立足于此。

        这部教程中的全部源文件都在这里。

     在学习这篇教程的过程中,无论你遇到什么问题,都可以Po到帮助版块。

//===============================================================

一、预备知识

        本节教程假设你已经知道如何配置OGRE工程,并已经成功编译通过。如果在这方面需要帮助,请阅读Setting Up An Application。

        

   本节内容目录列表:

    1、预备知识

    2、OGRE是如何工作的

           2.1、场景管理器

           2.2、场景节点

           2.3、实体

     3、构建场景

     4、坐标系统

     5、添加另一个实体

     6、更多实体

     7、更多场景节点

     8、改变一个实体的尺度

     9、旋转一个实体

     10、OGRE环境

            10.1、依赖库和插件

                     10.1.1、主要依赖库

                     10.1.2、插件

                     10.1.3、第三方插件

                     10.1.4、测试VS release

             10.2、配置文件

                     10.2.1、插件配置

                     10.2.2、资源配置

                     10.2.3、媒体配置

                     10.2.4、OGRE配置

                     10.2.5、Quake 3设置配置

     11、总结

     12、下一节

//====================================================================================

二、OGRE是如何工作的

      下面为OGRE场景的一些基本要素做出简单介绍。

     1)场景管理器(SceneManager)

        出现在屏幕上的一切内容都由SceneManager进行管理。SceneManager追踪屏幕中的物体的位置和一些其他属性。SceneManager同时也管理你添加到场景中的任何相机。SceneManager有多种类型,有些管理器关注于渲染地形,一些其他的管理器专注于渲染BSP地图。不同类型的场景管理器(SceneManager)可以在这里查看。

     2)场景节点(SceneNode)

        场景节点保存连接到这个节点上的所有物体的信息。一个你场景中的实体,只有连接到场景节点(SceneNode)中之后才会被渲染。另外,在你的场景中,场景节点并不是可见的物体,它仅仅包含一些简要信息,如位置和方向。仅仅当它被连接到某种物体上时,如一个实体,这些信息才会被用来在场景中渲染一个真正的物体。

         场景节点(SceneNodes)可以连接多个物体,也许我们想要一个光源在场景中跟随着一个角色。为了做到这一点,我们可以同时将角色实体和光源连接在同一个场景节点中,这样会使他们共享同一份相同的位置信息。我们甚至可以将一个场景节点连接在另一个场景节点上,这种做法在许多情况下非常有用。想象一下,你想在一个角色的手中放置一个工具,你不会想把这个工具连接在整个角色的场景节点上。然而,你可以使用一个场景节点代表他们的手,然后把这个场景节点连接到角色的主要场景节点上,然后连接工具实体到这个”子“场景节点。更多复杂的场景节点应用将会在后续内容中介绍。

        最后要记得场景节点的位置通常与他们的父节点相关,而且每一个场景管理器创建一个根节点,所有其他场景节点都与此根节点相连接。

     3)实体(Enitity)

        实体是一种类型的你可以在场景中进行渲染的物体。它可是3D 网格代表的任何物体,甚至地形目标也是巨大的实体。但是,如光线、广告牌、微粒、相机等场景要素并非实体。OGRE使用了一种众所周知的设计模型,这种模型分离了渲染目标的信息,比如位置信息。这意味着你并不不用直接在场景中防止实体。而是,放置一个场景节点在场景中,然后在这个节点上连接一个实体。随后使用场景节点上存储的各种信息来渲染这个实体。



三、构建场景

        终于可以在我们的场景中构建物体了,首先我们要做的就是打开灯光,添加下列代码到TutorialApplication::createScene:

        mSceneMgr->setAmbientLight(Ogre::ColorValue(0.5,0.5,0.5));

        此处,setAmbientLight方法需要一个Ogre::ColorValue,这三个值分别代表颜色空间三通道中的红、绿和蓝。他们的范围是0到1.

        此处,mSceneMgr是一个变量,定义在BaseApplication中,其中有很多变量,如mCamera,继承自BaseApplication。后面用到他们的时候我们再进行介绍。

        我们要做的下一件事就是让SceneManager创建一个实体。

        Ogre::Entity* ogreEntity=mSceneMgr->createEntity("ogrehead.mesh");

        传入此函数的参数必须是一个可以由Ogre资源管理器加载的Mesh。目前,资源加载是BaseApplication为我们管理的众多内容之一。后续教程里会进行解释。

        现在我们有了一个实体,我们需要创建一个场景节点,这样才能让这个实体在我们的场景中显示出来,每一个场景管理器都有一个根节点,这个根节点有一个方法叫做createChildSceneNode,这个方法可以返回一个新的连接在根节点上的场景节点。老版本的OGRE中,你会被要求为你的实体和场景节点提供一个唯一的名字。现在这个是可选项,如果你不提供名称,OGRE会自动生成。

        Ogre::SceneNode* ogreNode=mSceneMgr->getRootSceneNode()->createChildSceneNode();

        我们保存了createChildSceneNode()方法返回的场景节点指针,因此我们可以将它与我们的实体连接。

        ogreNode->attachObject(ogreEntity);

        灯光在下一节教程中会被详细提及,此处我们依然会添加一个简单的灯光到这个场景中,新的灯光目标依然可以从场景管理器中请求得到,在灯光被创建时,我们给它一个唯一的名字。

        Ogre::Light* light=mSceneMgr->createLight("MainLight");

        一旦灯光被创建,我们便设置它的位置,三参数是放置灯光位置信息的x,y和z坐标。

        light->setPosition(20,80,50);

         我们现在构建了一个基本的场景,编译和运行你的程序,你应该可以在你的屏幕中看到一个怪物的头。这只是一个开始........

         



四、坐标系统

        在我们继续之前,我们先看一下Ogre的一些基本的坐标系统。OGRE,与众多其他的图形图像引擎一样,使用x-z平面作为场景的”地板“。这意味着y轴是垂直坐标,用以确定Ogre使用的是右手坐标系统。

       

             图中,x轴从左侧的负值开始,向右不断增加(通过原点处的0值)。z轴表示前方和后方。z轴的正方向指示”屏幕外侧“。所以说,如果一个角色朝着屏幕方向走来,z值应该是增加的,最后,y轴表示从下到上,”低于地面“处值为负。不要从字面上理解这些意思,其实你可以把任何一个平面设置成地面,

这只是为了让你自己在场景中确定方向。

            当你运行你的程序时,请注意你的Ogre头部是如何面向相机的,看到z轴的正方向。这是Mesh自身和相机定向的一个属性。相机在后续教程中会介绍到,这个Orge的头处在我们师姐的原点(0,0,0)。头的默认朝向是它最初被建成模型时的朝向。你也可以高效的在Ogre中改变它。但是这需要一些四元数的知识,四元数直到中级教程Intermediate Tutorials中才会被提到。

            Ogre使用一个向量类来表示位置和方向。这是被定义为2-4维的向量。他们被成为Vector2,Vector3,以及Vector4。Vector3是目前使用最普遍的。如果你对向量的含义还不熟悉,强烈建议你在学习这一系列教程之前先去补充一下相关知识。即使Ogre相比较一些较为复杂的OpenGL和DirectX来说相对简单,但是掌握一些基本的数学概念还是必不可少的。如果你想在3D渲染方面更进一步,那么向量和一些基本的线性算法将是一些你可以掌握的十分有用的内容。这个页面提供了一些比较好的运用在游戏编程中的向量方面的基础知识。



五、添加另一个实体

        现在回归代码,对于第一个实体,我们没有指定它的位置。Ogre的许多函数都有默认的参数。其中,SceneNode::createChildSceneNode函数可以传入三个参数,但是我们以无参的形式调用了它。这些参数分别是场景节点创建时的名称、位置和旋转角度。我们前面已经提到Ogre为我们生成一个独一无二的名称。也会使用(0,0,0)作为默认的位置。

         第一、我们先移动相机,这样我们就可以适应屏幕上的更多实体,在创建场景中设置环境光之后,正确放置这个调用。

         mCamera->setPosition(0,47,222);

         现在,我们创建另一个实体和场景节点,但是这次我们给它一个新的位置。

         Ogre::Entity* ogreEntity2=mSceneMgr->createEntity("ogrehead.mesh");

         Ogre::SceneNode* ogreNode2=mSceneMgr->getRootSceneNode()->createChildSceneNode(Ogre::Vector3(84,48,0));

         ogreNode2->attachObject(ogreEntity2);

         这与我们第一次做的一样,除了现在我们提供了一个Vector3给我们的createChildSceneNode函数。这会取代默认位置,记得,场景节点的位置一直与它的父节点相关。这种情况下,父节点是根场景节点,根场景节点的位置默认为是(0,0,0);

         编译运行你的程序,你屏幕中的怪物头像此时应该有一个小伙伴。

        




六、更多实体

        Entity类内容非常多,我们现在仅仅多介绍一点非常有用的方法。Entity类拥有setVisible和isVisible方法。如果你想隐藏一个实体,但是你一会又需要用它,你可以使用这个函数替代销毁该实体,而后再重新渲染。

       笔记:实体并不需要被堆积起来就像他们在一些图像引擎中,仅仅一次复制每一个已经载入内存的Mesh和纹理即可,所以试图最小化实体数量并不能节省大量的内存空间。

        getName函数返回实体的名称,getParentSceneNode函数返回实体连接的负场景节点。在我们的这种情况下,父场景节点便是根场景节点。



七、更多场景节点

        SceneNode类非常复杂,现在, 我们将仅仅提到一些最有用的函数。

        在创建节点之后,你可以使用setPosition函数设置位置,这依然与其父节点相关,你也可以使用translate移动目标(相对于当前位置)。

        场景节点(SceneNodes)可以用来设置除位置外的更多参数,也可以用来管理物体的尺度和旋转。你可以使用setScale设置一个物体的尺度,你也可以使用yaw、pitch和roll来设置物体的方位。你可以使用resetRotation函数来返回物体的默认方位。最后,你可以使用rotate来执行更复杂的旋转,这也会涉及到四元数(中级教程里会有)。

         我们已经使用了SceneNode类中的attachObject方法,也有一些方法可以用来处理与场景节点连接的物体。你可以使用numAttachedObjects来获得该节点上连接的目标数目。你也可以使用众多getAttachedObject版本中的一种返回场景节点中的一个子节点。detachObject函数可以用来移除特定的子节点,detachAllObjects可以用来移除所有节点。

          既然子节点的位置与父节点相关,这就使得同时移动多组节点更加容易。例如:如果我们改变了这一行:

          Ogre::SceneNode* ogreNode2=mSceneMgr->getRootSceneNode()->createChildSceneNode(Ogre::Vector3(84,48,0));

         改成这样:

         Ogre::SceneNode* ogreNode2=ogreNode->createChildSceneNode(Ogre::Vector3(84,48,0));

         这样我们的新节点就直接以我们创建的第一个实体作为父节点。这意味着,移动ogreNode的同时也移动了ogreNode2.这也意味着ogre2的位置也与ogreNode相关。

         如果你对相对位置的含义不理解,那么举个栗子也许会有帮助。我们说,我们把第一个节点ogreNode放置在(10,10,10)的位置上,并且将ogreNode2直接连接在ogreNode上,然后我们设置ogreNode的位置为(-10,-10,-10).为了弄清ogreNode2将会展示在什么地方,我们加上这个位置坐标到它的父节点。

         (10,10,10)+(-10,-10,-10)=(0,0,0)

             ogreNode                  ogreNode2

             parent                          child

          这意味着ogreNode2将会被防止在(0,0,0)的位置,即使我们设置了他的位置为(-10,-10,-10).如果我们将它连接在根场景节点上,它会被展示在(-10,-10,-10)的位置,因为:

         (0,0,0)+(-10,-10,-10)=(-10,-10,-10

             root                     ogreNode2

             parent                          child

          花几秒钟时间消化一下这点内容。相对关系比较难理解,这也是我们为什么举这个例子帮助大家理解。

         最后,你可以通过调用getSceneNode或者调用getEntity来获得一个场景节点或者实体。这些是场景管理器(SceneManager)的函数。你不用为每一个场景节点都存储一个指针变量,你通常定义一个指针变量存储你常用的节点的指针。


八、改变实体的尺度

        我们可以通过调用setScale设置实体的尺度。这个方法允许我们为每一个维度提供一个尺度因子。我们添加另外一个怪物头,给它一个不同的展示尺度。我们也将它放置在一个屏幕闪的合适的位置。

         Ogre::Entity* ogreEntity3=mSceneMgr->createEntity("ogrehead.mesh");

         Ogre::SceneNode* ogreNode3=mSceneMgr->getRootSceneNode()->createChildSceneNode();

         ogreNode3->setPosition(0,104,0);

         ogreNode3->setScale(2,1.2,1);

         ogreNode3->attachObject(ogreEntity3);

         编译运行你的应用,你应该可以看到一个胖胖的怪物头部在上面。




九、旋转一个实体

       一个实体的旋转可以通过使用yaw、pitch和roll方法来实现

      

    这些方法需要传入一个Ogre::Degree或者Ogre::Radian变量。正如图像中展示,绕y轴旋转调用yaw,绕x轴旋转调用pitch,绕z轴旋转调用roll。这些通常用来描述飞行器的移动状态。

   有一个比较著名的小技巧去记住绕轴正向旋转的方向,称为右手法则。把你右手的大拇指指向坐标轴方向,则你的其余手指弯曲的方向就是正方向。你现在也可以看到为什么它被成为右手坐标系统。

    现在,让我们把这个用在我们的场景中放置一个旋转实体上。我们将它放置好:

    Ogre::Entity* ogreEntity4 = mSceneMgr->createEntity("ogrehead.mesh");

    Ogre::SceneNode* ogreNode4=mSceneMgr->getRootSceneNode()->createChildSceneNode();

    ogreNode4->setPosition(-84,48,0);

    ogreNode4->roll(Ogre::Degree(-90));

    ogreNode4->attachObject(ogreEntity4);

    编译运行你的程序,你会有一个旋转的怪物头在场景中。




十、Ogre环境

        Ogre的依赖库和配置文件可以在你的OgreSDK文件夹中的”bin“中找到,你在debug模式下编译你的应用程序时,需要用到debug文件。

        1)依赖库和插件

               Ogre被分为三个共享依赖库组:main library,plugins以及third-party libraries

              (一)主要依赖库(main library)

                         主要依赖库组包含Ogre依赖库自身和它依赖的共享依赖库。Ogre依赖库包含文件之一是OgreMain.dll或者libOgreMain。因此,它依赖于你的平台,这个依赖库必须包含于你所有的Ogre应用程序。OgreMain.dll要求一些其他的依赖库如:cg.dll

              (二)插件(plugins)

                         第二个共享数据库组是插件组。Ogre增加了一些功能在共享依赖库中,因此可以使它被打开或关闭更加容易。包含Ogre的核心插件在命名时以”Plugin_“开始,你也可以写你自己的插件。

                         Ogre也在不同的渲染系统(如:OpenGL、DirectX等)中使用插件。这些插件名以”RenderSystem_“开始。因此,你也可以仅仅添加你需要的的系统,如果你写的渲染器依赖特定的系统,这将非常有用。因为为了程序不出现兼容错误,你可以简单的移除不兼容的系统。这也意味着你可以写你自己的插件如果你想扩展Ogre到另一个渲染系统。

               (三)第三方插件(Thirty-party Plugins)

                          上一个主要的组包含了第三方库和一些其他的普通支持库。Ogre专注于作为图形渲染库。这个组使得整合其他库添加一些如物理、输入以及GUI系统更加容易。这些库共同用来组成一个完成的游戏开发环境。你也许会发现这些零碎的方法有点奇怪,但是这在大型软件工程中是一个非常常见的设计模式。首先它非常难以理解,但当你开始创建复杂场景时,会发现它是一个非常灵活的方法。

                          Ogre示例以及SDK包含了一些这样的第三方库。Open Input System被用来管理输入的事件以及分配他们到Ogre。这被包含在OIS.dll或者libOIS.so中。你也可以使用Cg,它是通过CgProgramManager来使用。这些库允许你按照管理渲染材料。也有一些其他库(不包含Ogre)提供一些功能,如声音(sound)和动作(physics)。

                (四)测试VS Release

                          当你创建了应用程序你可以使所有的插件都保持活跃。这允许你测试这些插件。但是当你准备发布一个release版本,你会想要关闭你没有用到的插件的活性。

               2):配置文件

                        Ogre使用了一些配置文件。他们控制事物比如载入插件以及你的应用程序从哪里搜索资源文件。我们将简单介绍一下这些文件。你需要仔细阅读下面的内容。

                      (一)插件配置(Plugin Configuration)

                                plugins.cfg

                                这个文件告诉Ogre加载哪个插件。当你想加载一个不同的插件组,就修改这个文件。通常我们注释掉不用的行,而不是删除他们,因为你永远不知道当你想重新加载一个不用的插件时,该如何表达。下面是一些示例:

                                 #Plugin=RenderSystem_Direct3D9

                                 #Plugin=RenderSystem_Direct3D10

                                 #Plugin=RenderSystem_Direct3D11

                                 Plugin=RenderSystem_GL

                                我们注释掉了三个DirectX系统,使用了OpenGL。在windows系统中,你可以将这个颠倒一下。你可以看到为什么不删除未用到的行也许是有帮助的,因为你必须试图记起渲染系统是RenderSystem_GL还是RenderSystem_OpenGL。

                                你也可以通过改变”PluginFolder“变量来决定Ogre在哪里查找插件。你可以使用绝对路径也可以使用相对路径。但是你不能使用像$(OGRE_HOME)这样的环境变量。例如:如果你需要在Linux系统中从源文件中构建一个Ogre项目,你将需要一行像这样的代码在你的文件开始位置:

                                PluginFolder=/usr/local/lib/OGRE

                               默认情况下,OGRE将会在”/usr/lib/OGRE“中找到,这是它默认放置的地方如果你从package manager中安装了Ogre。

                        (二)资源配置

                                resource.cfg

                                这个文件包含了一列Ogre用来查找资源的路径。资源包括脚本、Mesh,纹理,GUI 层和一些其他内容。你也可以使用绝对路径或者相对路径。但是你依然不能使用环境变量。Ogre不会查找子文件夹,所以你必须人工添加他们。示例如下:

                               [General]

                               FileSystem=../media

       FileSystem=../media/materials/scripts

       FileSystem=../media/materials/textures

       FileSystem=../media/materials/models

                               这是一个使用的相对路径的示例,子文件夹也需要列出来。包含”../media“路径不会自动包含”../media/models“路径。这也是Ogre不会贪心以及不会浪费时间加载一些不需要的资源。

                           (三)媒体配置

                               media.cfg

                               这个文件为Ogre提供了更多的关于资源的细节信息。也未必会让你花费很长的时间去修改这个文件。更多信息可以在Ogre手册中找到。

                            (四)Ogre配置

                              ogre.cfg

                              这个文件由你运行程序时出现的渲染设置对话框生成。这个文件代表着你自己的设置。不要把这个文件与你的应用分开。这个文件会包含你的选择比如屏幕分辨率。不要直接修改这个文件。通过对话框修改设置,这个文件就会自动更新。

                              (五)Quake3 设置配置

                              quake3settings.cfg

                              这个文件是被BSPSceneManager使用的。只有当你使用这个场景管理器的时候才会用到这个配置文件。这个文件也不应该跟你的应用程序分开。

                              它包含所有的Ogre直接操作的配置文件。Ogre将在相同路径下查找这些文件作为可执行文件,以及它必须正确的找到”Plugins.cfg“,"resources.cfg"以及”media.cfg“。后面的教程会提到更多他们的用法。

十一、总结

           你现在应该对构建Ogre场景有了一个基本的了解。这篇教程提到了Ogre中三种最重要的Object:Entity,SceneNode,SceneManager。这些Objects允许我们渲染和操作一个包含3d目标的场景文件。

           一个代表任何事物的实体(Entity)有一个Ogre Mesh。一个场景节点(SceneNode)被用来保存属性,比如位置,尺度,旋转。它也是一个连接场景中其他实体的锚点并且允许他们在屏幕上被渲染。最后,场景管理器(SceneManager)是一个Object可以整合所有内容。它有一些函数允许你创建实体和场景节点并且把他们组织成一个复杂的场景。


十二、下一节

        基础教程二

0 0
原创粉丝点击