]> git.mxchange.org Git - simgear.git/commitdiff
Sort cloud sprites using std::sort, based on projected Z.
authorTim Moore <timoore@redhat.com>
Thu, 15 Jan 2009 23:37:40 +0000 (00:37 +0100)
committerTim Moore <timoore@redhat.com>
Thu, 15 Jan 2009 23:37:40 +0000 (00:37 +0100)
A "cleanup" of cloud sorting.

simgear/scene/sky/CloudShaderGeometry.cxx
simgear/scene/sky/CloudShaderGeometry.hxx
simgear/scene/sky/cloudfield.cxx

index dee1e742677ff5ffa09a37d50af0db2e19bf8034..9acc3f309bad30545609901531bf10f880158264 100755 (executable)
@@ -19,6 +19,8 @@
  *
  */
 
+#include <algorithm>
+
 #include <osgDB/Registry>
 #include <osgDB/Input>
 #include <osgDB/ParameterOutput>
@@ -31,6 +33,17 @@ using namespace osg;
 using namespace osgDB;
 using namespace simgear;
 
+namespace
+{
+struct SpriteComp
+{
+    bool operator() (const CloudShaderGeometry::SortData::SortItem& lhs,
+                     const CloudShaderGeometry::SortData::SortItem& rhs) const
+    {
+        return lhs.depth < rhs.depth;
+    }
+};
+}
 namespace simgear
 {
 void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
@@ -38,80 +51,93 @@ void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
     if (!_cloudsprites.size()) return;
     
     osg::State& state = *renderInfo.getState();
-    
+    unsigned int contextID = state.getContextID();
+    SortData& sortData = _sortData[contextID];
+    int frameNumber = state.getFrameStamp()->getFrameNumber();
+
+    if (!sortData.spriteIdx)
+        sortData.spriteIdx = new SortData::SortItemList;
+    if (sortData.spriteIdx->size() < _cloudsprites.size()) {
+        for (int i = sortData.spriteIdx->size(); i < _cloudsprites.size(); ++i)
+            sortData.spriteIdx->push_back(SortData::SortItem(i, 0.0f));
+        sortData.frameSorted = frameNumber - (sortData.skip_limit + 1);
+    }
     // If the cloud is already sorted, then it is likely to still be sorted.
     // Therefore we can avoid re-sorting it for a period. If it is still
     // sorted after that period, then we can wait for a longer period before
     // checking again. In this way, only clouds that are changing regularly
     // are sorted.
-    
-    skip_info->skip_count = (skip_info->skip_count + 1) % skip_info->skip_limit;
-    
-    if (skip_info->skip_count == 0)
-    {
-        osg::Matrix vm = state.getModelViewMatrix();
-        bool sorted = true;
-        
-        // Transform the viewing direction, represented by the eye space vector (0,0,-1, 0), into model-space
-        // (here we simply take the opposite direction and reverse the ordering when sorting)
-        osg::Vec3f view_dir(vm(0, 2), vm(1, 2), vm(2, 2));      // Caveat: OpenSceneGraph matrices are transposed!
-    
-        float p = view_dir*_cloudsprites[0]->position.osg();
-        // Do a single iteration of a bubble sort, sorting
-        // back to front.
-        for(unsigned int i = 0; i < _cloudsprites.size() - 1; i++)
-        {
-            float q = view_dir*_cloudsprites[i+1]->position.osg();
-            if (p > q) {  
-                CloudSprite c = *_cloudsprites[i];
-                *_cloudsprites[i] = *_cloudsprites[i+1];
-                *_cloudsprites[i+1] = c;
-                
-                sorted = false;
-            }
-            else
-                p = q;
+    if (frameNumber - sortData.skip_limit >= sortData.frameSorted) {
+        Matrix mvp = state.getModelViewMatrix() * state.getProjectionMatrix();
+        for (SortData::SortItemList::iterator itr = sortData.spriteIdx->begin(),
+                 end = sortData.spriteIdx->end();
+             itr != end;
+             ++itr) {
+            Vec4f projPos
+                = Vec4f(_cloudsprites[itr->idx].position.osg(), 1.0f) * mvp;
+            itr->depth = projPos.z() / projPos.w();
         }
-        
-        
-        if (sorted)
-        {
+        // Already sorted?
+        if (std::adjacent_find(sortData.spriteIdx->rbegin(),
+                               sortData.spriteIdx->rend(), SpriteComp())
+            == sortData.spriteIdx->rend()) {
             // This cloud is sorted, so no need to re-sort.
-            skip_info->skip_limit = skip_info->skip_limit * 2;
-            
-            if (skip_info->skip_limit > 30) 
-            {
+            sortData.skip_limit = sortData.skip_limit * 2;
+            if (sortData.skip_limit > 30) {
                 // Jitter the skip frames to avoid synchronized sorts
                 // which will cause periodic frame-rate drops
-                skip_info->skip_limit += sg_random() * 10;
+                sortData.skip_limit += sg_random() * 10;
             }
-            
-            if (skip_info->skip_limit > 128) 
-            {
+            if (sortData.skip_limit > 128) {
                 // Maximum of every 128 frames (2 - 4 seconds)
-                skip_info->skip_limit = 128 + sg_random() * 10;
+                sortData.skip_limit = 128 + sg_random() * 10;
             }
+
+        } else {
+            std::sort(sortData.spriteIdx->begin(), sortData.spriteIdx->end(),
+                      SpriteComp());
+            sortData.skip_limit = 1;
         }
-        else
-        {
-            // This cloud is unsorted, so we need to sort next frame
-            skip_info->skip_limit = 1;
-        }
+        sortData.frameSorted = frameNumber;
     }
 
     const Extensions* extensions = getExtensions(state.getContextID(),true);
 
-    for(CloudSpriteList::const_iterator t = _cloudsprites.begin(); t != _cloudsprites.end(); ++t)
-    {
-      GLfloat ua1[3] = { (GLfloat) (*t)->texture_index_x/varieties_x, (GLfloat) (*t)->texture_index_y/varieties_y, (*t)->width };
-      GLfloat ua2[3] = { (GLfloat) (*t)->height, (*t)->shade, (GLfloat) (*t)->cloud_height };
+    for(SortData::SortItemList::const_iterator itr = sortData.spriteIdx->begin(),
+            end = sortData.spriteIdx->end();
+        itr != end;
+        ++itr) {
+        const CloudSprite& t = _cloudsprites[itr->idx];
+        GLfloat ua1[3] = { (GLfloat)t.texture_index_x/varieties_x,
+                           (GLfloat)t.texture_index_y/varieties_y,
+                           t.width };
+        GLfloat ua2[3] = { (GLfloat)t.height,
+                           t.shade,
+                           (GLfloat) t.cloud_height };
         extensions->glVertexAttrib3fv(USR_ATTR_1, ua1 );
         extensions->glVertexAttrib3fv(USR_ATTR_2, ua2 );
-        glColor4f((*t)->position.x(), (*t)->position.y(), (*t)->position.z(), 1.0);
+        glColor4f(t.position.x(), t.position.y(), t.position.z(), 1.0);
         _geometry->draw(renderInfo);
     }
 }
-    
+
+void CloudShaderGeometry::addSprite(SGVec3f& p, int tx, int ty,
+                                    float w, float h,
+                                    float s, float cull, float cloud_height)
+{
+    // Only add the sprite if it is further than the cull distance to all other sprites
+    for (CloudShaderGeometry::CloudSpriteList::iterator iter = _cloudsprites.begin();
+         iter != _cloudsprites.end();
+         ++iter) 
+    {
+        if (distSqr(iter->position, p) < cull) {
+            // Too close - cull it
+            return;
+        }
+    }
+    _cloudsprites.push_back(CloudSprite(p, tx, ty, w, h, s, cloud_height));
+}
+
 bool CloudShaderGeometry_readLocalData(Object& obj, Input& fr)
 {
     bool iteratorAdvanced = false;
@@ -143,7 +169,7 @@ bool CloudShaderGeometry_readLocalData(Object& obj, Input& fr)
                 fr[5].getFloat(w) && fr[6].getFloat(h)&& fr[7].getFloat(s) && fr[8].getFloat(ch)) {
                     fr += 5;
                     //SGVec3f* v = new SGVec3f(v.x(), v.y(), v.z());
-                    geom._cloudsprites.push_back(new CloudShaderGeometry::CloudSprite(v, tx, ty, w, h,s,ch));
+                    geom._cloudsprites.push_back(CloudShaderGeometry::CloudSprite(v, tx, ty, w, h,s,ch));
             } else {
                 ++fr;
             }
@@ -165,11 +191,11 @@ bool CloudShaderGeometry_writeLocalData(const Object& obj, Output& fw)
              = geom._cloudsprites.begin();
          itr != geom._cloudsprites.end();
          ++itr) {
-             fw.indent() << (*itr)->position.x() << " " << (*itr)->position.y() << " " 
-                     << (*itr)->position.z() << " " << (*itr)->texture_index_x << " "
-                     << (*itr)->texture_index_y << " "  << (*itr)->width << " " 
-                     << (*itr)->height << " " << (*itr)->shade 
-                     << (*itr)->cloud_height << " "<< std::endl;
+             fw.indent() << itr->position.x() << " " << itr->position.y() << " " 
+                     << itr->position.z() << " " << itr->texture_index_x << " "
+                     << itr->texture_index_y << " "  << itr->width << " " 
+                     << itr->height << " " << itr->shade 
+                     << itr->cloud_height << " "<< std::endl;
     }
     fw.moveOut();
     fw.indent() << "}" << std::endl;
index 66727406e7fabb23e571112a56a42833ccd78369..8a9c31c5172faea4c004a602fcee972fc58df3d7 100755 (executable)
@@ -31,6 +31,7 @@
 #include <osg/RenderInfo>
 #include <osg/Vec3>
 #include <osg/Vec4>
+#include <osg/buffered_value>
 
 #include <simgear/math/SGMath.hxx>
 #include <simgear/math/sg_random.h>
@@ -49,14 +50,12 @@ class CloudShaderGeometry : public osg::Drawable
         CloudShaderGeometry()
         { 
             setUseDisplayList(false); 
-            skip_info = new SkipInfo();
         }
 
         CloudShaderGeometry(int vx, int vy, float width, float height) :
             varieties_x(vx), varieties_y(vy)
         { 
             setUseDisplayList(false); 
-            skip_info = new SkipInfo();
             float x = width/2.0f;
             float z = height/2.0f;
             _bbox.expandBy(-x, -x, -z);
@@ -69,14 +68,6 @@ class CloudShaderGeometry : public osg::Drawable
 
         META_Object(flightgear, CloudShaderGeometry);
         
-        struct SkipInfo {
-            SkipInfo() : skip_count(0), skip_limit(1) {}
-            int skip_count;
-            int skip_limit;
-        };
-        
-        SkipInfo* skip_info;
-        
         struct CloudSprite {
             CloudSprite(SGVec3f& p, int tx, int ty, float w, float h, float s, float ch) :
                     position(p), texture_index_x(tx), texture_index_y(ty), width(w), height(h), shade(s), cloud_height(ch)
@@ -91,17 +82,17 @@ class CloudShaderGeometry : public osg::Drawable
                     float cloud_height;
         };
         
-        typedef std::vector<CloudSprite*> CloudSpriteList;
+        typedef std::vector<CloudSprite> CloudSpriteList;
         CloudSpriteList _cloudsprites;
         
-        void insert(CloudSprite* t)
+        void insert(const CloudSprite& t)
         { _cloudsprites.push_back(t); }
         void insert(SGVec3f& p, int tx, int ty, float w, float h, float s, float ch)
-        { insert(new CloudSprite(p, tx, ty, w, h, s, ch)); }
+        { insert(CloudSprite(p, tx, ty, w, h, s, ch)); }
         
         unsigned getNumCloudSprite() const
         { return _cloudsprites.size(); }
-        CloudSprite* getCloudSprite(unsigned i) const
+        CloudSprite& getCloudSprite(unsigned i)
         { return _cloudsprites[i]; }
         
         virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
@@ -115,23 +106,8 @@ class CloudShaderGeometry : public osg::Drawable
             _geometry = geometry;
         }
         
-        void addSprite(SGVec3f& p, int tx, int ty, float w, float h, float s, float cull, float cloud_height)
-        {
-            // Only add the sprite if it is further than the cull distance to all other sprites
-            for (CloudShaderGeometry::CloudSpriteList::iterator iter = _cloudsprites.begin();
-                 iter != _cloudsprites.end();
-                 ++iter) 
-            {
-                if (distSqr((*iter)->position, p) < cull)
-                {
-                    // Too close - cull it
-                    return;
-                }
-            }
-
-            _cloudsprites.push_back(new CloudSprite(p, tx, ty, w, h, s, cloud_height));
-        }
-        
+    void addSprite(SGVec3f& p, int tx, int ty, float w, float h, float s, float cull, float cloud_height);
+                
         osg::ref_ptr<osg::Drawable> _geometry;
 
         int varieties_x;
@@ -140,15 +116,30 @@ class CloudShaderGeometry : public osg::Drawable
         // Bounding box extents.
         osg::BoundingBox _bbox;
         
-    protected:
+    struct SortData
+    {
+        struct SortItem
+        {
+            SortItem(size_t idx_, float depth_) : idx(idx_), depth(depth_) {}
+            SortItem() : idx(0), depth(0.0f) {}
+            size_t idx;
+            float depth;
+        };
+        SortData() : frameSorted(0), skip_limit(1), spriteIdx(0) {}
+        int frameSorted;
+        int skip_limit;
+        // This will be sorted by Z distance
+        typedef std::vector<SortItem> SortItemList;
+        SortItemList* spriteIdx;
+    };
+protected:
+    mutable osg::buffered_object<SortData> _sortData;
     
-        virtual ~CloudShaderGeometry() {
-            delete skip_info;
-            for (unsigned int i = 0; i < _cloudsprites.size(); i++)
-            {
-                delete _cloudsprites[i];
-            }
-        }
+    virtual ~CloudShaderGeometry()
+    {
+        for (unsigned int i = 0; i < _sortData.size(); ++i)
+            delete _sortData[i].spriteIdx;
+    }
 };
 
 }
index a567c91e0e81b8106d43ebca02270ca6894fe0d6..e861442868f4417d1b0ab57759b610af3fad85f7 100644 (file)
@@ -137,7 +137,7 @@ bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
         field_transform->setMatrix( LAT*LON*T );
     }
     
-    field_root->getStateSet()->setRenderBinDetails(asl, "RenderBin");
+    field_root->getStateSet()->setRenderBinDetails(asl, "DepthSortedBin");
 
     return true;
 }