Ogre 渲染流程 RenderProcess

1. RenderQueue的组成

RenderQueue由Ogre::RenderQueueGroup组成的,RenderQueue中有一个RenderQueueGroup的Map的数据成员:

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

可见RenderQueueGroupMap 的key为RenderQueueGroupID,代表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,
     ENDER_QUEUE_OVERLAY = 100,
}

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

2. RenderQueueGroup的组成

RenderQueueGroup中有一个RenderPriorityGroup的Map的数据成员:

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

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

3. RenderPriorityGroup的组成

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

typedef std::vector<Renderable*> RenderableList;
typedef std::map<Pass*, RenderableList*, SolidQueueItemLess> SolidRenderablePassMap;
SolidRenderablePassMap mSolidPasses;
SolidRenderablePassMap mSolidPassesDiffuseSpecular;
SolidRenderablePassMap mSolidPassesDecal;
SolidRenderablePassMap mSolidPassesNoShadow;

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

4. QueuedRenderableCollection

RenderPriorityGroup有5个成员变量mSolidsBasicm、SolidsDiffuseSpecular、mSolidsDecal、mSolidsNoShadowReceive、mTransparents都是QueuedRenderableCollection,

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

     typedef std::vector<RenderablePass> RenderablePassList;
     typedef std::vector<Renderable*> RenderableList;
     typedef std::map<Pass*, RenderableList*, PassGroupLess> PassGroupRenderableMap;
     PassGroupRenderableMap mGrouped;
     RenderablePassList mSortedDescending;

mGrouped和mSortedDescending中存储的是Renderable和Pass。

QueuedRenderableCollection组织Renderable和Pass有三种,分别是按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;

acceptVisitor按OrganisationMode3种方式分别调用内部接口acceptVisitorGrouped、

acceptVisitorDescending和acceptVisitorAscending。
switch(om)
{
case OM_PASS_GROUP:
     acceptVisitorGrouped(visitor);
     break;
case OM_SORT_DESCENDING:
     acceptVisitorDescending(visitor);
     break;
case OM_SORT_ASCENDING:
     acceptVisitorAscending(visitor);
     break;
}

而acceptVisitorGrouped、acceptVisitorDescending和acceptVisitorAscending。内部调用如下

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通过WinMain或main调用go再通过Root调用startRendering进行消息循环,然后调用renderOneFrame,通过RenderSystem的_updateAllRenderTargets方法,更新所有的RenderTarget。RenderTarget通过update方法更新与之关联的Viewport并产生FPS统计信息。而Viewport则调用与之关联的Camera的_renderScene方法进行渲染,Camera此时把“球”踢给SceneManager。进入SceneManager的renderScene成员函数中后,在经过计算后,把需要渲染的场景送给RenderSystem去做真正的渲染,此时我们可以看到熟悉的_breginFrame和_endFrame。 一直下去经过RenderQueue、RenderQueueGroup、RenderPriorityGroup、QueuedRenderableCollection再通过访问者到达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. RenderQueueListenerclass _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)
}

fireRenderQueueStarted和fireRenderQueueEnded中遍列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)

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

enum SpecialCaseRenderQueueMode{
     SCRQM_INCLUDE,    只渲染Special Case
     SCRQM_EXCLUDE  不渲染Special Case
};

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

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);

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值