读书人

场景的治理 :RenderQueue

发布时间: 2012-12-25 16:18:28 作者: rapoo

场景的管理 :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排序了。

?

?

读书人网 >编程

热点推荐