//----------------------------------------------------------------------- void QueuedRenderableCollection::sort(const Camera* cam) { // ascending and descending sort both set bit 1 if (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 pass msRadixSorter1.sort(mSortedDescending, RadixSortFunctorPass()); // sort by depth msRadixSorter2.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 }
//----------------------------------------------------------------------- void QueuedRenderableCollection::sort(const Camera* cam) { // ascending and descending sort both set bit 1 // We always sort descending, becuase the only difference is in the // acceptVisitor method, where we iterate in reverse in ascending mode if (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. bool performRadixSort = mSortedDescending.size() > 2000; if (performRadixSort) { // sort by pass msRadixSorter1.sort(mSortedDescending, RadixSortFunctorPass()); // sort by depth msRadixSorter2.sort(mSortedDescending, RadixSortFunctorDistance(cam)); } else { std::stable_sort( mSortedDescending.begin(), mSortedDescending.end(), DepthSortDescendingLess(cam)); } /* #ManuallySpecifyingRenderOrder For a given renderable, we introduced a hack that lets you say it renders either immediately before or after another renderable. We do this by readjusting the render order after Ogre's depth sort. Caveats: * items must be in the same render queue * items must be in the same sub-render queue (in our case, everything is in the transparency bucket) */ if (performRadixSort) for (int i = 0; i < mSortedDescending.size(); i++) { Renderable* renderable1 = mSortedDescending[i].renderable; int inc = renderable1->renderAfterOtherRenderable() ? 1 : -1; // If we've manually specified the render order, fix renderable1's render position // We modified the sort algorithms in OgreRenderQueueSortingGrouping.h so that the depth of renderable1 is the // same as the renderable it's tied to; all we have to do is swap renderable1 with the renderable it's // tied to (unless it's in the correct order, in which case we do nothing at all) if (renderable1->renderOrderTiedToOtherRenderable()) { Real depth1 = renderable1->getSquaredViewDepth(cam); for (int j = i + inc; 0 <= j && j < mSortedDescending.size(); j += inc) { Renderable* renderable2 = mSortedDescending[j].renderable; if (renderable2 == renderable1->getRenderableToRenderNextTo()) { // swap the two values RenderablePass rp = mSortedDescending[i]; mSortedDescending[i] = mSortedDescending[j]; mSortedDescending[j] = rp; break; } // We know that the renderable that renderable1 is tied to has the same depth as renderable1, so if we've reached items // with different depths, we can quit the loop (the items must have already been in the correct order) if (Math::RealEqual(renderable2->getSquaredViewDepth(cam), depth1)) break; } } } } // Nothing needs to be done for pass groups, they auto-organise }