Ogre的基本渲染流程

一个基于dx的2D端游客户端程序猿的忧虑。
想从学习Ogre引擎中学习3D引擎渲染知识!学习模式设计!学习很多东西!
从零基础第一篇了解下Ogre的基本渲染流程(不对之处还请指出)

在这里插入图片描述
渲染的过程一般是:
1、 设置物体顶点 – Vertex更新
2、 设置空间变换 – Transform更新
3、 设置Camera和投影视口变换 – Viewport更新
4、 设置纹理数据 – Texture更新
5、 使用需要的Gpu Shader,开始渲染,管线执行,
重复上述步骤,绘制所有物体
最后,绘制完一帧提交渲染结果

启动

INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR cmdLine, INT)
{
  OgreBites::SampleBrowser brows (nograb, startUpSampleIdx);
        brows.go();
}

开始循环

class SampleContext : public ApplicationContext, public InputListener
{
virtual void go(Sample* initialSample = 0)
        {
            while (!mLastRun)
            {
                mLastRun = true;  // assume this is our last run
                initApp();
                loadStartUpSample();
                if (mRoot->getRenderSystem() != NULL)
                {
                    mRoot->startRendering();    // start the render loop
                }
                closeApp();
                mFirstRun = false;
            }
        }
};

开始更新

void Root::startRendering(void)
    {
        OgreAssert(mActiveRenderer != 0, "no RenderSystem");
        mActiveRenderer->_initRenderTargets();
        // Clear event times
        clearEventTimes();
        // Infinite loop, until broken out of by frame listeners
        // or break out by calling queueEndRendering()
        mQueuedEnd = false;
        while( !mQueuedEnd )
        {
            if (!renderOneFrame())
                break;
        }
    }

一帧的更新
renderOneFrame有两个fire函数,给用户以渲染前后的一些回调,如_fireFrameStarted就会对所以的frameListener进行处理

   bool Root::renderOneFrame(void)
    {
        if(!_fireFrameStarted())
            return false;
        if (!_updateAllRenderTargets())
            return false;
        return _fireFrameEnded();
    }

// Update all in order of priority
// This ensures render-to-texture targets get updated before render windows
// 根据优先级更新所有内容,确保在渲染到窗口之前更新渲染到纹理的对象
// 渲染物体到RenderBuffer时,一般会用到之前渲染好的RenderTexture,RenderTexture形式的RenderTarget需要在RenderBuffer之前进行更新。

常规的渲染操作都是直接将场景呈现到backbuffer中的,backbuffer说白了其实就是一个表面,再说白了就是一块内存,场景通过绘制函数载入显存后,再通过Present函数送至显示器。那么为什么

还要渲染到纹理呢?这是为了实现一些特殊的效果,比如常见的环境映射,简单的说,想象你有一个光滑的球体,它应该是可以反射周围环境的,这就是环境映射。

上面说了常规的渲染操作是将场景送至backbuffer,而backbuffer实际上是一个Surface,而纹理恰恰又包含了Surface,所以我们只需要取得纹理的Surface,其次将场景送至这个Surface,最后再把
这个纹理渲染到backbuffer中即可。举个例子,假设你要在一面墙壁上画一幅画,你有两种方法
1 直接在墙上画,这个很好理解,就对应常规的backbuffer渲染。
2 先将画绘制在纸上,然后将纸贴到墙上,这就对应渲染到纹理的过程。
这里墙壁相当于backbuffer,而纸张相当于纹理的Surface,在纸上作画相当于渲染到纹理,把纸贴到墙上相当于把纹理渲染到backbuffer。具体的步骤如下
1 创建纹理并获得纹理的表面(Surface)
2 向纹理的表面渲染场景
3 渲染纹理本身

 bool Root::_updateAllRenderTargets(void)
    {
		...
        mActiveRenderer->_updateAllRenderTargets(false);
        ...
        mActiveRenderer->_swapAllRenderTargetBuffers();
        ...
    }

更新全部渲染对象

void RenderSystem::_updateAllRenderTargets(bool swapBuffers)
{
    // Update all in order of priority
    // This ensures render-to-texture targets get updated before render windows
    RenderTargetPriorityMap::iterator itarg, itargend;
    itargend = mPrioritisedRenderTargets.end();
    for( itarg = mPrioritisedRenderTargets.begin(); itarg != itargend; ++itarg  )
    {
        if( itarg->second->isActive() && itarg->second->isAutoUpdated())
            itarg->second->update(swapBuffers);
    }
}

void RenderTarget::update(bool swap)
    {
        ...
        updateImpl();
   		...
    }

    void RenderTarget::updateImpl(void)
    {
      	...
        _updateAutoUpdatedViewports(true);
      	...
    }

更新自动更新的视口
Viewport其实就是定义了某RenderTarget上的一块要进行更新的区域,所以一个RenderTarget是可以包含多个Viewport。多个viewport就可以在画面中开多个窗口。

void RenderTarget::_updateAutoUpdatedViewports(bool updateStatistics)
{
    // Go through viewports in Z-order
    // Tell each to refresh
    ViewportList::iterator it = mViewportList.begin();
    while (it != mViewportList.end())
    {
        Viewport* viewport = (*it).second;
        if(viewport->isAutoUpdated())
        {
            _updateViewport(viewport,updateStatistics);
        }
        ++it;
    }
}

更新视口
在Ogre中,Viewport看成是保存Camera和RenderTarget这两者的组合;渲染时把Viewport中Camera拍摄到的东西渲染到RenderTarget上。Viewport有一个ZOrder的属性,ZOrder越小的,越先被渲染。如果两个Viewport区域重合,Zorder大的最后会覆盖掉Zorder小的内容。

void RenderTarget::_updateViewport(Viewport* viewport, bool updateStatistics)
{
	...
    viewport->update();
    ...
}

  void Viewport::update(void)
    {
			...
            mCamera->_renderScene(this, mShowOverlays);
			...
    }

场景渲染流程

void Camera::_renderScene(Viewport *vp, bool includeOverlays)
    {
		...
        //render scene
        mSceneMgr->_renderScene(this, vp, includeOverlays);
	  ...
    }

真正的场景渲染流程开始
利用所指定的Camera和Viewport,来把场景中的内容渲染到Viewport所指定的RenderTarget的某块区域中。
根据Camera,可以获取计算出View Matrix与Projection Matrix,还可以进行视锥体的剔除与裁剪,另外,可以只渲染Camera可见的物体。
_renderScene的任务比较多,一些特效的计算更新也放入其中

void SceneManager::_renderScene(Camera* camera, Viewport* vp, bool  includeOverlays)
{
			 ...
            _updateSceneGraph(camera);
         	 ...
        	setViewport(vp);
			...
            OgreProfileGroup("prepareRenderQueue", OGREPROF_GENERAL);
            prepareRenderQueue();
			...
            _findVisibleObjects(camera, &(camVisObjIt->second),
         	...
            _renderVisibleObjects();
 			...
}

第一个重要函数是_updateSceneGraph( 场景中的每个节点都经过了更新,包括位置,缩放,旋转,还有节点的包围盒AABB)
Scene的更新从根Node开始。在Ogre中,Scene图是用Node节点来进行组织的,Node之间有父子关系,有一个根节点。所有的物体都需要挂接在某个Node上,任何一个Node可以进行位置,缩放,旋转的空间变换;并且会作用到挂接在这些节点上的具体的物体上,也就是说,Node保存了全局的World Transform。对于任何一个物体来说,操作Node的空间变换,物体也进行响应的空间变换。
Node节点还保存了AABB(包装盒),这个包装盒是一个包含Node上的所有物体的一个立体空间,它的主要是用于视锥体裁减的,如果Camera看不见某个节点的AABB,那么说明Camera就看不见Node上所挂接的所有物体,在渲染时可以忽略掉这个Node。

void SceneManager::_updateSceneGraph(Camera* cam)
{
	...
    getRootSceneNode()->_update(true, false);
    ...
}

接下来重要的是setViewport,设置Viewport中所包含的RenderTarget为当前所要渲染的目标,而Viewport中的区域为当前所要渲染的目标区域。

void SceneManager::setViewport(Viewport* vp)
{
   ...
}

接下来一个重要的概念RenderQueue。可以简单把它想成是一个容器,里面的元素就是Renderable,每个Renderable可以看成是每次绘制时需要渲染的物体,可以是一个模型,也可以是模型的一部分。在RenderQueue中,它会按材质Material来分组这些Renderable,还会对Renderable进行一定规则的排序。
RenderQueue 渲染队列,确保正确的渲染顺序和提高渲染效率,将相同的Pass的物体一起进行渲染,尽可能降低了渲染状态的切换。
RenderQueue
RenderQueueGroup(RenderQueueGroupMap) 根据RenderQueueGroupID分组,代表Objects的渲染顺序,主要包括天空盒、地形、界面等
RenderPriorityGroup(PriorityMap) 根据UShort的值分组,代表渲染的优先级,不指定id会加到默认的组,值为100
QueueRenderableCollection 存储Renderable和Pass的最终场所,通过多种排序实现Renderable 和Pass的有序化,排序包括小于排序,深度递减排序和基数排序
RenderableList(SolidRenderablePassMap) 根据PassGroupLess的值分组,组织Renderable和Pass,有三种,分别是按Pass分组,按与Camera的距离升序和按与Camera的距离降序
Renderable
在每一次调用SceneManager::_renderScene时,都会调用SceneManager::prepareRenderQueue来清理RenderQueue

void SceneManager::prepareRenderQueue(void)
{
 ...
}

然后再调用SceneManager::_findVisibleObjects来把当前摄像机所能看见的物体都加入到RenderQueue中。

void SceneManager::_findVisibleObjects(
    Camera* cam, VisibleObjectsBoundsInfo* visibleBounds, bool onlyShadowCasters)
{
 ...
}

环境准备好了开始渲染

void SceneManager::_renderVisibleObjects(void)
{
	...
    renderVisibleObjectsDefaultSequence();
    ...
}

RenderQueue、RenderQueueGroup、RenderPriorityGroup都是管理器,正在的容器是QueueRenderableCollection

void SceneManager::renderVisibleObjectsDefaultSequence(void)
{
	...
    _renderQueueGroupObjects(pGroup,  QueuedRenderableCollection::OM_PASS_GROUP);
    ...
}


void SceneManager::_renderQueueGroupObjects(RenderQueueGroup* pGroup,
                                           QueuedRenderableCollection::OrganisationMode  om)
{
	...
    renderBasicQueueGroupObjects(pGroup, om);
}



void SceneManager::renderBasicQueueGroupObjects(RenderQueueGroup* pGroup,
                                                 QueuedRenderableCollection::OrganisationMode om)
{
  ...
  renderObjects(pPriorityGrp->getSolidsBasic(), om, true, true);
  // Do unsorted transparents
  renderObjects(pPriorityGrp->getTransparentsUnsorted(), om, true, true);
  // Do transparents (always descending)
  renderObjects(pPriorityGrp->getTransparents(),
  ...
}

对每个Renderable进行渲染

void SceneManager::renderObjects(const QueuedRenderableCollection& objs,
                                 QueuedRenderableCollection::OrganisationMode om,
                                 bool lightScissoringClipping,
                                 bool doLightIteration,
                                 const LightList* manualLightList,
                                 bool transparentShadowCastersMode)
{
	...
    objs.acceptVisitor(mActiveQueuedRenderableVisitor, om);
    ...
}

根据不同的组织规则进行渲染

void QueuedRenderableCollection::acceptVisitor(
    QueuedRenderableVisitor* visitor, OrganisationMode om) const
{
	...
    switch(om)
    {
    case OM_PASS_GROUP:
        acceptVisitorGrouped(visitor);
        break;
    case OM_SORT_DESCENDING:
        acceptVisitorDescending(visitor);
        break;
    case OM_SORT_ASCENDING:
        acceptVisitorAscending(visitor);
        break;
    }
    
}

//-----------------------------------------------------------------------
void QueuedRenderableCollection::acceptVisitorGrouped(
    QueuedRenderableVisitor* visitor) const
{
   ...
   visitor->visit(ipass->first,  const_cast<RenderableList&>(ipass->second));
   ...
}

//-----------------------------------------------------------------------
void QueuedRenderableCollection::acceptVisitorDescending(
    QueuedRenderableVisitor* visitor) const
{
  	...
  	visitor->visit(const_cast<RenderablePass*>(&(*i)));
	...
}

//-----------------------------------------------------------------------
void QueuedRenderableCollection::acceptVisitorAscending(
    QueuedRenderableVisitor* visitor) const
{
    ...
    visitor->visit(const_cast<RenderablePass*>(&(*i)));
    ...
}

最终在SceneManager::renderSingleObject中取出每个Renderable所保存的顶点、世界矩阵等信息来进行渲染

void SceneManager::SceneMgrQueuedRenderableVisitor::visit(RenderablePass* rp)
{
		...
        targetSceneMgr->renderSingleObject(rp->renderable, mUsedPass, scissoring,
            autoLights, manualLightList);
		...
}


void SceneManager::renderSingleObject(Renderable* rend, const Pass* pass,
                                      bool lightScissoringClipping, bool doLightIteration,
                                      const LightList* manualLightList)
{
   ...
    // Reset view / projection changes if any
    resetViewProjMode(passTransformState);
   ...
}


    void SceneManager::issueRenderWithLights(Renderable* rend, const Pass* pass,
                                             const LightList* pLightListToUse, bool  fixedFunction,
                                             bool lightScissoringClipping)
    {
	   ...
        _issueRenderOp(rend, pass);
	   ...
    }

选择当前的渲染系统进行渲染(dx9 dx11 OpenGL)

    void SceneManager::_issueRenderOp(Renderable* rend, const Pass* pass)
    {
	   ...
       mDestRenderSystem->_render(ro);
	   ...
    }

   void RenderSystem::_render(const RenderOperation& op)
    {
     ...
    }
发布了7 篇原创文章 · 获赞 2 · 访问量 1201

猜你喜欢

转载自blog.csdn.net/xyxsuoer/article/details/89706958