(原创)OGRE主要渲染流程简介

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

                        OGRE主要渲染流程简介

                                    谢伟亮       feiyurainy@163.com

                               转载请注明出处

    很早以前就想写一些关于OGRE的文章了,一直没机会。

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

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

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

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

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

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

      setupVertexBuffer

      setWorldTransform

      setCamera

      setProjectionTransform

      setViewport

       beginFrame

      setTexture

      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对所有创建出来的render target进行update,render target也就是渲染的目的地,一般会有两种,一种是render texture,一种是render buffer,接着进入RenderSystem::_updateAllRenderTargets,可以看到在render system中,对创建出来的render target是用RenderTargetPriorityMap来保存的,以便按照一定的顺序来对render target进行update,因为在渲染物体到render buffer时,一般会用到之前渲染好的render texture,所以render texture形式的render target需要在render buffer之前进行更新。

     进入render target的update,可以看到,它仍然把update操作继续传递下去,调用所有挂在这个render target上的viewport的update。

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

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

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

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

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

     继续回到SceneManager::_renderScene,接下来要看的是setViewport,它会调用具体的renderer的setviewport的操作,设置viewport中所挂接的render target为当前所要渲染的目标,viewport中的区域为当前所要渲染的目标中的区域。

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

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

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

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

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

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

       mDestRenderSystem->clearFrameBuffer

      mDestRenderSystem->_beginFrame   

       mDestRenderSystem->_setProjectionMatrix

       mDestRenderSystem->_setViewMatrix

       _renderVisibleObjects();

      mDestRenderSystem->_endFrame();

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

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

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

 
OGRE与Qt的结合(一)----使用OGRE渲染QWidget 最近几天开始重新学习Ogre,这次从源码编译了Ogre2.1,编译过程基本跟Ogre1.8.1类似,连第三方依赖库都是用的官网推荐的以前版本的,此处不多说了,网上有很多教程,现在给出下载连接。          Ogre2.1的源码:  https://bitbucket.org/sinbad/ogre/branch/v2-1          Dependencies: https://bi 阅读详情

相关推荐

Ogre学习笔记(3):Mesh的渲染流程

       首先一个Entity对象必须Attach到一个SceneNode。1.  创建一个SceneNode:SceneManager::getRootSceneNode() (在SceneManager::init时会创建一个RootNode)à SceneNode::createChildSceneNode()àNode::createChild()主要的操作在这个函数中完成,首先调

燕良@游戏开发 8330

帮助理解 Ogre 源码体系结构的几张图片

Ogre 类关系图,一帧渲染流程图,结构图,对理解Ogre源码有帮助。

OGRE引擎基础RPG游戏开发探索

OGRE(面向对象的图形渲染引擎)是一个高级的C++开源框架,用于创建3D图形应用程序。OGRE以解耦、组件化和场景图管理为特点,为开发者提供了一个直观和灵活的平台,以减少直接与底层图形API打交道的复杂性。它的应用范围非常广泛,从游戏开发到视觉仿真、虚拟现实等,都是其潜在的使用场景。OGRE支持多种编程语言,并且拥有一个活跃的社区,不断为其贡献各种扩展插件和工具,进一步提高了开发效率和质量。

weixin_35756130的博客 1035

OGRE引擎介绍,基础知识

关于OGRE引擎的介绍,了解性的知识,从别的地方总结的

OGRE的良好架构

OGRE独立于平台(windows or linux or MacOS),独立于3D接口(Direct3D和OpenGL),独立于场景类型(不论是室内场景还是室外场景)。OGRE中没有对窗体类型的依赖,没有假定你使用那种接口,没有预先假定你将于创建的场景的类型。所有3D方面的概念都是基于核心的数学描述而不是某种特殊的应用程序接口。       当然OGRE必须处理底层的平台特性,接口和场景,但这

a936676463的专栏 1846

【亲测免费】 探秘Ogre:一款强大的3D渲染引擎

是一个开源的、跨平台的实时3D图形渲染引擎,专为游戏开发和专业可视化应用设计。它的目标是简化复杂3D场景的构建与管理,让开发者可以专注于创新,而不是底层图形API。本文将带你了解Ogre的核心技术特性,应用场景,以及为何你应该考虑在你的项目中使用它。 ## 项目简介 Ogre始于2001年,由Steve Jackson创立,其名字来源于“OGRE”,这是一个早期的MUD(多用户地下城)游戏中的...

gitblog_00078的博客 1661

OGRE源码深度解析:3D图形编程的内核揭秘

OGRE的核心架构建立在几个关键的抽象层之上,包括场景管理、渲染系统、资源管理、脚本系统以及插件系统。这些组成部分是独立的,它们通过一个统一的接口与应用逻辑层交互。OGRE的这种模块化设计允许开发者根据需要轻松替换或扩展特定功能。开发一个自定义的OGRE插件需要遵循以下步骤:定义接口:首先需要确定插件需要提供哪些功能,并定义相应的接口。实现插件逻辑:根据定义的接口实现插件的具体逻辑。例如,实现一个自定义的渲染器插件需要继承并重写特定的渲染相关的接口。集成到OGRE

weixin_31185473的博客 515

ogre主要渲染流程

ogre主要渲染流程          很早以前就想写一些关于OGRE的文章了,一直没机会。 理解一个渲染引擎,我觉得最重要的是先抓住了它的主架构,它的主线,渲染流程,不然的话,一个引擎几万行,甚至几十万行的代码,光是打开solution就能吓你一跳了,OGRE也有十几万行的代码量,我一开始看它的时候也是无从下手,感觉代码太多了,不知道从哪开始看好,这个class看看,那个class看看,由于对

Only me 1267

OGRE主要渲染流程简介

转载自: http://blog.csdn.net/rainini/article/details/2000778   OGRE主要渲染流程简介                                     谢伟亮       feiyurainy@163.com                                转载请注明出处     很

lynon的专栏 261

OGRE主要渲染流程简介(转)

很想写点什么,可是心乱如麻,实在写不出什么, 无奈,先借借别人的吧,以后自己再做总结。 http://www.cppblog.com/zhuyeaini/archive/2011/01/08/138159.aspx ogre渲染流程: 1. _fireFrameStarted() 2. 按某种优先级更新所有渲染目标 2.1 firePreUpdate()...

aigao1992的博客 234

Ogre的基本渲染流程

一个基于dx的2D端游客户端程序猿的忧虑。 想从学习Ogre引擎中学习3D引擎渲染知识!学习模式设计!学习很多东西! 从零基础第一篇了解下Ogre的基本渲染流程(不对之处还请指出) 渲染的过程一般是: 1、 设置物体顶点 – Vertex更新 2、 设置空间变换 – Transform更新 3、 设置Camera和投影视口变换 – Viewport更新 4、 设置纹理数据 – Texture更新...

xyxsuoer的博客 1262

Ogre内部渲染流程分析系列

关于 OGRE 中的 Renderable     要理解OGRE引擎,就要理解其中占很重要位置的 Renderable接口,今天先将一部分我分析的内容贴出来。 以下是 Ogre 的代码中的详细说明: Renderable是OGRE中所有可渲染对象的抽象接口 这个接口抽象出了在渲染管线中的被分组的离散的可渲染对象基本的方法。 此接口的实现类必须是基于单一的材质、单一的世

把握自己。 4766

ogre渲染流程

<br />ogre主要渲染流程 <br /><br /><br /> 很早以前就想写一些关于OGRE的文章了,一直没机会。 <br />理解一个渲染引擎,我觉得最重要的是先抓住了它的主架构,它的主线,渲染流程,不然的话,一个引擎几万行,甚至几十万行的代码,光是打开solution就能吓你一跳了,OGRE也有十几万行的代码量,我一开始看它的时候也是无从下手,感觉代码太多了,不知道从哪开始看好,这个class看看,那个class看看,由于对整个引擎没有一个清晰的认识,看过了也印象不深,所以,最

xuqian6307的专栏 644

Ogre 渲染流程

ogre中,调用renderOneFrame就是渲染一帧的画面, 所以要了解Ogre渲染流程就直接单步调试跟着renderOneFrame走就好了。 本文以调用栈的方式展示ogre渲染流程,由于调用栈是在太深,所以会根据功能分块描述渲染进行到哪一步。 1. renderOneFrame 下面是主要调用堆栈,这部分主要描述了:所谓渲染实际上就是更新视口的画面,而画面则来自与视口绑定的摄像机所看到的...

A.A的博客 605

【转】OGRE渲染主干 [Ogre渲染流程]

来源:http://school.ogdev.net/ListShow.asp?ListType=1&TypeID=8 很早以前就想写一些关于OGRE的文章了,一直没机会。 理解一个渲染引擎,我觉得最重要的是先抓住了它的主架构,它的主线,渲染流程,不然的话,一个引擎几万行,甚至几十万行的代码,光是打开solution就能吓你一跳了,OGRE也有十几万行的代码量,我一...

diaoqu4574的博客 143
上一篇: (原创)bls文件格式的解析
下一篇: (原创)后置++在不同编译器中的行为
RAINini
博客等级 码龄22年 11粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值