首先一个
Entity
对象必须
Attach
到一个
SceneNode
。
1.
创建一个
SceneNode
:
SceneManager::getRootSceneNode()
(在
SceneManager::init
时会创建一个
RootNode
)
à
SceneNode::createChildSceneNode()
à
Node::createChild()
主要的操作在这个函数中完成,首先调用虚函数
SceneNode::createChildImpl
(),此函数又会调用
OctreeSceneManager::createSceneNode
(),此函数会
new
一个
SceneNode
的派生类对象,这里是
OctreeNode
,并加入到
SceneNodeList mSceneNodes
中;随后又进行了坐标变换;最后将此指针又加入到
ChildNodeMap mChildren
中,然后返回此指针;
2.
将
Entity Attach
到
SceneNode
:
SceneNode:: attachObject()
;
3.
渲染从
Root::startRendering()
函数开始,此函数启动一个循环,每次执行
Root::renderOneFrame
()
à
Root::_updateAllRenderTargets
à
RenderSystem::_updateAllRenderTargets()
à
RenderWindow::update()
à
D3D9RenderWindow::update(bool swap)
à
RenderTarget::update()
à
Viewport::update()
à
Camera::_renderScene()
à
SceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays)
4.
绕了好大一圈,才来到了
SceneManager::_renderScene()
,此函数想必是渲染的主要操作所在;
5. SceneManager:: _updateSceneGraph()
从
root node
开始递归的调用了所有
scene node
的
update
,主要是计算了
transform
;
6.
给
AutoParamDataSource
设置了一系列参数,这个类是用来为
gpu programs
提供一些参数的;
7. SceneManager::prepareRenderQueue
()。这里有一个
Ogre
场景管理的概念
RenderQueue
。粗略的看,这个类主要是为了把
Objects
按照材质分组,它还将管理对象的渲染优先权;
8. OctreeSceneManager::_findVisibleObjects
()
à
OctreeSceneManager::walkOctree
à
OctreeNode::_addToRenderQueue
如果想显示包裹盒的话,则会调用
” sn->_addBoundingBoxToQueue(queue);”
可见这个操作利用
SceneManager
的空间管理算法来对所有的
SceneNode
进行了可见性判断,如果可能可见,则加入到
RenderQueue
中;
9.
在计算好了
RenderQueue
之后,开始调用
RenderSystem
的一系列函数,例如
_setProjectionMatrix
等等开始为真正的渲染操作做好准备;
10. SceneManager::_renderVisibleObjects
,渲染操作就在这里了。
à
SceneManager::renderVisibleObjectsDefaultSequence
à
SceneManager::_renderQueueGroupObjects
à
SceneManager::renderBasicQueueGroupObjects
(此函数遍历
RenderQueueGroup
中的每个
RenderPriorityGroup
,然后先渲染
solids
,再渲染
transparents
)
à
SceneManager::SceneMgrQueuedRenderableVisitor::visit
11.
à
SceneManager::renderSingleObject
,此函数设置了灯光、
GPU programs
,然后使用一个
RenderOperation
对象来调用
D3D9RenderSystem::_render
,也就是真正的
Draw call
。
RenderOperation
对象是由
SubEntity::getRenderOperation
à
SubMesh::_getRenderOperation
来设置的,主要是
IndexData
和
VertexData
。
这里有几个细节需要注意:
1.
在
SceneManager::renderObjects
函数中用到了一个
visitor
模式来访问
QueuedRenderableCollection
(这个类的实例用来在
RenderPriorityGroup
中包括
solids
、
transparents
等等)。
2. Entity
是从
MoveableObject
派生的,而
SubEntity
才是从
Renderable
派生的;
3.
一个
SceneNode
可以
Attach
多个
Entity
;实际上
SceneNode
可以
Attach
任何的
MoveableObject
;
4.
前面只提到了
IndexData
和
VertexData
,而对于渲染来说
Material
更是关注的焦点,
Mesh
的材质是如何与
RenderSystem
交互的呢?
总结:
SceneManager
进行可见性判断之后,形成一个
RenderQueue
,然后对于队列中的每个
Object
再使用
RenderOpertation
与
RenderSystem
联系,来执行渲染操作。
总体感觉有些地方相当复杂,有些觉得比较罗索,例如通过
root
然后找到
RenderTarget
然后知道
ViewPort
,再找到
Camear
,最后才执行到
SceneManager
的渲染函数,为什么不把
ViewPort
做完
SceneManaer::_renderScene
的一个参数,交给上层来控制呢?毕竟多数程序要一个
RenderWindow
,一个
ViewPort
就够了。又比如
RenderQueue
(见下图),不知道是不是因为要处理
Shadow
等才搞得这么复杂。
对于
Objects
按照
Material
分组,然后对于每个
Group
再先显然
Solids
再渲染
transparents
,这种透明处理方式明显是不安全的,如果两个组中都有透明物体,那画面肯定会出问题的。