From 8b57ed46b146d87981588dd63c59de6aca90a849 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 16 Jan 2009 00:37:40 +0100 Subject: [PATCH] Sort cloud sprites using std::sort, based on projected Z. A "cleanup" of cloud sorting. --- simgear/scene/sky/CloudShaderGeometry.cxx | 142 +++++++++++++--------- simgear/scene/sky/CloudShaderGeometry.hxx | 69 +++++------ simgear/scene/sky/cloudfield.cxx | 2 +- 3 files changed, 115 insertions(+), 98 deletions(-) diff --git a/simgear/scene/sky/CloudShaderGeometry.cxx b/simgear/scene/sky/CloudShaderGeometry.cxx index dee1e742..9acc3f30 100755 --- a/simgear/scene/sky/CloudShaderGeometry.cxx +++ b/simgear/scene/sky/CloudShaderGeometry.cxx @@ -19,6 +19,8 @@ * */ +#include + #include #include #include @@ -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; diff --git a/simgear/scene/sky/CloudShaderGeometry.hxx b/simgear/scene/sky/CloudShaderGeometry.hxx index 66727406..8a9c31c5 100755 --- a/simgear/scene/sky/CloudShaderGeometry.hxx +++ b/simgear/scene/sky/CloudShaderGeometry.hxx @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -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 CloudSpriteList; + typedef std::vector 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 _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 SortItemList; + SortItemList* spriteIdx; + }; +protected: + mutable osg::buffered_object _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; + } }; } diff --git a/simgear/scene/sky/cloudfield.cxx b/simgear/scene/sky/cloudfield.cxx index a567c91e..e8614428 100644 --- a/simgear/scene/sky/cloudfield.cxx +++ b/simgear/scene/sky/cloudfield.cxx @@ -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; } -- 2.39.5