后把RenderableList组织成SolidRenderablePassMap:
typedef std::vector<Renderable*> RenderableList;
typedef std::map<Pass*, RenderableList*, SolidQueueItemLess> SolidRenderablePassMap;
SolidRenderablePassMap mSolidPasses;
SolidRenderablePassMap mSolidPassesDiffuseSpecular;
SolidRenderablePassMap mSolidPassesDecal;
SolidRenderablePassMap mSolidPassesNoShadow;
综上所述,需渲染的物体分别经过RenderPriorityGroup、RenderQueueGroup分类后,由RenderQueue统一管理。
4. QueuedRenderableCollection
RenderPriorityGroup有5个成员变量mSolidsBasicm、SolidsDiffuseSpecular、mSolidsDecal、mSolidsNoShadowReceive、mTransparents都是QueuedRenderableCollection,
QueuedRenderableCollection是存储Renderable和Pass的最终场所。通过多种排序实现Renderable和Pass的有序化。排序包括小于排序、深度递减排序和基数排序。
typedef std::vector<RenderablePass> RenderablePassList;
typedef std::vector<Renderable*> RenderableList;
typedef std::map<Pass*, RenderableList*, PassGroupLess> PassGroupRenderableMap;
PassGroupRenderableMap mGrouped;
RenderablePassList mSortedDescending;
mGrouped和mSortedDescending中存储的是Renderable和Pass。
QueuedRenderableCollection组织Renderable和Pass有三种,分别是按Pass分组、按与camera的距离升序和按与camera的距离减序。
enum OrganisationMode{
OM_PASS_GROUP = 1,
OM_SORT_DESCENDING = 2,
OM_SORT_ASCENDING = 6
};
5.QueuedRenderableVisitor
QueuedRenderableVisitor是按访问者模式设计的抽象接口。在QueuedRenderableCollection中有一个公用接口和三个内部接口如下:
void acceptVisitor(QueuedRenderableVisitor* visitor, OrganisationMode om) const;
void acceptVisitorGrouped(QueuedRenderableVisitor* visitor) const;
void acceptVisitorDescending(QueuedRenderableVisitor* visitor) const;
void acceptVisitorAscending(QueuedRenderableVisitor* visitor) const;
acceptVisitor按OrganisationMode3种方式分别调用内部接口acceptVisitorGrouped、
acceptVisitorDescending和acceptVisitorAscending。
switch(om)
{
case OM_PASS_GROUP:
acceptVisitorGrouped(visitor);
break;
case OM_SORT_DESCENDING:
acceptVisitorDescending(visitor);
break;
case OM_SORT_ASCENDING:
acceptVisitorAscending(visitor);
break;
}
而acceptVisitorGrouped、acceptVisitorDescending和acceptVisitorAscending。内部调用如下
void QueuedRenderableCollection::acceptVisitorGrouped(QueuedRenderableVisitor* visitor) const
{
RenderableList* rendList = ipass->second;
RenderableList::const_iterator irend, irendend;
irendend = rendList->end();
for (irend = rendList->begin(); irend != irendend; ++irend)
{
visitor->visit(*irend);
}
}
通过以上分析可以看到最终的渲染任务是交到QueuedRenderableVisitor手中。
而在SceneManager中有如下定义,具体实现了渲染任务。
class SceneMgrQueuedRenderableVisitor : public QueuedRenderableVisitor
SceneMgrQueuedRenderableVisitor* mActiveQueuedRenderableVisitor;
SceneMgrQueuedRenderableVisitor mDefaultQueuedRenderableVisitor;
6. RenderTarget
RenderTarget用来接收渲染操作的结果,它可以是屏幕上的窗口、离屏面(如texture)等。FPS信息的统计也是由RenderTarget完成的。在RenderTarget每次更新完成后,将会更新统计信息(封装于FrameStats中)。 除了负责统计帧的信息外,RenderTarget还负责创建维护Viewport(视口):
typedef std::map<int, Viewport*, std::less<int> > ViewportList;
ViewportList mViewportList;
Viewport* RenderTarget::addViewport(Camera* cam, int ZOrder, float left, float top ,
float width , float height)
{
ViewportList::iterator it = mViewportList.find(ZOrder);
if (it != mViewportList.end())
{
…
}
Viewport* vp = new Viewport(cam, this, left, top, width, height, ZOrder);
mViewportList.insert(ViewportList::value_type(ZOrder, vp));
fireViewportAdded(vp);
return vp;
}
由上面的代码可以看出,每个Viewport都对应一个Camera和一个RenderTarget。当创建一个Viewport后,它会自动建立与Camera的联系。可以把Camera看作是图像的来源,而RenderTarget是图像渲染的目的地。一个Viewport只能对应一个Camera和一个RenderTarget,而一个Camera也只能对应一个Viewport,但RenderTarget却可以拥有几个Viewport。
7. 渲染过程
OGRE通过WinMain或main调用go再通过Root调用startRendering进行消息循环,然后调用renderOneFrame,通过RenderSystem的_updateAllRenderTargets方法,更新所有的RenderTarget。RenderTarget通过update方法更新与之关联的Viewport并产生FPS统计信息。而Viewport则调用与之关联的Camera的_renderScene方法进行渲染,Camera此时把“球”踢给SceneManager。进入SceneManager的renderScene成员函数中后,在经过计算后,把需要渲染的场景送给RenderSystem去做真正的渲染,此时我们可以看到熟悉的_breginFrame和_endFrame。 一直下去经过RenderQueue、RenderQueueGroup、RenderPriorityGroup、QueuedRenderableCollection再通过访问者到达QueuedRenderableVisitor的子类SceneMgrQueuedRenderableVisitor,最终又回到SceneManager,由SceneManager再到RenderSystem完成整个渲染过程。过程伪码如下所示:
int WinMain or main(int argc, char **argv)
{
app.go();
}
virtual void go(void)
{
Root->startRendering();
}
void Root::startRendering(void)
{
renderOneFrame();
}
bool Root::renderOneFrame(void)
{
_updateAllRenderTargets();
}
void Root::_updateAllRenderTargets(void)
{
RenderSystem->_updateAllRenderTargets();
}
void RenderSystem::_updateAllRenderTargets(void)
{
RenderTarget->update();
}
void RenderTarget::update(void)
{
Viewport->update();
}
void Viewport::update(void)
{
Camera->_renderScene(this, mShowOverlays);
}
void Camera::_renderScene(Viewport *vp, bool includeOverlays)
{
SceneManager->_renderScene(this, vp, includeOverlays);
}
void SceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays)
{
RenderSystem->_beginFrame();
_renderVisibleObjects();
RenderSystem->_endFrame();
}
void SceneManager::_renderVisibleObjects(void)
{
//如果有阴影
renderVisibleObjectsCustomSequence();
//否则
renderVisibleObjectsDefaultSequence();
}
void SceneManager::renderVisibleObjectsDefaultSequence(void)
{
fireRenderQueueStarted(qId,mIlluminationStage)
_renderQueueGroupObjects(pGroup, QueuedRenderableCollection::OM_PASS_GROUP);
fireRenderQueueEnded(qId, mIlluminationStage)
}
void SceneManager::_renderQueueGroupObjects(RenderQueueGroup* pGroup, OrganisationMode om)
{
renderBasicQueueGroupObjects(pGroup, om);
}
void SceneManager::renderBasicQueueGroupObjects(RenderQueueGroup* pGroup, OrganisationMode om)
{
renderObjects(pPriorityGrp->getSolidsBasic(), om, true);
}
void SceneManager::renderObjects(const QueuedRenderableCollection& objs, …)
{
objs.acceptVisitor(mActiveQueuedRenderableVisitor, om);
}
void QueuedRenderableCollection::acceptVisitor(QueuedRenderableVisitor* visitor…)
{
switch(om){
case OM_PASS_GROUP:
acceptVisitorGrouped(visitor);
…
}
}
void QueuedRenderableCollection::acceptVisitorGrouped(QueuedRenderableVisitor* visitor)
{
QueuedRenderableVisitor->visit(Renderable);
}
void SceneManager::SceneMgrQueuedRenderableVisitor::visit(const Renderable* r)
{
SceneManager->renderSingleObject(r, mUsedPass, autoLights, manualLightList);
}
void SceneManager::renderSingleObject(const Renderable* rend, const Pass* pass…)
{
RenderSystem->_render(RenderOperation);
}
最终进入的RenderSystem的子类D3D9RenderSystem or GLRenderSystem。
void D3D9RenderSystem::_render(const RenderOperation& op)
{
mpD3DDevice->DrawIndexedPrimitive or mpD3DDevice->DrawPrimitive
}
void GLRenderSystem::_render(const RenderOperation& op)
{
glDrawElements or glDrawArrays
}
8. RenderQueueListener
class _OgreExport RenderQueueListener
{
public:
virtual ~RenderQueueListener() {}
virtual void renderQueueStarted(uint8 queueGroupId, const String& invocation, bool& skip) = 0;
virtual void renderQueueEnded(uint8 queueGroupId, const String& invocation, bool& repeat) = 0;
};
RenderQueueListener的作用就是在SceneManager开始渲染和结束渲染时改变render state和别的操作,比如检查本次RenderQueue是否skip,如果skip就直接break本次render。
在上面渲染过程中有如下:
void SceneManager::renderVisibleObjectsDefaultSequence(void)
{
fireRenderQueueStarted(qId,mIlluminationStage)
_renderQueueGroupObjects(pGroup, QueuedRenderableCollection::OM_PASS_GROUP);
fireRenderQueueEnded(qId, mIlluminationStage)
}
fireRenderQueueStarted和fireRenderQueueEnded中遍列RenderQueueListener。
定义如下:
typedef std::vector<RenderQueueListener*> RenderQueueListenerList;
RenderQueueListenerList mRenderQueueListeners;
bool SceneManager::fireRenderQueueStarted(uint8 id, const String& invocation)
{
RenderQueueListener->renderQueueStarted(id, invocation, skip);
}
bool SceneManager::fireRenderQueueEnded(uint8 id, const String& invocation)
{
RenderQueueListener->renderQueueEnded(id, invocation, repeat);
}
9. SpecialCaseRenderQueue
SenceManager中的RenderQueue包含一种特殊情况的渲染队列(Special Case Render Queue)
enum SpecialCaseRenderQueueMode{
SCRQM_INCLUDE, // 只渲染Special Case
SCRQM_EXCLUDE // 不渲染Special Case
};
通过setSpecialCaseRenderQueueMode可以设置。以下是跟Special Case Render Queue有关的变量和操作:
typedef std::set<uint8> SpecialCaseRenderQueueList;
SpecialCaseRenderQueueList mSpecialCaseQueueList;
SpecialCaseRenderQueueMode mSpecialCaseQueueMode;
virtual void addSpecialCaseRenderQueue(uint8 qid);
virtual void removeSpecialCaseRenderQueue(uint8 qid);
virtual void clearSpecialCaseRenderQueues(void);
virtual void setSpecialCaseRenderQueueMode(SpecialCaseRenderQueueMode mode);
virtual SpecialCaseRenderQueueMode getSpecialCaseRenderQueueMode(void);
这里面需要说明一下的是qid,qid是RenderQueueGroupID,RenderQueueGroupID的定义在上面已经提过。
总之,通过上面分析可以看出render queue是Renderable的集合。其实场景树和渲染队列都是对Renderable进行分类,只是分类的标准不同,场景树主要是从空间结构对Renderable进行分类,而渲染队列则是对Renderable从material以及blend上进行分类。
四. 动态阴影Shadow
Ogre支持两种主流的动态阴影技术,模板(stencil)阴影与纹理(texture)阴影,每一种都有两个变体:modulative与additive。这四种技术完全兼容fixed-function pipeline,因此不需要可编程GPU支持。然而,可利用GPU程序进行加速。在场景中只能使用一种阴影Technique,应该在场景渲染这前进行阴影Technique相关设置(最好是在创建场景管理器之间)。通过调用SceneManager::setShadowTechnique来设置Technique,参数指定Technique的具体类型。阴影Technique缺省情况下被关闭。对于物体,投射与接收阴影可以在材质中控制,也可以控制物体自己对自己投射。由于模板阴影算法的本质特征,透明半透明的物体要么全部投射实心阴影要么根本不投影影,不可能得到半透明的阴影。而使用纹理阴影技术则可以。灯不能用来投射阴影。
1. ShadowRenderable
ShadowRenderable是存储shadow volume材质和渲染数据的类。
2. ShadowCaster
ShadowCaster是计算和产生shadow volume的类。
3. ShadowVolumeExtrudeProgram
ShadowVolumeExtrudeProgram是存储asm shader代码的类。
4. ShadowListener
ShadowListener可以在渲染阴影过程中定义一些自己的操作。这个类只在shadow texture时有用。
Shadow这块可以精简,ogre有点复杂。