Ogre中SceneManager分析

原创 2007年09月26日 13:32:00
 

SceneManager分析

最近以为写引擎,需要研究ogre,以下是研究场景管理的结果。

Ogre使用插件机制来实现场景管理功能。ScenceManager只是接口,他可以有很多具体的实现。Ogre允许在同一时刻同一场景中使用多个Scene Manager,这样在不同的场景类型切换时带来好处。(v1.4版本后加了一个SceneManagerEnumerator)。

 

场景管理主要工作包括以下几点:

1.可移动、不可移动和可渲染物体的创建删除。

2.场景查询。

3.渲染队列。

4.动态阴影。

 

. 场景对象创建

场景中的所有对象,包括可移动与不可移动的:CameraLightSceneNodeEntityManualObjectBillboardChainRibbonTrailParticleSystemBillboardSetAnimationAnimationStateStaticGeometryMovableObject13种物体的createXXXgetXXXhasXXXdestroyXXX.都由场景管理器来创建。场景中的任何东西都由场景管理器来管理。任何通过场景管理器得到的东西,都必须由场景管理器来销毁。用户不能delete通过由场景管理器得到的指针。

 

SkyDome, SkyPlane, SkyBox

主要的相似点是它们与相机保持一个常量的距离。它们可以在场景中其它对象之前或是之后渲染。它们使用普通的ogre material,因此纹理动画与其他纹理没有什么不同。它们可以被场景管理器打开或关闭,与相机的距离也可以设置。

skyplane 是一个平面。用距离和法线定义它与相机的位置关系。可以弯曲,可以分多个段,可对纹理进行多次平铺。

skydome由五个平面组成,底部空。使用改变纹理坐标的方式来达到外观上的曲率变化。有一个值用来调节,值越低,曲率越柔和,值越高,越陡峭。

skybox skydome,但他不能弯曲材质坐标。它可以使用立方材质。可使用硬件加速功能达到很好渲染效率。

 

SkyDome, SkyPlane, SkyBox3种天空形式的setSkyXXXisSkyXXXgetSkyXXX

getSkyXXXGenParameters.以及setFoggetFog等参数的操作。

 

以下是这些操作一览:

1.Create函数

 

2.Destroy函数

3.Set函数

4.Get函数

 

. 场景查询

Ogre的场景查询目前分为3种,一种是相交查询,一种是射线查询,一种是区域查询。查询的结果分为两种,一种是可运动对象(movable objects),一种是关卡的一部分(world geometry)。对于不同的场景管理器,同种查询得到的结果是不一样的。

其实查询可以直接做到场景管理器中,不过Ogre另外开辟了一个类,专门负责处理查询,就是SceneQuery。这个类的查询操作,其实就是包装场景管理器的查询接口。

相交查询,主要是查询两两相交的可运动对象,以及可运动对象和关卡子部分。

射线查询也是这种。

区域查询,是设定一个区域,如AABB区域,或者球形区域,或者由多面体组成的区域,查询在该区域中的可运动对象。

所有这些查询都是 maskble的,这表明可以在查询时过滤掉不关心的对象类型。如球查询时,只想看看它包含了多少lights,其他的对象即使包含在球里也不必返回,实际上根本不用计算。以下是UML

 

1. WorldFragmentTypeWorldFragment

    前面说过查询的结果分两种, movable objectsworld geometry。而world geometry根据不同的查询方式得到的结果又分几种。WorldFragment就是表示world geometry查询结果的结构。WorldFragmentType是指用那种查询方式得到的结果。

enum WorldFragmentType {

    WFT_NONE,

    WFT_PLANE_BOUNDED_REGION,    // Region Scene Query结果

    WFT_SINGLE_INTERSECTION,     // Ray Scene Query结果

    WFT_CUSTOM_GEOMETRY,         // 自定义结果

    WFT_RENDER_OPERATION         // ?没发现有用

};

struct WorldFragment {

    WorldFragmentType fragmentType;

    Vector3 singleIntersection;  // WFT_SINGLE_INTERSECTION

    std::list<Plane>* planes;    // WFT_PLANE_BOUNDED_REGION

    void* geometry;              // WFT_CUSTOM_GEOMETRY

    RenderOperation* renderOp;   // ?没发现有用

};

 

2. SceneQuerySceneQueryListener

    SceneQuery场景查询的基类,负责保存与之相关的SceneManager、查询掩码和查询类掩码(SceneQuery类型掩码需要自己定义,也自己解释)和场景查询支持的World Fragment Type

SceneManager* mParentSceneMgr;

uint32 mQueryMask;

uint32 mQueryTypeMask;

std::set<WorldFragmentType> mSupportedWorldFragments;

WorldFragmentType mWorldFragmentType;

SceneManager中定义了几种类型掩码,如下:

static uint32 WORLD_GEOMETRY_TYPE_MASK;   // for world geometry

static uint32 ENTITY_TYPE_MASK;           // for entities

static uint32 FX_TYPE_MASK;               // for effects like billboardsets / particle systems

static uint32 STATICGEOMETRY_TYPE_MASK;   // for StaticGeometry

static uint32 LIGHT_TYPE_MASK;            // for lights

static uint32 USER_TYPE_MASK_LIMIT;       // max limit

 

SceneQueryListener是负责执行场景查询的回调抽象类,在3种查询的执行中把

SceneQueryListener的指针传递给SceneQuery的子类。

virtual void execute(SceneQueryListener* listener);

以下是SceneQueryListener的定义

class _OgreExport SceneQueryListener

{

public:

    virtual ~SceneQueryListener() { }

    virtual bool queryResult(MovableObject* object) = 0;

    virtual bool queryResult(SceneQuery::WorldFragment* fragment) = 0;

};

 

3. RegionSceneQuery RaySceneQuery IntersectionSceneQuery

上面3个查询的功能很简单,主要负责执行查询和保存查询结果。RegionSceneQuery又分别派生AxisAlignedBoxSceneQuerySphereSceneQueryPlaneBoundedVolumeListSceneQuery

 

4.SceneManager中的SceneQuery

上面提过SceneQuery其实就是包装场景管理器的查询接口。下面代码证明了这个说法:

class DefaultRaySceneQuery : public RaySceneQuery

{

public:

    DefaultRaySceneQuery(SceneManager* creator);

    ~DefaultRaySceneQuery();

    void execute(RaySceneQueryListener* listener);

};

class DefaultSphereSceneQuery : public SphereSceneQuery

{

public:

    DefaultSphereSceneQuery(SceneManager* creator);

    ~DefaultSphereSceneQuery();

    void execute(SceneQueryListener* listener);

};

class DefaultPlaneBoundedVolumeListSceneQuery : public PlaneBoundedVolumeListSceneQuery

{

public:

    DefaultPlaneBoundedVolumeListSceneQuery(SceneManager* creator);

    ~DefaultPlaneBoundedVolumeListSceneQuery();

    void execute(SceneQueryListener* listener);

};

class DefaultAxisAlignedBoxSceneQuery : public AxisAlignedBoxSceneQuery

{

public:

    DefaultAxisAlignedBoxSceneQuery(SceneManager* creator);

    ~DefaultAxisAlignedBoxSceneQuery();

    void execute(SceneQueryListener* listener);

};

 

5. SceneManager中的接口

virtual AxisAlignedBoxSceneQuery*

    createAABBQuery(const AxisAlignedBox& box, unsigned long mask = 0xFFFFFFFF);

 

virtual SphereSceneQuery*

    createSphereQuery(const Sphere& sphere, unsigned long mask = 0xFFFFFFFF);

 

virtual PlaneBoundedVolumeListSceneQuery*

    createPlaneBoundedVolumeQuery(const PlaneBoundedVolumeList& volumes, unsigned long mask = 0xFFFFFFFF);

 

virtual RaySceneQuery*

    createRayQuery(const Ray& ray, unsigned long mask = 0xFFFFFFFF);

 

virtual IntersectionSceneQuery*

    createIntersectionQuery(unsigned long mask = 0xFFFFFFFF);

 

virtual void destroyQuery(SceneQuery* query);

下图是整个SceneQuery家族的UML结构图

. 渲染队列RenderQueue

1. RenderQueue的组成

RenderQueueOgre::RenderQueueGroup组成的,RenderQueue中有一个RenderQueueGroupMap的数据成员:

typedef std::map< RenderQueueGroupID, RenderQueueGroup * > RenderQueueGroupMap

RenderQueueGroupMap mGroups

可见RenderQueueGroupMap keyRenderQueueGroupID,代表Objects的渲染先后顺序。RenderQueueGroupID是一个枚举量,根据场景内物体的渲染顺序由先及后定义RenderQueueGroupID的定义如下

     enum RenderQueueGroupID

     {

         RENDER_QUEUE_BACKGROUND = 0,

         RENDER_QUEUE_SKIES_EARLY = 5,

         RENDER_QUEUE_1 = 10,

         RENDER_QUEUE_2 = 20,

         RENDER_QUEUE_WORLD_GEOMETRY_1 = 25,

         RENDER_QUEUE_3 = 30,

         RENDER_QUEUE_4 = 40,

         RENDER_QUEUE_MAIN = 50,

         RENDER_QUEUE_6 = 60,

         RENDER_QUEUE_7 = 70,

         RENDER_QUEUE_WORLD_GEOMETRY_2 = 75,

         RENDER_QUEUE_8 = 80,

         RENDER_QUEUE_9 = 90,

         RENDER_QUEUE_SKIES_LATE = 95,

         RENDER_QUEUE_OVERLAY = 100,

     }

RenderQueue通过成员函数addRenderable 添加物体到渲染队列中,在RenderQueue getQueueGroup成员负责RenderQueueGroup的查找创建。RenderQueueGroup的生命周期由RenderQueue来控制。

 

2. RenderQueueGroup的组成

RenderQueueGroup中有一个RenderPriorityGroupMap的数据成员:

typedef std::map<ushort, RenderPriorityGroup*, std::less<ushort> > PriorityMap;

PriorityMap mPriorityGroups;

 

PriorityMapkey为一个ushort,它代表着RenderPriorityGroup渲染的优先级。对同一优先级的ObjectsRenderQueueGroup会通过成员函数addRenderable 将它加入相同的RenderPriorityGroup中,RenderPriorityGroup的生命周期是由 RenderQueueGroup管理的。

 

3. RenderPriorityGroup的组成

RenderPriorityGroup中是存放需要渲染的Objects的最终场所。需要渲染的Objects——RenderableRenderPriorityGroup组织将其组织为RenderableList,然后把RenderableList组织成SolidRenderablePassMap

 

typedef std::vector<Renderable*> RenderableList;

typedef std::map<Pass*, RenderableList*, SolidQueueItemLess> SolidRenderablePassMap;

SolidRenderablePassMap mSolidPasses;

SolidRenderablePassMap mSolidPassesDiffuseSpecular;

SolidRenderablePassMap mSolidPassesDecal;

SolidRenderablePassMap mSolidPassesNoShadow;

综上所述,需渲染的物体分别经过RenderPriorityGroupRenderQueueGroup分类后,由RenderQueue统一管理。

 

 

4. QueuedRenderableCollection

RenderPriorityGroup5个成员变量mSolidsBasicmSolidsDiffuseSpecularmSolidsDecalmSolidsNoShadowReceivemTransparents都是QueuedRenderableCollection

QueuedRenderableCollection是存储RenderablePass的最终场所。通过多种排序实现RenderablePass的有序化。排序包括小于排序、深度递减排序和基数排序。

     typedef std::vector<RenderablePass> RenderablePassList;

     typedef std::vector<Renderable*> RenderableList;

     typedef std::map<Pass*, RenderableList*, PassGroupLess> PassGroupRenderableMap;

     PassGroupRenderableMap mGrouped;

     RenderablePassList mSortedDescending;

mGroupedmSortedDescending中存储的是RenderablePass

QueuedRenderableCollection组织RenderablePass有三种,分别是按Pass分组、按与camera的距离升序和按与camera的距离减序。

         enum OrganisationMode{

              OM_PASS_GROUP = 1,

              OM_SORT_DESCENDING = 2,

              OM_SORT_ASCENDING = 6

         };

 

5.QueuedRenderableVisitor

QueuedRenderableVisitor是按访问者模式设计的抽象接口。在QueuedRenderableCollection中有一个公用接口和三个内部接口如下:

void acceptVisitor(QueuedRenderableVisitor* visitor, OrganisationMode om) const;

void acceptVisitorGrouped(QueuedRenderableVisitor* visitor) const;

void acceptVisitorDescending(QueuedRenderableVisitor* visitor) const;

void acceptVisitorAscending(QueuedRenderableVisitor* visitor) const;

 

acceptVisitorOrganisationMode3种方式分别调用内部接口acceptVisitorGrouped

acceptVisitorDescendingacceptVisitorAscending

switch(om)

{

case OM_PASS_GROUP:

     acceptVisitorGrouped(visitor);

     break;

case OM_SORT_DESCENDING:

     acceptVisitorDescending(visitor);

     break;

case OM_SORT_ASCENDING:

     acceptVisitorAscending(visitor);

     break;

}

acceptVisitorGroupedacceptVisitorDescendingacceptVisitorAscending。内部调用如下

void QueuedRenderableCollection::acceptVisitorGrouped(QueuedRenderableVisitor* visitor) const

{

     RenderableList* rendList = ipass->second;

     RenderableList::const_iterator irend, irendend;

     irendend = rendList->end();

     for (irend = rendList->begin(); irend != irendend; ++irend)

     {

         visitor->visit(*irend);

     }

}

通过以上分析可以看到最终的渲染任务是交到QueuedRenderableVisitor手中。

而在SceneManager中有如下定义,具体实现了渲染任务。

class SceneMgrQueuedRenderableVisitor : public QueuedRenderableVisitor

SceneMgrQueuedRenderableVisitor* mActiveQueuedRenderableVisitor;

SceneMgrQueuedRenderableVisitor mDefaultQueuedRenderableVisitor;

 

6. RenderTarget

RenderTarget用来接收渲染操作的结果,它可以是屏幕上的窗口、离屏面(如texture)等。FPS信息的统计也是由RenderTarget完成的。在RenderTarget每次更新完成后,将会更新统计信息(封装于FrameStats中)。 除了负责统计帧的信息外,RenderTarget还负责创建维护Viewport(视口):

typedef std::map<int, Viewport*, std::less<int> > ViewportList;

    ViewportList mViewportList;

    Viewport* RenderTarget::addViewport(Camera* cam, int ZOrder, float left, float top ,

        float width , float height)

    {

        ViewportList::iterator it = mViewportList.find(ZOrder);

        if (it != mViewportList.end())

        {

             

        }

        Viewport* vp = new Viewport(cam, this, left, top, width, height, ZOrder);

        mViewportList.insert(ViewportList::value_type(ZOrder, vp));

        fireViewportAdded(vp);

        return vp;

}

由上面的代码可以看出,每个Viewport都对应一个Camera和一个RenderTarget。当创建一个Viewport后,它会自动建立与Camera的联系。可以把Camera看作是图像的来源,而RenderTarget是图像渲染的目的地。一个Viewport只能对应一个Camera和一个RenderTarget,而一个Camera也只能对应一个Viewport,但RenderTarget却可以拥有几个Viewport

 

7. 渲染过程

OGRE通过WinMainmain调用go再通过Root调用startRendering进行消息循环,然后调用renderOneFrame,通过RenderSystem_updateAllRenderTargets方法,更新所有的RenderTargetRenderTarget通过update方法更新与之关联的Viewport并产生FPS统计信息。而Viewport则调用与之关联的Camera_renderScene方法进行渲染,Camera此时把踢给SceneManager。进入SceneManagerrenderScene成员函数中后,在经过计算后,把需要渲染的场景送给RenderSystem去做真正的渲染,此时我们可以看到熟悉的_breginFrame_endFrame。 一直下去经过RenderQueueRenderQueueGroupRenderPriorityGroupQueuedRenderableCollection再通过访问者到达QueuedRenderableVisitor的子类SceneMgrQueuedRenderableVisitor,最终又回到SceneManager,由SceneManager再到RenderSystem完成整个渲染过程。过程伪码如下所示:

int WinMain or main(int argc, char **argv)

{

app.go();

}

virtual void go(void)

{

     Root->startRendering();

}

void Root::startRendering(void)

{

     renderOneFrame();

}

bool Root::renderOneFrame(void)

{

     _updateAllRenderTargets();

}

void Root::_updateAllRenderTargets(void)

{

     RenderSystem->_updateAllRenderTargets();

}

void RenderSystem::_updateAllRenderTargets(void)

{

     RenderTarget->update();

}

void RenderTarget::update(void)

{

     Viewport->update();

}

void Viewport::update(void)

{

     Camera->_renderScene(this, mShowOverlays);

}

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

{

     SceneManager->_renderScene(this, vp, includeOverlays);

}

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

{

    RenderSystem->_beginFrame();

    _renderVisibleObjects();

    RenderSystem->_endFrame();

}

void SceneManager::_renderVisibleObjects(void)

{

//如果有阴影

renderVisibleObjectsCustomSequence();

//否则

renderVisibleObjectsDefaultSequence();

}

void SceneManager::renderVisibleObjectsDefaultSequence(void)

{

     fireRenderQueueStarted(qId,mIlluminationStage)

     _renderQueueGroupObjects(pGroup, QueuedRenderableCollection::OM_PASS_GROUP);

     fireRenderQueueEnded(qId, mIlluminationStage)

}

void SceneManager::_renderQueueGroupObjects(RenderQueueGroup* pGroup, OrganisationMode om)

{

     renderBasicQueueGroupObjects(pGroup, om);

}

void SceneManager::renderBasicQueueGroupObjects(RenderQueueGroup* pGroup, OrganisationMode om)

{

     renderObjects(pPriorityGrp->getSolidsBasic(), om, true);

}

void SceneManager::renderObjects(const QueuedRenderableCollection& objs, )

{

     objs.acceptVisitor(mActiveQueuedRenderableVisitor, om);

}

void QueuedRenderableCollection::acceptVisitor(QueuedRenderableVisitor* visitor)

{

     switch(om){

     case OM_PASS_GROUP:

         acceptVisitorGrouped(visitor);

     }

}

void QueuedRenderableCollection::acceptVisitorGrouped(QueuedRenderableVisitor* visitor)

{

     QueuedRenderableVisitor->visit(Renderable);

}

void SceneManager::SceneMgrQueuedRenderableVisitor::visit(const Renderable* r)

{

     SceneManager->renderSingleObject(r, mUsedPass, autoLights, manualLightList);

}

void SceneManager::renderSingleObject(const Renderable* rend, const Pass* pass)

{

     RenderSystem->_render(RenderOperation);

}

最终进入的RenderSystem的子类D3D9RenderSystem or GLRenderSystem

void D3D9RenderSystem::_render(const RenderOperation& op)

{

mpD3DDevice->DrawIndexedPrimitive or mpD3DDevice->DrawPrimitive

}

void GLRenderSystem::_render(const RenderOperation& op)

{

glDrawElements or glDrawArrays

}

 

 

8. RenderQueueListener

class _OgreExport RenderQueueListener

{

public:

     virtual ~RenderQueueListener() {}

 

     virtual void renderQueueStarted(uint8 queueGroupId, const String& invocation, bool& skip) = 0;

     virtual void renderQueueEnded(uint8 queueGroupId, const String& invocation, bool& repeat) = 0;

};

RenderQueueListener的作用就是在SceneManager开始渲染和结束渲染时改变render state和别的操作,比如检查本次RenderQueue是否skip,如果skip就直接break本次render

在上面渲染过程中有如下:

void SceneManager::renderVisibleObjectsDefaultSequence(void)

{

     fireRenderQueueStarted(qId,mIlluminationStage)

     _renderQueueGroupObjects(pGroup, QueuedRenderableCollection::OM_PASS_GROUP);

     fireRenderQueueEnded(qId, mIlluminationStage)

}

fireRenderQueueStartedfireRenderQueueEnded中遍列RenderQueueListener

定义如下:

typedef std::vector<RenderQueueListener*> RenderQueueListenerList;

RenderQueueListenerList mRenderQueueListeners;

bool SceneManager::fireRenderQueueStarted(uint8 id, const String& invocation)

{

    RenderQueueListener->renderQueueStarted(id, invocation, skip);

}

bool SceneManager::fireRenderQueueEnded(uint8 id, const String& invocation)

{

     RenderQueueListener->renderQueueEnded(id, invocation, repeat);

}

 

9. SpecialCaseRenderQueue

SenceManager中的RenderQueue包含一种特殊情况的渲染队列(Special Case Render Queue

enum SpecialCaseRenderQueueMode{

SCRQM_INCLUDE,     // 只渲染Special Case

     SCRQM_EXCLUDE      // 不渲染Special Case

};

通过setSpecialCaseRenderQueueMode可以设置。以下是跟Special Case Render Queue有关的变量和操作:

typedef std::set<uint8> SpecialCaseRenderQueueList;

SpecialCaseRenderQueueList mSpecialCaseQueueList;

SpecialCaseRenderQueueMode mSpecialCaseQueueMode;

 

virtual void addSpecialCaseRenderQueue(uint8 qid);

virtual void removeSpecialCaseRenderQueue(uint8 qid);

virtual void clearSpecialCaseRenderQueues(void);

virtual void setSpecialCaseRenderQueueMode(SpecialCaseRenderQueueMode mode);

virtual SpecialCaseRenderQueueMode getSpecialCaseRenderQueueMode(void);

这里面需要说明一下的是qidqidRenderQueueGroupIDRenderQueueGroupID的定义在上面已经提过。

 

总之,通过上面分析可以看出render queueRenderable的集合。其实场景树和渲染队列都是对Renderable进行分类,只是分类的标准不同,场景树主要是从空间结构对Renderable进行分类,而渲染队列则是对Renderablematerial以及blend上进行分类。

 

. 动态阴影Shadow

Ogre支持两种主流的动态阴影技术,模板(stencil)阴影与纹理(texture)阴影,每一种都有两个变体:modulative additive。这四种技术完全兼容fixed-function pipeline,因此不需要可编程GPU支持。然而,可利用GPU程序进行加速。在场景中只能使用一种阴影Technique,应该在场景渲染这前进行阴影Technique相关设置(最好是在创建场景管理器之间)。通过调用SceneManager::setShadowTechnique来设置Technique,参数指定Technique的具体类型。阴影Technique缺省情况下被关闭。对于物体,投射与接收阴影可以在材质中控制,也可以控制物体自己对自己投射。由于模板阴影算法的本质特征,透明半透明的物体要么全部投射实心阴影要么根本不投影影,不可能得到半透明的阴影。而使用纹理阴影技术则可以。灯不能用来投射阴影。

 

1. ShadowRenderable

    ShadowRenderable是存储shadow volume材质和渲染数据的类。

 

2. ShadowCaster

    ShadowCaster是计算和产生shadow volume的类。

 

3. ShadowVolumeExtrudeProgram

    ShadowVolumeExtrudeProgram是存储asm shader代码的类。

 

4. ShadowListener

    ShadowListener可以在渲染阴影过程中定义一些自己的操作。这个类只在shadow texture时有用。

 

Shadow这块可以精简,ogre有点复杂。 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关文章推荐

Ogre中SceneManager分析

SceneManager分析 最近以为写引擎,需要研究ogre,以下是研究场景管理的结果。 Ogre使用插件机制来实现场景管理功能。ScenceManager只是接口,他可以有很多具体的实...

Ogre场景管理器SceneManager类

  • 2010年12月23日 14:22
  • 224KB
  • 下载

SceneManager 第五章 Ogre场景管理器

第五章 Ogre场景管理器作者:赵光强 发表于 2010-8-2 16:58:49     在这里我可以大胆的断言,目前在地球上,所有的图形引擎都在使用场景图(Scene Graph)的概念来组织管理...

Ogre游戏开发 第一课 SceneManager,SceneNode和 Entity Objects

第一课课程介绍:     这一课中,我们将会给你介绍Ogre中非常基础的组件:SceneManager, SceneNode 和 Entity Objects。 为了让你能更好的开始学习Ogre,...
  • ml3947
  • ml3947
  • 2012年07月07日 00:00
  • 2143

ogre 场景管理器 scenemanager

声明:本篇转自 痞子龙3D编程 CSDN博客,仅留作学习交流之用 ^_^ 原文参照: http://blog.csdn.net/pizi0475/archive/2010/04/05/54513...

OGRE基础教程 一 SceneManager、SceneNode、Entity

英语水平有限,欢迎大家批评指正 本文并没有将原文全部翻译,只是将其中的一些知识点翻译总结了一下,想要查看详细讲解的话,可以到原文处看一下,附上英文原文地址:http://www.ogre3d.org...

Ogre 1.8 SceneManager

终于到了麻烦的场景管理了。 OgreSceneManager.h 最重要的类SceneManager,主要功能就是管理一个场景,也就是Scene(由一群SceneNode组成),当然还可以同时管理...

Ogre场景管理器SceneManager类

SceneManager类       场景管理类,是场景管理的核心类。       SceneManager类内部保存std::map类型的CameraList、LightList、EntityLi...

OGRE基础教程一:OGRE最基本的组成结构:SceneManager,SceneNode和Entity objects

文献来源网址:http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Basic+Tutorial+1&structure=Tutorials     导...

OGRE分析之场景管理

  • 2012年11月15日 18:44
  • 258KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Ogre中SceneManager分析
举报原因:
原因补充:

(最多只允许输入30个字)