注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Silence的博客

大师只有一个

 
 
 

日志

 
 

引用 2010年05月21  

2010-07-13 20:10:42|  分类: 技术 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
本文转载自wodejiawww《2010年05月21》

 

引用

wodejiawww2010年05月21

Ogre的组成及核心对象

Ogre(O-O graphic rendering engine)是一个图形渲染引擎,主要负责游戏引擎中的渲染,如下图所示:

Ogre实现了由红色实线所包含的模块。它的核心对象如下图所示:

       Root:整个Ogre系统的入口点,它必须第一个被创建,最后一个被消毁。通过Root对象你可以配置系统,还可以获得系统内的其它对象。

       RenderSystem:3D API的抽象层,它负责设置所有的渲染属性,并调用3D API执行渲染操作。

       SceneManager:场景管理器,它负责组织组织场景,包括场景中Material、Light、Movable Object(Entity)和场景本身。

       Material:定义场景中几何体的表面属性。

       Entity:场景中的可运动物体。

       SceneNode:代表位置和方向,Attach到SceneNode上的Entity可以继承其位置和方向。场景中的SceneNode以树的形式来组织。

       Camera:场景中的视点。

支持模块

STL

字符串处理与脚本语言设计基础

       为了允许DDL导出,Ogre将STL的string类做了包装,如下图所示:

       String类较之std::string,提供了一些辅助函数,如实现将字符串中的字符转换成大写/小写、整理字符串间的空格等。

       通过操作字符串可以实现功能强大的脚本语言,关于脚本引擎,请参考文章<<实现一个脚本引擎>>。Ogre语言提供了一系列以String、StringVector为基础的类,从而方便实现脚本语言。这些类的关系如下图所示:

       Ogre允许脚本使用者定义自反风格(reflection-style)的关键字集合。脚本语言用起来什么样呢?请看下面这句Material脚本代码:

       particle_width  30

       Ogre会自动解析这行代码,然后在内部调用ParticleSystem的成员函数setDefaultWidth (),来设置粒子的宽度。很酷吧,这样的效果是怎么实现的呢?下面就让我们逐个分析这几个类。

ParameterDef类与ParamCommand类

       ParameterDef类描述了一个关键字。

       包括关键字的名字,描述以及关键字后面参数的类型。

       ParamCommand类是一个抽象类,负责将关键字与Ogre内部的函数联系起来。

       它提供了两个抽象函数,ParamCommand的派生类实现这两个函数。doSet调用与关键字相关联的函数,设置某个参数。在刚才的例子里,doSet会调用与particle_width相关联的函数setDefaultWidth。doGet返回某个与关键字相关的参数值。上图所示的三个派生类分别用来设置或返回角度、颜色、颜色范围的起始值。

       现在需要将ParameterDef与ParamCommand关联起来,ParamDictionary类满足了这个需求。

      

ParamDictionary类

       ParamDictionary类将ParameterDef与ParamCommand类关联起来,为一个类维护了和这个类相关的命令列表(关键字与参数类型等),如下图所示:

      

void addParameter(const ParameterDef& paramDef, ParamCommand* paramCmd);

此函数可以将新的关键字加入到字典中。

const ParameterList& getParameters(void);

此函数返回这个字典所有关键字定义的索引。

 

StringInterface类

       StringInterface类提供了对外接口,来实现自反风格(reflection-style)的关键字集合。

       所有想维护自己命令列表(关键字与参数类型等)的类必须从StringInterface类派生,派生类通过它提供的接口,可以为自己创建关键字字典、创建关键字。如上图所示,与粒子系统相关的类(ParticleAffector、ParticleEmitter、BillboardSet)和与图形用户接口相关的类(GuiElemnet)都是从StringInterface派生出来的。粒子系统脚本语言与图形用户接口脚本语言的实现细节我们放到以后讲。

现在先分析StringInterface的数据成员:

       1,msDictionary

       typedef std::map<String, ParamDictionary> ParamDictionaryMap;

static ParamDictionaryMap msDictionary;

这是一个关键字字典列表,类型是由类名和ParamDictionary组成的Map。由于一个ParamDictionary对象维护了一个类的所有关键字,所以StringInterface通过msDictionary维护了多个类的关键字。另外,这个数据成员是静态的,这意味着所有的StringInterface对象共用一个字典列表。

2,mParamDictName

String mParamDictName;

当前类的关键字字典名。

 

StringInterface类提供了接口createParamDictionary()来创建关键字字典:

bool createParamDictionary(const String& className);

注意这个类是受保护的(protected),StringInterface的派生类应该在构造函数里调用这个函数来创建字典。

SetParameter、getParameter分别用来设置和得到一个命令。

 

Log

 

Exception

Math

Dynamic loading plugin system

Archives

DataChunk

       DataChunk类,代表一个内存块。封装了内存块的大小、指向内存块的指针等属性。并为DataChunk提供了类似于文件的读写操作。如果你想释放DataChunk所代表的内存块,需要调用clear()成员函数。

       SDDataChunk类,DataChunk类的子类。当SDDataChunk类的对象被删除后,该对象所代表的内存块也被释放。SD是Self-deleted的缩写。

    class _OgreExport DataChunk

    {

    protected:

           uchar* mData;              // 指向内存块起始位置的指针

           uchar* mPos;        // 指向内存块当前位置的指针

           uchar* mEnd;        // 指向内存块结尾位置的指针

           size_t mSize;          // 内存块的大小

 

    public:

              // 分配size大小的内存,并根据传入的指针初始化该内存块。

           uchar * allocate( size_t size, const uchar * ptr = NULL );

              // 释放内存块的空间。

           DataChunk & clear();

              // 得到内存块大小

           size_t getSize() const;   

              // 返回指向内存块起始位置的指针

           uchar * getPtr();

 

           // 从内存块的当前位置处读取size大小的数据到另一内存块中。

           ulong read(void* buffer, unsigned long size);

 

           // 重新设定当前位置mPos,pos为距离内存起始处的位置。

           DataChunk & seek( size_t pos );

 

           // 将mPos向前或向后移动。Offset为偏移量。

           DataChunk & skip( long offset );

 

// 将内存块中的数据读入到另一块内存中,直到遇到中止字符串或达到规定数据量上限时为止。Buffer代表目标内存、size为数据量上限、delim为中止字符串。

           unsigned long readUpTo(

                  void* buffer,

                  size_t size,

                  const char* delim = "\n" );

 

        // 向后移动,直到遇到中止字符串或到达内存块末尾为止。

        unsigned long skipUpTo( const char* delim );

 

           bool isEOF();

 

// 返回一行数据。如果TrimAfter为true,则整理该行数据的空格。这个函数只是用于文本文件。

           String getLine( bool trimAfter = true );

    };

杂项

资源管理

       资源管理模块负责资源的加载、卸载、排序、搜索等。Ogre的资源管理类图如下所示:

       两个抽象类ResourceManager与Resource,分别代表抽象的资源和资源管理器。它们的派生类分别代表具体的资源和资源管理器。如Material代表材质,MaterialManager负责创建、销毁Material。

不难发现这里应用了抽象工厂模式(请参考<<设计模式>>一书)。Resource类是抽象产品,ResourceManager是抽象工厂。具体产品与具体工厂分别从这两个类继承,并且由具体工厂负责生产具体产品。假如现在我要加入一种新的资源Overlay,则只需从Resource类派生出Overlay类,并从ResourceManager类派生出OverlayManager类,这使得在没有修改老代码的前提下扩展了程序,加入了新功能,这符合开放-封闭性原则(OCP,Open-Closed Principle),这也正是抽象工厂的好处之一。

       资源管理还包括档案文件的读写。

档案(Archive)文件读写

档案(Archive),并不是我们常说的文件,档案可以是一个文件夹(文件夹内可以含有文件和子文件夹),也可以是一个Zip文件(Zip文件里可以包含文件和文件夹)。档案文件呢,顾名思义,就是档案内的文件。

Ogre的档案文件读写类图如下所示:

       档案(Archive)也是一种资源,所以应该从抽象类Resource和ResourceManager派生出ArchiveEx类与 ArchiveManager类。

       由于档案的类型有很多种,可以是Zip文件,也可以是文件系统,还可以是Rar文件等等。为了便于以后加入新的档案类型,我们自然会想到用抽象工厂模式。如上图所示,ArchiveEx与ArchiveFactory分别是抽象产品类与抽象工厂类,Ogre提供了两个具体产品与具体工厂,分别用来处理文件系统和Zip文件。

 

ArchiveEx类

下面我们打开OgreArchiveEx.h,看一下抽象类ArchiveEx的定义。它提供了每种档案(Archive)都应该实现的函数,如下图所示:

这些函数的功能包括:

1,  档案的读取和卸载。

2,  档案文件的打开、读取、保存、删除等操作。

3,  档案内目录的删除、移动、拷贝等操作。

所有成员函数都是纯虚函数,ArchiveEx的子类必须实现这些函数。

ArchiveFactory类

 

ArchiveFactory类定义了两个纯虚函数:

       前者用来创建档案。

       后者返回一字符串,来标识档案的具体类型(Zip或FileSystem)。

 

 

ArchiveManager类

       ArchiveManager类聚合了ArchiveFactory类,并提供了面向用户的档案管理接口,ArchiveManager类图如下:

1,mArchFactories

ArchiveManager维护了一个ArchiveFactory的列表mArchFactories,并以字符串做为具体ArchiveFactory的标识符。

2,load

     load函数负责打开一个档案,以读写档案内的文件。其代码如下

   

    /** 打开一个档案,以读写文件

           @param filename

            要打开的档案名

        @param archiveType

            标识符,标识具体档案工厂的类型。如“Zip”,“FileSystem”。

        @param priority

            档案的优先级

        @returns

            如果成功,则返回指向打开档案对象的指针。如果失败,则抛出异常。

*/

ArchiveEx* ArchiveManager::load( const String& filename, const String& archiveType, int priority )

    {

        ArchiveEx* pArch = (ArchiveEx*)(getByName(filename));

        if (!pArch)

        {

            // 在mArchFactories中搜索由字符串所标识的具体档案工厂

            ArchiveFactoryMap::iterator it = mArchFactories.find(archiveType);

            if (it == mArchFactories.end())

                // 如果未找到,则抛出异常

                Except(Exception::ERR_ITEM_NOT_FOUND, "Cannot find archivefactory "

"to deal with archive of type " + archiveType, "ArchiveManager::load");

 

            pArch = it->second->createObj( filename );

 

            ResourceManager::load(pArch, priority);

        }

        return pArch;

       }

 

3,addArchiveFactory

       addArchiveFactory负责向mArchFactories中加入一个新的具体档案工厂。其代码如下:

    void ArchiveManager::addArchiveFactory(ArchiveFactory* factory)

{

       // getType是ArchiveFactory的成员函数,它返回具体工厂的标识符(如“Zip”)       

        mArchFactories.insert( ArchiveFactoryMap::value_type( factory->getType(), factory ) );

        LogManager::getSingleton().logMessage("ArchiveFactory for archive type " +     factory->getType() + " registered.");

}

 

 

Resource类

       抽象类,代表可以加载的资源。如下图所示:

       其中mLastAccess保存了该资源最后一次被访问的时间,成员函数getLastAccess返回mLastAccess。成员函数touch用来更新该资源的最后访问时间为当前时间:

    void touch(void)

    {

           mLastAccess = time(NULL);

}

time()返回当前的系统时间。

 

 

 

 

      

ResourceManager类

       下图所示为ResourceManager的类图:

1,  mResources

每个ResourceManager类的子类(某种类型资源的资源管理器),都会维护这样一个数据成员,用来保存该类型的资源。成员函数getByName就是通过传入的字符串,返回一个相应的资源指针。

 

2,  mMemoryBudget、mMemoryUsage

用来支持内存预算。mMemoryBudget记录当前资源管理器可以占有的最大内存数,

mMemoryUsage记录当前资源管理器已经占用的内存数。Ogre还没有实现这个特性,只是声明了这两个数据成员。

 

3,  mArchiveFiles、mCommonArchiveFiles

这两个数据成员的类型都是HashMap,Key是字符串类型的,它保存档案内的文件名,value是ArchiveEx类型的指针,它指向文件所在的档案。

其中mCommonArchiveFiles是静态数据成员,静态数据成员在ResourceManager的所有子类中只存在一份,所以它保存了所有的档案。而mArchiveFiles在ResourceManager的一个子类中保存一份,所以它保存了所属资源管理器的档案。

 

4,  mVFS、mCommonVFS

这两个数据成员的类型都是vector<ArchiveEx*>, 用来保存档案,唯一的区别就是mCommonVFS是静态的,而mVFS不是。VFS是virtual file system(虚拟文件系统)的缩写。

下面我们分析一个与mArchiveFiles、mCommonArchiveFiles、mVFS、mCommonVFS有关的函数:addArchiveEx与addCommonArchiveEx负责增加档案,_findResourceData负责搜索档案文件,并将档案文件的内容读取出来。

 

       // 为某种类型的资源增加档案。strName为档案名,strDriverName为档案工厂名。

void ResourceManager::addArchiveEx( const String& strName, const String& strDriverName )

{

       // 通过ArchiveManager得到strName所代表档案的指针

        ArchiveEx* pArch = ArchiveManager::getSingleton().load( strName, strDriverName );

 

              // 得到档案内所有的文件名

        StringVector vec = pArch->getAllNamesLike( "", "" );

              // 将文件名与pArch成对加入到mArchiveFiles中

        for( StringVector::iterator it = vec.begin(); it != vec.end(); ++it )

mArchiveFiles[(*it)] = pArch;     

 

              // 将pArch加入到mVFS中

        mVFS.push_back(pArch);

}

 

 

// 为所有类型的资源增加档案。strName为档案名,strDriverName为档案工厂名。

    void ResourceManager::addCommonArchiveEx( const String& strName, const String& strDriverName )

    {

        ArchiveEx* pArch = ArchiveManager::getSingleton().load( strName, strDriverName );

 

        StringVector vec = pArch->getAllNamesLike( "", "" );

        for( StringVector::iterator it = vec.begin(); it != vec.end(); ++it )

            mCommonArchiveFiles[(*it)] = pArch;

 

        mCommonVFS.push_back(pArch);

}

 

// 搜索并读取文件。

// filename:要读取的文件名

// refChunk:DataChunk对象的引用,用来存储文件的内容

    bool ResourceManager::_findResourceData(

        const String& filename,

        DataChunk& refChunk )

    {

        DataChunk* pChunk = &refChunk;

 

        // Search file cache first

        // NB don't treat this as definitive, incase ArchiveEx can't list all existing files

              // 为什么有些情况下档案不能列出档案内的所有文件?

        FileMap::const_iterator it;

        if( ( it = mArchiveFiles.find( filename ) ) != mArchiveFiles.end() )

            return it->second->fileRead( filename, &pChunk );

        if( ( it = mCommonArchiveFiles.find( filename ) ) != mCommonArchiveFiles.end() )

            return it->second->fileRead( filename, &pChunk );

 

        // Not found in cache

        // Look for it the hard way

        std::vector<ArchiveEx*>::iterator j;

        // Search archives specific to this resource type

        for(j = mVFS.begin(); j != mVFS.end(); ++j )

        {

            if( *j && (*j)->fileTest(filename) )

            {

                return (*j)->fileRead( filename, &pChunk );

            }

        }

        // Search common archives

        for(j = mCommonVFS.begin(); j != mCommonVFS.end(); ++j )                

        {

            if( *j && (*j)->fileTest(filename) )

            {

                return (*j)->fileRead( filename, &pChunk );

            }

        }

       

        // Not found

        Except(

            Exception::ERR_ITEM_NOT_FOUND,

            "Resource " + filename + " not found.",

            "ResourceManager::_findResourceData" );

 

        // To keep compiler happy

        return false;

    }

 

输入/输出

渲染器

渲染器可以分为几个模块:可见性、碰撞检测和响应、摄象机、静态几何图形、动态几何图形、粒子系统、公告板、网格、天空盒、光照、雾化、顶点着色、输出。

Ogre的渲染器让所有的三角形同时进入渲染管道。(不是每次一个三角形,我们可以用三角形列表、扇形、条带等等)。Ogre把所有的东西统一成为一种格式,以便经过相同的光照、雾化、及阴影代码处理。最后,你会欣慰地发现,只要简单地改变材质/纹理索引,就可以对游戏中所有多边形生效。

下面我们将一步步剖析Ogre的渲染器。

Ogre的几何渲染管道

综述

Ogre的几何渲染管道简如下图所示:

       Renderable类代表所有可以渲染的事物,RenderSystem类代表渲染系统(图形API的抽象层),它负责将Renderable最终渲染到显示器上,RenderOperation类描述了渲染操作(比如用列表、扇形还是条带来渲染三角形),并且保存了顶点坐标数组与纹理坐标数组。RenderOperation将所有东西统一成为一种格式,以便经过相同的光照、雾化、及阴影代码处理。

       在Ogre中,通过Renderable类的成员函数getRenderOperation(RenderOperation &)来得到可渲染物体的RenderOperation,然后通过RenderSystem类的_render(RenderOperation &)统一渲染所有的RenderOperation。

       下图显示了渲染系统RenderSystem的继承关系:

 

       Ogre实现了Direct3D7、Direct3D8和SDL+OpenGL这些渲染系统,你可以通过编写插件(Plugin)来增加新的渲染系统。

       Renderable是可以被RenderSystem渲染的物体的基类。下图是Renderable的继承关系:

       包括公告板集合、图形用户界面、节点等。

渲染队列

       我们知道,渲染速度的快慢很大程度上取决于渲染状态的变化次数的多少。如果渲染状态频繁的变化,则渲染速度会很慢,反之,渲染速度会提高。Ogre的渲染队列就是为了尽量减少渲染状态的变化而设计的。

       Ogre渲染队列的类图如下所示:

      

关键点在RenderPriorityGroup类,它维护了一个以Material为key,以Renderable列表为value的Map,这使得拥有相同Material的Renderable被放到一起,便于管理:

 

typedef std::map<Material*, RenderableList > MaterialGroupMap;

MaterialGroupMap mMaterialGroups;

 

在MaterialGroupMap中,将不透明Material放到透明Material的前面。

渲染时,设置一个Material,将用到此Material的所有可渲染物体(Renderable)全部渲染。然后设置下一个Material,也就是转到下一个状态。这样,渲染状态变化的次数最少,因此渲染速度上升了。

渲染过程

       下面的序列图描述了Ogre的渲染过程:

SceneManager类是关键,它组织场景中所有事物,并将可渲染物体(Renderable)交给RenderSystem处理。下图显示了SceneManager与RenderQueue、RenderSystem的关系。

 

Root的startRendering()是渲染循环的进入点,经过一系列函数调用,最终执行SceneManager的成员函数_renderScene(),下面我们具体分析一下_renderScene()的代码:

    void SceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays)

    {

      // …

        // 更新场景

        _applySceneAnimations();     // 更新场景中物体的动画

        _updateSceneGraph(camera);// 更新场景中物体的位置、方向

        _updateDynamicLights();   // 更新动态光的信息位置、方向

 

        // 清空渲染队列

        mRenderQueue.clear();

 

        // 分析场景中的物体,将可见的物体加入到渲染队列

        _findVisibleObjects(camera);

       

// 将天空加入渲染队列

        _queueSkiesForRendering(camera);

 

        // 设置渲染模式(点、线框、固体)

        mDestRenderSystem->_setRasterisationMode(camera->getDetailLevel());

 

        // 更新所有的Controller

        ControllerManager::getSingleton().updateAllControllers();

 

        // 渲染场景内的物体(不包括场景本身)

        _renderVisibleObjects();

}

_renderScene()每一次渲染循环都会被调用一次。它负责将场景的内容进行排序、culling,然后放到渲染管道里渲染。

       Ogre的渲染管道将场景合理地组织后,再进行渲染。这样做减少了渲染状态的变化,提高了渲染速度。

      

可渲染事物(Renderable)

Renderable类

       Renderable是抽象类,它定义了所有可渲染事物都应该实现的接口。下面是Renderable类的部分代码:

    class _OgreExport Renderable

    {

    public:

        // 返回指向Renderable所用材质(Material)的指针

        virtual Material* getMaterial(void) const = 0;

       

// 得到Renderable的RenderOperation

        virtual void getRenderOperation(RenderOperation& rend) = 0;

       

// 返回此可渲染事物的旋转/平移矩阵

        virtual void getWorldTransforms(Matrix4* xform) = 0;

 

              // 返回可渲染事物到摄像机的距离

              virtual Real getSquaredViewDepth(const Camera* cam) const = 0;

 

};

前面讲过,RenderOperation是为了将Ogre中所有物体抽象成一种格式而设计的。所有的可渲染事物必须实现函数getRenderOperation(),用来返回统一的格式RenderOperation。

GetSquaredViewDepth()的返回值用来排序渲染队列中的透明事物,从而能够正确显示多个透明事物重叠的情况。

 

材质(Material)

为了优化渲染,必须把渲染状态的变化减少到最小。渲染状态改变最频繁的是材质的变化(材质变化又大多是纹理的变化)。尽管我们建议对一个物体只用一个纹理,但实际中一个物体的不同部份有可能用多个纹理来实现。

Ogre的Material类封装了一个物体的所有材料属性,类似于3D Studio中material的概念。平时不被认为是属于材料的属性,像culling模式和深度缓存设置等,也被Ogre的Material类包含了。因为这些属性同样影响了物体的外观,把它们放到Material类里可以集中设置所有影响物体的属性。这和D3D中只保存颜色组件而没有纹理映射的Material有明显不同。Ogre的Material可以被认为是’Shader’的等同物。

与Material相关的类,如下图所示:

       Root类聚合了MaterialManager类,它通过MaterialManager来管理Material对象。材质(Material)可以由一层或多层纹理组成,Ogre抽象出TextureLayer类来代表一层纹理,因此Material聚合TextureLayer类。同时Material是一种资源(Resource),因此Material是Resource类的派生类,提供加载材质资源的接口。

 

Material类

       Material的类图如下:

      

Material类包括如下几类属性:

1,  基本的表面材质属性,如对不同颜色的反射率、Shininess等等:

ColourValue mAmbient;        

            ColourValue mDiffuse;         

            ColourValue mSpecular;   

            ColourValue mEmissive;

            Real mShininess;

2,  组成Material的纹理层

int mNumTextureLayers;

TextureLayer mTextureLayers[OGRE_MAX_TEXTURE_LAYERS];

3,  纹理之间的混合(Blend)方式

SceneBlendFactor mSourceBlendFactor;   

SceneBlendFactor mDestBlendFactor;

4,  深度缓冲设置

        bool mDepthCheck;

        bool mDepthWrite;

        CompareFunction mDepthFunc;

        ushort mDepthBias;

5,  Culling模式

        CullingMode mCullMode;                                  // 硬件Culling模式

        ManualCullingMode mManualCullMode;              // 软件Culling模式     

6,  纹理过滤方式

        TextureFilterOptions mTextureFiltering;

           enum TextureFilterOptions

           {

               TFO_NONE,               

               TFO_BILINEAR,          // 双线性纹理过滤

               TFO_TRILINEAR         // 三线性纹理过滤

           };

 

7,  是否受光照影响

8,  Shading选项

9,  雾化

        bool mFogOverride;

        FogMode mFogMode;

        ColourValue mFogColour;

        Real mFogStart;

        Real mFogEnd;

        Real mFogDensity;

       其中TextureLayer类是在Material类内定义的,它代表一层纹理。

TextureLayer类

MaterialManager类

       MaterialManager类负责管理Material库。它还负责分析Material脚本(Material Script),来初始化Material的属性,其类图如下:

1,  mHandles、mResources

前者是用整数Handle管理Material库。后者是用Material名来管理相同的Material库。

Create函数,创建一个Material类的对象,将之加入到mHandles和mResources中,并加相关的档案文件(纹理图)。

CreateDefferred函数,创建这个对象,将之加入到mHandles和mResources中,但并不加载档案文件。

Add函数,向mHandles和mResources中加入一个非MaterialManager创建的Material的拷贝。

GetByHandle与getByName分别通过Handle与Material名称来获得指向该Material对象的指针。

2,  mMatAttribParsers、mLayerAttribParsers

/// Function def for material attribute parser.

typedef void (*MATERIAL_ATTRIB_PARSER)(StringVector::iterator&, int, Material*);

/// Function def for texture layer attribute parser.

typedef void (*TEXLAYER_ATTRIB_PARSER)(StringVector::iterator&, int, Material*, Material::TextureLayer*);

 

        /// Keyword-mapped attribute parsers.

        //typedef std::map<String, MATERIAL_ATTRIB_PARSER> MatAttribParserList;

        typedef std::map<String, MATERIAL_ATTRIB_PARSER> MatAttribParserList;

        MatAttribParserList mMatAttribParsers;

        /// Keyword-mapped attribute parsers.

        typedef std::map<String, TEXLAYER_ATTRIB_PARSER> LayerAttribParserList;

        //typedef HashMap<String, TEXLAYER_ATTRIB_PARSER, std::hash<String>> LayerAttribParserList;

        LayerAttribParserList mLayerAttribParsers;

Controller类

 

公告板与粒子系统

公告板

       所谓公告板,就是指一个矩形(由两个三角形拼接成),这个矩形总是面向摄像机。根据这个特点,公告板可以模拟一些特效,粒子系统中的每一个粒子就是一个公告板。Ogre定义了Billboard类来代表公告板。

       为了提高效率,我们可以把具有相同属性的公告板放到一起同时处理。Ogre实现了BillboardSet类,将具有相同大小、材质(Material)以及相同活动区域的公告板组织到一起,见下图:

      

      

Billboard类

      

BillboardSet类

       BillboartSet类是怎么管理Billboard的呢?答案是用Billboard池,它负责保存所有的Billboard。在Billboard池里有两种Billboard,一种是被激活的,一种是未被激活的。

粒子系统

静态几何图形

动态几何图形

光照

摄像机

场景本身

雾化

GUI

字体渲染

可见性

 来源:<<Ogre设计教程>>

作者

Mage小组。Mage = Make a game engine 或者 Marry a game engine。

成员:Norman_chen  

         noslopforever  

renwind       

  评论这张
 
阅读(467)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017