X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Fsky%2FCloudShaderGeometry.cxx;h=229710db32ba4fa96dad76aa3ec4bf0a59c5820d;hb=e7f151ad02467cb1763b118e699776d9b3e10492;hp=eaa9450fe9ea1f36f2345462e12605e0dffb4447;hpb=0b8b6ac56ab1efd3ad8cd1f430ec48641a1f2a13;p=simgear.git diff --git a/simgear/scene/sky/CloudShaderGeometry.cxx b/simgear/scene/sky/CloudShaderGeometry.cxx index eaa9450f..229710db 100755 --- a/simgear/scene/sky/CloudShaderGeometry.cxx +++ b/simgear/scene/sky/CloudShaderGeometry.cxx @@ -19,6 +19,8 @@ * */ +#include + #include #include #include @@ -29,59 +31,114 @@ 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 { - osg::State& state = *renderInfo.getState(); - osg::Matrix vm = state.getModelViewMatrix(); - - //TODO: It isn't clear whether this is worth the perf hit ATM. + if (!_cloudsprites.size()) return; - // Do a single iteration of a bubble sort. We do this in reverse - // so that elements closest to the camera bubble to the front than - // the elements further away - for(int i = (_cloudsprites.size() -2); i >= 0; i--) - { - osg::Vec4f p = vm * osg::Vec4f(_cloudsprites[i]->position.osg(), 1.0f); - osg::Vec4f q = vm * osg::Vec4f(_cloudsprites[i+1]->position.osg(), 1.0f); - - if (p.z() > q.z()) - { - CloudSprite c = *_cloudsprites[i]; - *_cloudsprites[i] = *_cloudsprites[i+1]; - *_cloudsprites[i+1] = c; + 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 (unsigned i = sortData.spriteIdx->size(); i < (unsigned)_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. + 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(toOsg(_cloudsprites[itr->idx].position), 1.0f) * mvp; + itr->depth = projPos.z() / projPos.w(); } + // 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. + 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 + sortData.skip_limit += sg_random() * 10; + } + if (sortData.skip_limit > 128) { + // Maximum of every 128 frames (2 - 4 seconds) + sortData.skip_limit = 128 + sg_random() * 10; + } + + } else { + std::sort(sortData.spriteIdx->begin(), sortData.spriteIdx->end(), + SpriteComp()); + sortData.skip_limit = 1; + } + sortData.frameSorted = frameNumber; } - + const Extensions* extensions = getExtensions(state.getContextID(),true); - for(CloudSpriteList::const_iterator t = _cloudsprites.begin(); t != _cloudsprites.end(); ++t) - { - extensions->glVertexAttrib1f(TEXTURE_INDEX_X, (GLfloat) (*t)->texture_index_x/varieties_x); - extensions->glVertexAttrib1f(TEXTURE_INDEX_Y, (GLfloat) (*t)->texture_index_y/varieties_y); - extensions->glVertexAttrib1f(WIDTH, (GLfloat) (*t)->width); - extensions->glVertexAttrib1f(HEIGHT, (GLfloat) (*t)->height); - extensions->glVertexAttrib1f(SHADE, (GLfloat) (*t)->shade); - glColor4f((*t)->position.x(), (*t)->position.y(), (*t)->position.z(), 1.0); + 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, + (GLfloat) t.width }; + GLfloat ua2[3] = { (GLfloat) t.height, + (GLfloat) 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); _geometry->draw(renderInfo); } } -BoundingBox CloudShaderGeometry::computeBound() const +void CloudShaderGeometry::addSprite(const SGVec3f& p, int tx, int ty, + float w, float h, + float s, float cull, float cloud_height) { - BoundingBox geom_box = _geometry->getBound(); - BoundingBox bb; - for(CloudSpriteList::const_iterator itr = _cloudsprites.begin(); - itr != _cloudsprites.end(); - ++itr) { - bb.expandBy(geom_box.corner(0)*(*itr)->width + - osg::Vec3( (*itr)->position.x(), (*itr)->position.y(), (*itr)->position.z() )); - bb.expandBy(geom_box.corner(7)*(*itr)->height + - osg::Vec3( (*itr)->position.x(), (*itr)->position.y(), (*itr)->position.z() )); + // Only add the sprite if it is further than the cull distance to all other sprites + // except for the center sprite. + for (CloudShaderGeometry::CloudSpriteList::iterator iter = _cloudsprites.begin(); + iter != _cloudsprites.end(); + ++iter) + { + if ((iter != _cloudsprites.begin()) && + (distSqr(iter->position, p) < cull)) { + // Too close - cull it + return; + } } - return bb; + + _cloudsprites.push_back(CloudSprite(p, tx, ty, w, h, s, cloud_height)); } bool CloudShaderGeometry_readLocalData(Object& obj, Input& fr) @@ -109,13 +166,13 @@ bool CloudShaderGeometry_readLocalData(Object& obj, Input& fr) while (!fr.eof() && fr[0].getNoNestedBrackets() > entry) { SGVec3f v; int tx, ty; - float w, h, s; + float w, h, s, ch; if (fr[0].getFloat(v.x()) && fr[1].getFloat(v.y()) - && fr[2].getFloat(v.z()) && fr[3].getInt(tx) && fr[3].getInt(ty) && - fr[4].getFloat(w) && fr[4].getFloat(h)&& fr[4].getFloat(s)) { + && fr[2].getFloat(v.z()) && fr[3].getInt(tx) && fr[4].getInt(ty) && + 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)); + geom._cloudsprites.push_back(CloudShaderGeometry::CloudSprite(v, tx, ty, w, h,s,ch)); } else { ++fr; } @@ -137,10 +194,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 << 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;