场景的管理 :RenderQueue
RenderQueue渲染队列是送给渲染系统渲染的最终结果集,本质上它与查询队列没什么不同,但由于它的内部做过多次分类排序,所以它查询队列复杂。
RenderQueue :
1.RenderQueueGroupID :即是key又是优先级别
?
enum RenderQueueGroupID { /// Use this queue for objects which must be rendered first e.g. backgrounds RENDER_QUEUE_BACKGROUND = 0, // 背景 RENDER_QUEUE_SKIES_EARLY = 5, // 背景之后的第一个队列,用于天空盒 RENDER_QUEUE_1 = 10, RENDER_QUEUE_2 = 20,RENDER_QUEUE_WORLD_GEOMETRY_1 = 25, RENDER_QUEUE_3 = 30, RENDER_QUEUE_4 = 40, RENDER_QUEUE_MAIN = 50, // 默认渲染队列 RENDER_QUEUE_6 = 60, RENDER_QUEUE_7 = 70,RENDER_QUEUE_WORLD_GEOMETRY_2 = 75, RENDER_QUEUE_8 = 80, RENDER_QUEUE_9 = 90, RENDER_QUEUE_SKIES_LATE = 95, // 前景(控件),之前的最后一个队列,用于天空盒 RENDER_QUEUE_OVERLAY = 100, // 这个是给2D界面上的控件用的,在最前面RENDER_QUEUE_MAX = 105 // 这个应该是预留的,如果你想显示在控件的前面就必须得是它了 };?
?从小到大:这个是按照对象离屏幕距离来排列的,里面天空盒出现了两次。理论上来说,还需要根据材质进行分组,不过不应该是现在,而是在裁剪之后,因为裁剪之后就没有先后顺序了,也就没有什么遮挡不遮挡的了。
?
addRenderable :为渲染队列添加渲染对象
?
void RenderQueue::addRenderable(Renderable* pRend, uint8 groupID, ushort priority) { // Find group RenderQueueGroup* pGroup = getQueueGroup(groupID);Technique* pTech;// tell material it's been usedif (!pRend->getMaterial().isNull())pRend->getMaterial()->touch();// Check material & technique supplied (the former since the default implementation // of getTechnique is based on it for backwards compatibility if(pRend->getMaterial().isNull() || !pRend->getTechnique()) { // Use default base whiteMaterialPtr baseWhite = MaterialManager::getSingleton().getByName("BaseWhite"); pTech = baseWhite->getTechnique(0); }elsepTech = pRend->getTechnique();if (mRenderableListener){// Allow listener to override technique and to abortif (!mRenderableListener->renderableQueued(pRend, groupID, priority, &pTech, this))return; // rejected// tell material it's been used (incase changed)pTech->getParent()->touch();} pGroup->addRenderable(pRend, pTech, priority); }?getQueueGroup(groupID)如果不存储会创建,这样使其具有唯一性。pGroup->addRenderable(pRend, pTech, priority);表示这个方法其实除了对材质做了些判断什么都没做。
?
?
pGroup = OGRE_NEW RenderQueueGroup(this, mSplitPassesByLightingType, mSplitNoShadowPasses, mShadowCastersCannotBeReceivers);mGroups.insert(RenderQueueGroupMap::value_type(groupID, pGroup));void RenderQueue::setSplitPassesByLightingType(bool split) { mSplitPassesByLightingType = split; RenderQueueGroupMap::iterator i, iend; i = mGroups.begin(); iend = mGroups.end(); for (; i != iend; ++i) { i->second->setSplitPassesByLightingType(split); } }?
?在RenderQueue里面有3个字段mSplitPassesByLightingType,mSplitNoShadowPasses和
mShadowCastersCannotBeReceivers他们其实是给RenderQueueGroup使用的,这里强调的是RenderQueue的所有RenderQueueGroup的这三个属性都是一样的,一旦改变都会改变。
?
RenderQueueGroup :
?
void addRenderable(Renderable* pRend, Technique* pTech, ushort priority) { // Check if priority group is there PriorityMap::iterator i = mPriorityGroups.find(priority); RenderPriorityGroup* pPriorityGrp; if (i == mPriorityGroups.end()) { // Missing, create pPriorityGrp = OGRE_NEW RenderPriorityGroup(this, mSplitPassesByLightingType, mSplitNoShadowPasses, mShadowCastersNotReceivers);if (mOrganisationMode){pPriorityGrp->resetOrganisationModes();pPriorityGrp->addOrganisationMode((QueuedRenderableCollection::OrganisationMode)mOrganisationMode);} mPriorityGroups.insert(PriorityMap::value_type(priority, pPriorityGrp)); } else { pPriorityGrp = i->second; } // Add pPriorityGrp->addRenderable(pRend, pTech); }?
?RenderQueueGroup?的作用与RenderQueue 没什么两样,它的存在让我想起一个词“诟病”,这是在秀自己的设计能力吗?只能说这个类的能力过分简单,它只做了一件事,就是在RenderQueue?的基础上再分类。
?
RenderPriorityGroup :
?
QueuedRenderableCollection mSolidsBasic; // 不启用阴影(即不投射也不接收阴影)或启用modulative阴影或启用additive阴影但处于环境光阶段。 QueuedRenderableCollection mSolidsDiffuseSpecular; // 启用additive阴影,且处于逐个光源上色阶段 QueuedRenderableCollection mSolidsDecal; // 启用additive阴影,且处于纹理映射阶段。 QueuedRenderableCollection mSolidsNoShadowReceive; // 开启阴影但不接收阴影(如自发光体)(阴影可投可不投)QueuedRenderableCollection mTransparentsUnsorted; //透明的被排序的QueuedRenderableCollection mTransparents; // 透明的未被排序的
?
void RenderPriorityGroup::addRenderable(Renderable* rend, Technique* pTech) { // Transparent and depth/colour settings mean depth sorting is required? // Note: colour write disabled with depth check/write enabled means // setup depth buffer for other passes use. if (pTech->isTransparentSortingForced() || (pTech->isTransparent() && (!pTech->isDepthWriteEnabled() || !pTech->isDepthCheckEnabled() || pTech->hasColourWriteDisabled()))) {if (pTech->isTransparentSortingEnabled())addTransparentRenderable(pTech, rend);elseaddUnsortedTransparentRenderable(pTech, rend); } else { if (mSplitNoShadowPasses && mParent->getShadowsEnabled() &&((!pTech->getParent()->getReceiveShadows() ||rend->getCastsShadows()) && mShadowCastersNotReceivers)) { // Add solid renderable and add passes to no-shadow group addSolidRenderable(pTech, rend, true); } else { if (mSplitPassesByLightingType && mParent->getShadowsEnabled()) { addSolidRenderableSplitByLightType(pTech, rend); } else { addSolidRenderable(pTech, rend, false); } } } }所有同一个RenderQueueGroup 的渲染对象,传递到RenderPriorityGroup的时候,会根据Technique分配给这几个队列。目前对这几个队列不是很了解,但是整体上来看它区分了阴影的类型和是否为透明。另外,前面一直在传递未被使用过的几个参数,被这个方法使用了。
?
QueuedRenderableCollection :相比前面几个类,这个类更实在。
?
enum OrganisationMode // 以何种方式分组和排序{OM_PASS_GROUP = 1, // 根据pass分组OM_SORT_DESCENDING = 2, // 升序排序OM_SORT_ASCENDING = 6 // 降序排序};?
分组一般是在场景中的渲染对象比较多的时候使用,而排序是相对于相机的距离排序的,其实对于不透无阴影明体是不需要排序的。
?
PassGroupRenderableMap mGrouped;RenderablePassList mSortedDescending; static RadixSort<RenderablePassList, RenderablePass, uint32> msRadixSorter1; static RadixSort<RenderablePassList, RenderablePass, float> msRadixSorter2;
?
尽管这个类里面的字段比较多,但是重要的就这么几个,所有的渲染体分组都是放在mGrouped这个map中的,既然如此为什么还需要一个mSortedDescending呢?这个是用于存放不需要按照pass分类的渲染对象。
?
void QueuedRenderableCollection::addRenderable(Pass* pass, Renderable* rend){// ascending and descending sort both set bit 1if (mOrganisationMode & OM_SORT_DESCENDING){mSortedDescending.push_back(RenderablePass(rend, pass));}if (mOrganisationMode & OM_PASS_GROUP){ PassGroupRenderableMap::iterator i = mGrouped.find(pass); if (i == mGrouped.end()) { std::pair<PassGroupRenderableMap::iterator, bool> retPair; // Create new pass entry, build a new list // Note that this pass and list are never destroyed until the // engine shuts down, or a pass is destroyed or has it's hash// recalculated, although the lists will be cleared etPair = mGrouped.insert( passGroupRenderableMap::value_type(pass, OGRE_NEW_T(RenderableList, MEMCATEGORY_SCENE_CONTROL)() )); assert(retPair.second && "Error inserting new pass entry into PassGroupRenderableMap"); i = retPair.first; } // Insert renderable i->second->push_back(rend);}}?根据不同的mOrganisationMode类型,插入到不同的list里面。
void QueuedRenderableCollection::sort(const Camera* cam) {// ascending and descending sort both set bit 1// We always sort descending, because the only difference is in the// acceptVisitor method, where we iterate in reverse in ascending modeif (mOrganisationMode & OM_SORT_DESCENDING){// We can either use a stable_sort and the 'less' implementation,// or a 2-pass radix sort (once by pass, then by distance, since// radix sorting is inherently stable this will work)// We use stable_sort if the number of items is 512 or less, since// the complexity of the radix sort is approximately O(10N), since // each sort is O(5N) (1 pass histograms, 4 passes sort)// Since stable_sort has a worst-case performance of O(N(logN)^2)// the performance tipping point is from about 1500 items, but in// stable_sorts best-case scenario O(NlogN) it would be much higher.// Take a stab at 2000 items.if (mSortedDescending.size() > 2000){// sort by passmsRadixSorter1.sort(mSortedDescending, RadixSortFunctorPass());// sort by depthmsRadixSorter2.sort(mSortedDescending, RadixSortFunctorDistance(cam));}else{std::stable_sort(mSortedDescending.begin(), mSortedDescending.end(), DepthSortDescendingLess(cam));}}// Nothing needs to be done for pass groups, they auto-organise }??这个排序也挺重要的,大于2000个渲染对象的时候,才排序,渲染对象不多的时候就没必要按照pass排序了。
?
?