在ogre中,调用renderOneFrame就是渲染一帧的画面, 所以要了解Ogre渲染流程就直接单步调试跟着renderOneFrame走就好了。
本文以调用栈的方式展示ogre渲染流程,由于调用栈是在太深,所以会根据功能分块描述渲染进行到哪一步。
1. renderOneFrame
下面是主要调用堆栈,这部分主要描述了:所谓渲染实际上就是更新视口的画面,而画面则来自与视口绑定的摄像机所看到的场景。
Root::renderOneFrame(void) //渲染入口
_updateAllRenderTargets() //更新所有渲染目标
mActiveRenderer->_updateAllRenderTargets()
forach(RenderTargetPriorityMap)->update() //遍历所有目标进行更新
updateImpl()
_updateAutoUpdatedViewports() //更新视口
foreach(ViewportList)->_updateViewport()//遍历每一个视口
viewport->update()
mCamera->_renderScene()/*通过与视口绑定的摄像机渲染场景,这里在第二节展开*/
mActiveRenderer->_swapAllRenderTargetBuffers() //渲染完毕后,交换渲染缓存
SceneManagerEnumerator->_handleLodEvents() //通知更新场景事件
2. _renderScene
这部分的主要作用是准备渲染场景所需要的灯光和物体。
流程如下:
- 初始化场景中的设置
- 更新控制器、动画等类的参数,从而更新节点的属性(位置、方向等)
- 更新节点的包围盒,重新计算各个节点的包围盒
- 更新摄像机状态
- 遍历灯光,找出会影响摄像机的灯光(计算是否与摄像机视锥相交)
- 准备阴影纹理(如果有)
- 遍历物体,找出需要渲染的物体添加进渲染队列(计算是否与摄像机视锥相交)
- 渲染物体
- 渲染后操作
mCamera->_renderScene()
listeners->cameraPreRenderScene() //摄像机渲染器前处理
mSceneMgr->_renderScene()
Root::getSingleton()._pushCurrentSceneManager(this) //加入场景栈
mDestRenderSystem->setDrawBuffer() //设置缓存
useLights() //添加附加灯光
mDestRenderSystem->_useLights()
initShadowVolumeMaterials() //初始化阴影材质
ControllerManager::updateAllControllers() //更新控制器
foreach(ControllerList)->update()
_applySceneAnimations() //更新动画
updateDirtyInstanceManagers() //更新脏实例管理器
//更新所有场景节点包围盒(AABB)
_updateSceneGraph(camera)
processQueuedUpdates()
foreach(Node : msQueuedUpdates)->needUpdate(true) //重设节点状态
msQueuedUpdates->clear()
getRootSceneNode()->_update() //从根节点开始更新
_updateFromParent()
foreach(Node : ChildNodeMap)->_update() //递归更新子节点
_updateBounds() //更新节点包围盒(AABB)
foreach(mObjects) mWorldAABB.merge(mObjects->getWorldBoundingBox()) //合并包围盒
foreach(mChildren) mWorldAABB.merge(child->mWorldAABB()) //合并子节点包围盒
//对于设置了跟踪目标的对象随目标对象更新朝向
foreach(AutoTrackingSceneNodes)->autoTrack()
lookAt(mAutoTrackTarget)
camera->_autoTrack()
//找出可能影响摄像机(视锥)的灯光
findLightsAffectingFrustum(camera)
lights = getMovableObjectCollection("Light")
foreach(lights)
if(camera->isVisible(sphere(light.position, light.range))) //判断摄像机的范围与灯光范围是否重叠
mTestLightInfos.push_back(lightInfo);
stable_sort(mLightsAffectingFrustum) //对灯光进行排序,以确定用以生成阴影的灯光
//阴影纹理初始化
if(isShadowTechniqueInUse() && isShadowTechniqueTextureBased()) //如果启用了纹理阴影
prepareShadowTextures()
mShadowRenderer.prepareShadowTextures(cam, vp, lightList) //渲染阴影纹理
mDestRenderSystem->setInvertVertexWinding(camera->isReflected()) //是否反转顶点
setViewport(vp) //如果之前启用了阴影纹理,这里会换成渲染了阴影纹理的视口
//设置摄像机、灯光距离、目标对象等渲染参数
mAutoParamDataSource->setCurrentCamera()
mAutoParamDataSource->setShadowDirLightExtrusionDistance()
mAutoParamDataSource->setCurrentRenderTarget()
mDestRenderSystem->setClipPlanes()
//准备渲染队列
prepareRenderQueue() //初始化渲染队列(清空)
q = getRenderQueue()
if(mLastRenderQueueInvocationCustom) //如果上次启用了自定义渲染,而本次没有,则返回默认设置
foreach(q->_getQueueGroups)->defaultOrganisationMode()
updateRenderQueueSplitOptions() //更新全局渲染设置(阴影纹理相关)
//查找能被摄像机看到的目标物体 添加进队列
camVisObjIt = mCamVisibleObjectsMap.find( camera ) //渲染目标队列
_findVisibleObjects(camera)
foreach(getRootSceneNode()->_findVisibleObjects()) //从根节点开始,计算所有实体并添加到渲染目标队列
queue->processVisibleObject(mo, cam, onlyShadowCasters, visibleBounds)
foreach(mChildren)->_findVisibleObjects() //递归查找子节点
queue->addRenderable(getDebugRenderable()) //添加自己到目标队列
if(mShowBoundingBox)_addBoundingBoxToQueue(queue) //如果要显示节点边框,也添加进渲染目标队列
mAutoParamDataSource->setMainCamBoundsInfo(camVisObjIt) //把渲染目标队列添加进渲染参数
mSkyRenderer.queueSkiesForRendering(getRenderQueue(), camera) //把天空盒添加进目标队列
//渲染队列准备完毕,检查是否保留上次渲染结果(覆盖渲染)
if(mCurrentViewport->getClearEveryFrame())
mDestRenderSystem->clearFrameBuffer() //如果视口要求每帧重绘,则清空帧缓存
/*渲染所有渲染队列中的物体,此处在第三节中展开*/
_renderVisibleObjects()
//渲染结束
Root::getSingleton()._popCurrentSceneManager(this) //退出场景栈
listeners->cameraPostRenderScene() //摄像机渲染后处理
3. _renderVisibleObjects
这部分的作用是决定启用的渲染序列和阴影纹理(自定义渲染器就是覆盖着部分的内容)。
_renderVisibleObjects()
//获取自定义渲染序列
invocationSequence = mCurrentViewport->_getRenderQueueInvocationSequence()
//只有关闭阴影纹理才能使用自定义渲染序列
if(mIlluminationStage != IRS_RENDER_TO_TEXTURE)
renderVisibleObjectsCustomSequence(invocationSequence) //启用自定义渲染序列(这里不展开)
//采用默认渲染序列
else renderVisibleObjectsDefaultSequence()
groups = getRenderQueue()->_getQueueGroups() //获取渲染序列组
foreach(groups) //遍历每个渲染序列组
//渲染前事件,可以根据需要跳过此次渲染
if(fireRenderQueueStarted())
break;
_renderQueueGroupObjects(groups[i])
//使用阴影纹理的渲染(这里不展开)
if(isShadowTechniqueTextureBased())
mShadowRenderer.renderTextureShadowCasterQueueGroupObjects()
//带阴影传递的渲染(这里不展开)
else if(doShadows)
mShadowRenderer.render()
//没有阴影传递的渲染(一般渲染)
else
renderBasicQueueGroupObjects()
pPriorityGrp = groupIt.getNext()
pPriorityGrp->sort(camera) //对渲染目标进行排序(按与摄像机的距离)
foreach(QueueGroupObjects) //循环每个渲染序列
/*按类别渲染物体,在下一节展开*/
renderObjects(pPriorityGrp->getSolidsBasic()) //渲染实体
renderObjects(getTransparentsUnsorted()) //渲染未分类的透明物体
renderObjects(getTransparents()) //渲染透明物体
//渲染后事件,可以根据渲染器要求进行重复渲染(跳回渲染前事件那里)
if(fireRenderQueueEnded()) goto
//endif
4. renderObjects
这部分是渲染单个物体前的准备工作。
renderObjects()
objs.acceptVisitor()
acceptVisitorGrouped(visitor)
foreach(visitor)->visit()
targetSceneMgr->validateRenderableForRendering() //在渲染前判断是否有冲突或者需要跳过
//渲染单个物体
targetSceneMgr->renderSingleObject()
mAutoParamDataSource->setCurrentRenderable(rend) //标记当前正在渲染的目标
setWorldTransform(rend)
//如果渲染状态被更改,则直接退出渲染
if(mSuppressRenderStateChanges)
mDestRenderSystem->setCurrentPassIterationCount(1) //重置渲染次数
resetViewProjMode() //重置渲染视图
return
//更新需要依赖视图矩阵的纹理贴图
foreach(getTextureUnitStates())
if hasViewRelativeTextureCoordinateGeneration()
mDestRenderSystem->_setTextureUnitSettings()
//排除归一化,如果使用多个着色器,应当自己手动归一化
mDestRenderSystem->setNormaliseNormals()
//设置负缩放剔除模式(负缩放会把模型的反面替换为正面,而有些模型反面是没有贴图的)
mDestRenderSystem->_setCullingMode(cullMode)
//设置摄像机渲染模式PM_POINTS、PM_WIREFRAME、PM_SOLID
mDestRenderSystem->_setPolygonMode(reqMode)
//遍历所有灯光,使用每个灯光渲染目标
foreach(localLightList)
issueRenderWithLights() /*使用灯光渲染目标,在下一节展开*/
//渲染结束,重置渲染视图
resetViewProjMode()
//end for
5. issueRenderWithLights
渲染的核心部分了,光线与每一个物体的作用(即成像),根据摄像机的渲染模式决定是渲染点、线或者实体等等。gl开头的函数都是OpenGL的函数了,至此已不能再往下跟踪了。
issueRenderWithLights()
useLights() //启用灯光
_issueRenderOp()
updateGpuProgramParameters() //把前面设置的参数全部设置到GPU中
rend->getRenderOperation(ro)
mDestRenderSystem->_render(ro);
RenderSystem::_render() //开始渲染顶点
setClipPlanesImpl() //裁剪平面
getElements() //取出所有顶点
bindVertexElementToGpu() //绑定顶点到GPU
glEnableClientState() //开启渲染flag
glClientActiveTextureARB()
//确定渲染模式(GL_POINTS、GL_LINES、GL_TRIANGLES等)
primType = switch(op.operationType)
//渲染所有节点
do
glDrawElements() or glDrawArrays() //渲染顶点
while(updatePassIterationRenderState()) //渲染下一个顶点
glDisableClientState() //结束渲染flag
rend->postRender()
resetLightClip() //重置灯光,准备下一次渲染