ogre中文:ogre的主要渲染流程



很早以前就想写些有关OGRE文章了直没机会
理解个渲染引擎我觉得最重要是先抓住了它主架构主线渲染流程不然个引擎几万行甚至几十万行代码光是打开solution就能吓你跳了OGRE也有十几万行代码量开始看它时候也是无从下手感觉代码太多了不知道从哪开始看好这个看看那个看看由于对整个引擎没有个清晰认识看过了也印象不深所以最后还是决定先找出它主线了解它渲染流程这样才能有机地把各个部分联系起来

这篇短文也是对OGRE主要渲染流程个介绍可能对不会太多地去介绍具体实现细节我所用代码都是取自于OGRE最新CVS版本

读者最好对OGRE有了解至少得看懂它example不然可能些东西理解起来比较困难对D3DOPENGL有定了解更好

如果你看过D3DSDK中带例子定知道个比较简单3D要运行起来至少都会涉及以下几部分:

首先是数据来源包括顶点数据纹理数据等这些数据可以从文件中读取也可以在运行时生成

接下来我们会建立顶点缓冲区把顶点保存起来建立texture对象来表示texture对顶点组成物体设置它在世界坐标系下坐标设置摄像机位置视点设置viewport位置和大小然后就可以在渲染循环中开始渲染操作了经过了frontbuffer和backbuffer交换我们就能在屏幕上看到3D图形了伪代码如下:

upVertexBuffer

WorldTransform

Camera

ProjectionTransform

Viewport

beginFrame

Texture

drawObject

endFrame

以下就是渲染个物体主要步骤在我看来这就是3D主线同样道理无论你多复杂渲染引擎都得实现上述这些步骤其他些效果如阴影光照等都是附着在这条主线上所以如果你能在你所研究渲染引擎上也清晰地看到这条主线可能对你深入地研究它会大有帮助下面我们就起来找到OGRE中这条主线

OGRE渲染循环都是起源于Root::renderOneFrame这个在OGRE自带example中是不会显式example都了Root::startRendering由startRendering来renderOneFrame如果你用OGRE来写真正游戏或者编辑器你可能就需要在消息主循环中renderOneFrame了顾名思义这个就是对整个OGRE进行更新包括动画渲染状态改变渲染api在这个会包括了我们上述伪代码几乎全部内容所以是本文重点所在

进入renderOneFrame可以看到头尾两个fire这种在OGRE中经常出现般都是fire…start和fire…end起出现在这些可能会处理些用户自定义操作如_fireFrameStarted就会对所以frameListener进行处理这些fire可以暂时不用理会继续看_updateAllRenderTargets在这个会委派当前所用renderer对所有创建出来rendertarget进行updaterendertarget也就是渲染般会有两种种是rendertexture种是renderbuffer接着进入Render::_updateAllRenderTargets可以看到在rendersystem中对创建出来rendertarget是用RenderTargetPriorityMap来保存以便按照顺序来对rendertarget进行update在渲染物体到renderbuffer时般会用到的前渲染好rendertexture所以rendertexture形式rendertarget需要在renderbuffer的前进行更新

进入rendertargetupdate可以看到它仍然把update操作继续传递下去所有挂在这个rendertarget上viewportupdate

Viewport其实就是定义了rendertarget上块要进行更新区域所以个rendertarget是可以挂多个viewport以实现多人对战时分屏或者是画中画等效果可以把OGRE中viewport看成是保存camera和rendertarget这两者组合把viewport中所定义camera所看到场景内容渲染到viewport所定义rendertarget区域里

Viewport还有个重要信息是ZOrder可以看到RenderTarget中ViewportList带有个比较所以在RenderTarget::update中ZOrder越小越先被渲染所以如果两个viewport所定义区域互相重叠了而且ZOrder又不最终效果就是ZOrder小viewport内容会被ZOrder大viewport内容所覆盖

继续进入Viewport::update就像前面所说它所引用camera来渲染整个场景而在Camera::_renderScene中SceneManager::_renderScene(Camera*camera,Viewport*vp,boolOverlays)SceneManager::_renderScene里就是具体渲染流程了名称还有参数也可以看出来这个作用就是利用所指定camera和viewport来把场景中内容渲染到viewport所指定rendertarget某块区域中根据camera我们可以定出viewmatrixprojectionmatrix还可以进行视锥剔除只渲染看得见物体注意我们这里只看标准SceneManager思路方法不看BspSceneManager派生类思路方法而且我们会抛开跟主线无关内容如对shadowup骨骼动画播放shader参数传递等我们只注重渲染主流程



在SceneManager::_renderScene中所应看个重要是_updateSceneGraphOGRE对场景组织是通过节点树来组织个节点你可以看成是空间中某些变换组合如位置缩放旋转等这些变换会作用到挂接在这些节点上具体物体信息也就是说节点保存了worldtransform对具体物体个人在空间中定位都是通过操作节点来完成同时节点还保存了个世界坐标AABB这个AABB能容纳所有它所挂接物体大小主要是用于视锥裁减如果当前摄像机看不见某个节点AABB那么介绍说明摄像机看不见节点所挂接所有物体所以在渲染时可以对这个节点视而不见

_updateSceneGraph内部处理比较繁琐我们只需知道经过了_updateSceneGraph场景节点树中每个节点都经过了更新包括位置缩放和方位还有节点包围盒

继续回到SceneManager::_renderScene接下来要看Viewport它会具体rendererviewport操作设置viewport中所挂接rendertarget为当前所要渲染目标viewport中区域为当前所要渲染目标中区域

接下来要碰到OGRE渲染流程中个重要概念RenderQueue这个东西实在内容比较多还是以后有机会单独提出来说吧你可以简单把它想成是个容器里面元素就是renderable每个renderable可以看成是每次drawprimitive所渲染物体可以是个模型也可以是模型部分在RenderQueue中它会按材质来分组这些renderable还会对renderable进行排序

在每SceneManager::_renderScene时都会SceneManager::prepareRenderQueue来清理RenderQueue然后再SceneManager::__findVisibleObjects来把当前摄像机所能看见物体都加入到RenderQueue中

SceneManager::__findVisibleObjects是个递归处理过程它从场景根节点开始先检查摄像机是否能看见这个节点包围盒(包围盒在_updateSceneGraph时已经计算好了)如果看不见那么这个节点还有它子节点都不用管了如果能看见再检测挂在这个节点上所有MovableObject如果当前所检测MovableObject是可见就会_updateRenderQueue思路方法般在这个思路方法里就可以把和这个MovableObject相关renderable送入RenderQueue了

这里要说说MovableObjectMovableObject主要是用于表示场景中离散物体如Entity顾名思义能移动物体不过它“能移动”这个能力是要通过SceneNode来实现所以MovableObject来能显示出来首先得先挂接在某个场景节点上通过场景节点来定位你可以控制MovableObject些属性如某个MovableObject是否要显示是否要隐藏都可以通过MovableObject::Visible思路方法来实现

检测完该节点上MovableObject的后就继续所有子节点_findVisibleObjects思路方法直递归下去这样就能把场景中所有要渲染renderable所加入到RenderQueue中了

至此我们就拥有了要渲染物体信息了接下来就是对这些物体进行渲染了你会发现跟D3D或OpenGL代码很类似:

mDestRender->clearFrameBuffer

mDestRender->_beginFrame

mDestRender->_ProjectionMatrix

mDestRender->_ViewMatrix

_renderVisibleObjects;

mDestRender->_endFrame;

这些api作用和D3D中类似作用都差不多这里再说下_renderVisibleObjects在这个会对RenderQueue中每个renderable进行渲染是visitor模式来遍历操作每个renderable最终在SceneManager::renderSingleObject中取出每个renderable所保存顶点索引世界矩阵等信息来进行渲染这其中还包括了查找离该renderable最近光源等操作比较复杂

到这里SceneManager::_renderScene流程基本走完了也就是说OGRE帧中渲染流程差不多也结束了你应该也发现这个流程跟你用D3D写个简单流程基本是在这个流程基础上再去看具体实现如如何样设置纹理如何样你熟悉D3D或OpenGLAPI来渲染物体应该会简单得多

对OGRE渲染流程大概介绍到这里也结束了很多细节都没涉及以后有机会再写吧



Tags:  ogre编辑器 ogre引擎 ogre于mfc结合 ogre中文

延伸阅读

最新评论

发表评论