Ogre的渲染流程解析

使用OpenGL渲染物体所需流程

  1. 设置顶点数据,贴图数据:这一步可以封装成读取网格数据(mesh)以及其对应的贴图操作
  2. 清理颜色缓冲、深度缓冲等
  3. 设置shader并传入其所需的参数(模型变换矩阵,观察矩阵,投影矩阵,光照信息)
  4. 绘制顶点并交换窗口缓冲

Ogre渲染流程

Root开启渲染循环

一般由应用程序调用root->startRendering(void)开启渲染循环。

void Root::startRendering(void)
{
         ...
        //游戏渲染循环是一个无限循环,除非被frame listeners或者queueEndRendering()终止
        mQueuedEnd = false;

        while( !mQueuedEnd )
        {
           ...
           if (!renderOneFrame())
                break;
        }
}

在renderOneFrame函数中,我们获得root对应的RenderSystem,并调用RenderSystem实例中所有的RenderTarget的渲染接口。

RenderTarget

RenderTarget可以是窗口,也可以是渲染到纹理。

在RenderTarget的渲染接口中,RenderTarget会调用其所有的ViewPort的渲染接口,一个RenderTarget对应着多个Viewport。

ViewPort

ViewPort是窗口中被更新的地方,一个窗口可以有多个ViewPort,多个Viewport可以在一个窗口中。例如下图中只有一个窗口(RenderTarget),但是却有三个Viewport。
在这里插入图片描述
一个ViewPort对应着一个Camera引用,渲染调用传递从ViewPort传递到Camera。

Camera

Camera定义了渲染流程中所需的观察矩阵、投影矩阵,是游戏场景玩家观察世界的位置和方向。每一个Camera对应一个SceneManager,渲染调用进而传递到SceneManager

SceneManager

Ogre中,场景定义了一个游戏世界的组织,比如说主角在哪,怪物的出生点在哪,目的地在哪,可以类比Unity中的scene。Ogre中场景的组织是由一个根场景节点(Root SceneNode)来描述,每个SceneManager都持有一个根场景节点的引用。

因此每一个场景对应一个SceneManager,其负责场景物体的创建和删除,以及进行场景查询和调用渲染队列的渲染。

其中,场景查询的作用为决定哪些对象被送入到RenderSystem中进行渲染,通过减少需要渲染的物体来获得更好的渲染性能表现。

渲染调用传递到SceneManager的_renderScene函数,该函数会更新场景的变换信息(Transform)以及进行场景查询的操作:

SceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays)
{
    ...
    //更新场景的变换信息
    _updateSceneGraph(camera);
    ...
    //清空渲染队列
    prepareRenderQueue();
    ...
    //场景查询
    _findVisibleObjects(camera, &(camVisObjIt->second),
                mIlluminationStage == IRS_RENDER_TO_TEXTURE? true : false);
    ...
    
}

其中_renderScene中会调用__updateSceneGraph函数更新整个场景的变换信息:

void SceneManager::_updateSceneGraph(Camera* cam)
{
    ...
    // Cascade down the graph updating transforms & world bounds
    // ...
    getRootSceneNode()->_update(true, false);
    ...
}

RenderQueue

接下来一个重要的概念RenderQueue。可以简单把它想成是一个容器,里面的元素就是Renderable,每个Renderable可以看成是一次渲染过程中渲染一个物体所需的基本属性:顶点数据,纹理数据,光照信息,材质属性,变换矩阵等。在RenderQueue中,它会按材质Material来分组这些Renderable,还会对Renderable进行一定规则的排序。之所以这么做,是因为使用相同材质的Material会使用同样的Shader,通过减少Shader切换的频率可以达到优化渲染效率的作用。

Renderable

Renderable对象是OGRE中所有可渲染对象的抽象接口。这个接口的实现类必须是基于单一的材质、单一的世界矩阵。每一个Renderable对象封装了一个物体渲染所需的基本信息:顶点数据,纹理数据,光照信息,材质属性,变换矩阵等。

传入顶点数据,贴图数据,模型变换矩阵

对比OpenGL渲染流程,在Ogre中我们是如何将顶点数据、贴图数据等传入渲染管线中的呢?

从前面的分析中可以看到,Renderable提供了一个物体渲染所需的基本信息。

在实际Ogre框架的使用过程中,我们是用Mesh等类去存储网格信息,并在场景中实例化为Entity,其中Entity是由SubEntity组成,SubEntity继承自Renderable。场景中每个Entity都会attach到一个SceneNode上,前文中的SceneManager::_renderScene中的_updateSceneGraph函数将遍历场景所有的节点的变换信息,在这个过程中,每个SceneNode将会遍历附加在它上面的MoveableObject列表,然后遍历每个MoveableObject所有的SubEntity并将其加入到RenderQueue中。

而SceneNode代表的是游戏场景中的变换信息,故其包含了挂载在其上的Renderable所需的模型变换矩阵。

Ogre在读取Mesh的时候,不仅读入了网格信息,还会读取网格依赖的纹理信息,故上述步骤完成了顶点数据、贴图数据的读入。

清理颜色缓冲、深度缓冲

在SceneManager::_renderScene函数中,当执行完场景查询之后,我们会清理当前视口的颜色缓冲、深度缓冲等:

    ...
    // Clear the viewport if required
    if (mCurrentViewport->getClearEveryFrame())
    {
        mDestRenderSystem->clearFrameBuffer(
            mCurrentViewport->getClearBuffers(), 
            mCurrentViewport->getBackgroundColour(),
            mCurrentViewport->getDepthClear() );
    }        
    ...
    

设置投影和观察矩阵

在SceneManager::renderScene函数中,当执行完颜色缓冲、深度缓冲的清理调用函数后,我们会设置投影矩阵、观察矩阵,然后就开始调用 renderVisibleObjects函数:

   ...
   // Set initial camera state
    mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrixRS());
    mCachedViewMatrix = mCameraInProgress->getViewMatrix(true);
    ...
    setViewMatrix(mCachedViewMatrix);
    ...
    // Render scene content
    {
        ...
        _renderVisibleObjects();
    }

光照信息

光源继承自Moveable Object,也是属于场景信息的一部分。不同的是,光源会影响场景其他物体的颜色。那么光照信息是如何传到渲染管线中的呢?

可以看到Renderable类提供了queryLights接口,该函数会传递到SceneNode的findLights函数,并进一步传递到SceneManager的_populateLightsList函数,而SceneManager中可以查到整个场景的信息,包括各个光源Light对象的引用。

参考

Ogre渲染主循环内部流程简介:http://gad.qq.com/article/detail/14402

OGRE内部渲染循环: http://blog.sina.com.cn/lucyloveayu

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值