首先看
root::startRendering()
{
1 首先调用活动渲染系统的RenderSystem::_initRenderTargets(void)
这个函数调用渲染系统里面的每个RenderTarget->resetStatistics();
重置统计状态。
clearEventTimes清除事件时间。
进入循环直到退出
WindowEventUtilities::messagePump(); 这个实际上是windows的消息循环。
renderOneFrame();
2 关键函数renderOneFrame();
_fireFrameStarted();//调用所有帧监听器的frameStarted
_updateAllRenderTargets();
_fireFrameEnded();
3 关键函数:_updateAllRenderTargets();
1 更新渲染系统的所有渲染目标:mActiveRenderer->_updateAllRenderTargets(false);
{
按渲染目标的优先级来更新,
如果RenderTarget是活动的并且是自动更新的,这调用每个RenderTarget::update(swapBuffers);
内部调用了RenderTarget::update(bool swap);这跟函数的内部这样执行
RenderTarget::_beginUpdate(); 调用每个RenderTarget监听器的preRenderTargetUpdate()函数。
_updateAutoUpdatedViewports(true);
遍历所有RenderTarget里面的每一个viewport,如果这个viewport是自动更新,就更新它。
RenderTarget::_updateViewport(viewport,updateStatistics);
这个函数内部:
fireViewportPreUpdate(viewport); 调用每个视口监听器的RenderTargetListener::preViewportUpdate(evt)
viewport->update();这个是真正的viewport更新:
应该是一个视口有一个照相机,所以
mCamera->_renderScene(this, mShowOverlays); //原来是调用照相机来更新场景。
遍历相机监听器列表, 调用相机更新前和更新后的的函数。
相机里面有个场景管理器的指针mSceneMgr->_renderScene(this, vp, includeOverlays);渲染到相机的视口里面 这个是最主要的函数:
它做了下面这些事情:
1 到具体的渲染系统里面去设置使用灯光。
2 根据是否使用了阴影技术来initShadowVolumeMaterials();
3 照相机无线远平面处理
4 ControllerManager::getSingleton().updateAllControllers();
5 更新动画:_applySceneAnimations();
遍历每个动画状态
对每个动画状态里的每个NodeTrack,NumericTrack重置到初始状态。
调用每个动画的:Animation::apply(Real timePos, Real weight, Real scale)
在这个函数里面:遍历所有三种Track,并调用它们的apply(timeIndex, weight, scale)函数
NodeTrack,NumericTrack,VertexTrack:三种Track。
5 这里漏了一个:要对所有能够影响到Frustum的灯光进行处理。
如果SceneManager::isShadowTechniqueInUse()并且viewPort::getShadowsEnabled()
再判断如果使用了基于纹理的阴影技术,则所相应的准备。prepareShadowTextures(camera, vp);
重点看 6 更新场景图:SceneManager::_updateSceneGraph(camera);
1 Node::processQueuedUpdates(); 静态函数
遍历所有需要更新的节点,设置需要更新标志。
2 getRootSceneNode()->_update(true, false);
真正的更新,调用节点的监听器函数,更新节点,_getDerivedOrientation()。_getDerivedScale()。。。
更新世界包围盒。
7 看场景节点和照相机是否要lookAt某个东西,然后做处理
8 根据照相机是否isReflected(),渲染系统做相应的动作。
9 mAutoParamDataSource做了一些动作,不知道干了什么。
10 设置裁减平面:mDestRenderSystem->setClipPlanes
重点看 11 准备渲染列队:prepareRenderQueue();貌似做了蛮多事。
首先介绍一下渲染列队
数据成员RenderQueueGroupMap mGroups;成员。
好像有四个RenderQueueGroup,RENDER_QUEUE_BACKGROUND,RENDER_QUEUE_OVERLAY,
RENDER_QUEUE_SKIES_EARLY,RENDER_QUEUE_SKIES_LATE
uint8 mDefaultQueueGroup 缺省渲染列队组
ushort mDefaultRenderablePriority 缺省可渲染优先级
bool mSplitPassesByLightingType 是否根据灯光类型来划分通路
bool mSplitNoShadowPasses
bool mShadowCastersCannotBeReceivers
RenderableListener * mRenderableListener 监听器
下面介绍函数具体做了哪些事情:
RenderQueue* q = getRenderQueue(); 获得渲染列队
这个函数如果发现没有渲染列队就new一个渲染列队
q->clear();
清理所有渲染列队组,以及Pass::processPendingPassUpdates();
如果当前视口有RenderQueueInvocationSequence* sep;
对每个RenderQueueGroupp调用resetOrganisationModes()。然后又对每个RenderQueueGroupp调用addOrganisationMode()。
并且updateRenderQueueGroupSplitOptions设置splitting option
还不是很清楚
12 在照相机的视觉里面查找可见对象;
firePreFindVisibleObjects(vp);
_findVisibleObjects(camera, &(camVisObjIt->second),这个函数内部调用了下面这个函数
getRootSceneNode()->_findVisibleObjects(cam, getRenderQueue(), visibleBounds, true,
mDisplayNodes, onlyShadowCasters);
mIlluminationStage == IRS_RENDER_TO_TEXTURE? true : false);
firePostFindVisibleObjects(vp);
13 将overlay加入渲染列队准备渲染:
貌似重点 OverlayManager::getSingleton()._queueOverlaysForRendering(camera, getRenderQueue(), vp);
14 将天空球入队准备渲染:
_queueSkiesForRendering(camera);
15 判断是否每帧都要清除帧缓存,用背景颜色清除帧缓存:mDestRenderSystem->clearFrameBuffer();
16 开始帧:mDestRenderSystem->_beginFrame();进入ogl或d3d里面;
设置多边形模式:mDestRenderSystem->_setPolygonMode(camera->getPolygonMode());
设置投影矩阵和视矩阵:
重点看 真正渲染可见对象:_renderVisibleObjects();
对当前视口以定制的渲染列队调用顺序或缺省的渲染列队调用顺序来渲染物体。
先看一下却省的:renderVisibleObjectsDefaultSequence();
1 SceneManager::firePreRenderQueues();
2 对每个需要处理的RenderQueueGroup进行下面的操作:
SceneManager::fireRenderQueueStarted 渲染列队组开始渲染事件回调
SceneManager::_renderQueueGroupObjects()渲染这个RenderQueueGroup里面的对象。
根据使用的阴影技术这个里面有三条路:
如果使用了Additive stencil shadows
renderAdditiveStencilShadowedQueueGroupObjects(pGroup, om);
如果使用了Modulative stencil shadows
renderModulativeStencilShadowedQueueGroupObjects(pGroup, om);
如果使用的是基于纹理的阴影技术:
又分了几种情况,
如果没有使用阴影技术:
renderBasicQueueGroupObjects(pGroup, om);
{renderBasicQueueGroupObjects(pGroup, om);看看这个函数做了什么
对这个组里面的每一个RenderPriorityGroup* pPriorityGrp;对象
首先调用pPriorityGrp->sort(mCameraInProgress),对各种类型的物体进行排序
mSolidsBasic.sort(cam); QueuedRenderableCollection::sort()按深度或按通路进行排序
mSolidsDecal.sort(cam);
mSolidsDiffuseSpecular.sort(cam);
mSolidsNoShadowReceive.sort(cam);
mTransparentsUnsorted.sort(cam);
mTransparents.sort(cam);
接下来渲染各种已排好序的对象: //真正的渲染物体在这里
// Do solids
renderObjects(pPriorityGrp->getSolidsBasic(), om, true, true);
这函数里面用的是Visitor模式进行渲染的。
通过Visitior最终会调用场景管理器的
renderSingleObject(r, mUsedPass, scissoring, autoLights, manualLightList);
第一个参数是一个Renderable*类型,第二个是Pass类型*
判断这个通路是否使用了GPU着色程序。
接下来设置世界矩阵,通路使用的纹理单元状态等,cull模式,多边形模式,阴影技术,灯光等
更新GPU程序参数等。做出相应的设置。
渲染完成之后还要重置这些个状态。
// Do unsorted transparents
renderObjects(pPriorityGrp->getTransparentsUnsorted(), om, true, true);
// Do transparents (always descending)
renderObjects(pPriorityGrp->getTransparents(),
QueuedRenderableCollection::OM_SORT_DESCENDING, true, true);
}
SceneManager::fireRenderQueueEnded 渲染列队组结束渲染事件回调
结束帧:mDestRenderSystem->_endFrame(); 进入ogl或d3d里面;
17 通知照相机渲染的面和渲染的批次。
至此结束
这里还更新了统计数据;
fireViewportPostUpdate(viewport);
_endUpdate();
}
2_fireFrameRenderingQueued();
调用所有帧监听器的:frameRenderingQueued();
3 交换渲染系统的缓存:mActiveRenderer->_swapAllRenderTargetBuffers;
// 真正的渲染目标更新在这里
按优先级遍历所有RenderTarget,调用所有RenderTarget::swapBuffer();
4 处理所有场景管理器的lodEvent:_handleLodEvents();
}