X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Fsky%2FCloudShaderGeometry.cxx;h=229710db32ba4fa96dad76aa3ec4bf0a59c5820d;hb=11479cd8c386d8bf7e1fee7bed60ab4abefc5fad;hp=92d73f961c7466f92242426aa9445867416257bd;hpb=28031542130063b039b180716d32b852179b0acb;p=simgear.git diff --git a/simgear/scene/sky/CloudShaderGeometry.cxx b/simgear/scene/sky/CloudShaderGeometry.cxx index 92d73f96..229710db 100755 --- a/simgear/scene/sky/CloudShaderGeometry.cxx +++ b/simgear/scene/sky/CloudShaderGeometry.cxx @@ -19,6 +19,8 @@ * */ +#include + #include #include #include @@ -29,7 +31,19 @@ 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 @@ -37,73 +51,96 @@ 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 (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. - - 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(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(toOsg(_cloudsprites[itr->idx].position), 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. - // Maximum of every 128 frames (2 - 4 seconds) - skip_info->skip_limit = skip_info->skip_limit * 2; - if (skip_info->skip_limit > 128) - { - skip_info->skip_limit = 128; + 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; } - 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) - { - 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); - extensions->glVertexAttrib1f(CLOUD_HEIGHT, (GLfloat) (*t)->cloud_height); - 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); } } - + +void CloudShaderGeometry::addSprite(const 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 + // 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; + } + } + + _cloudsprites.push_back(CloudSprite(p, tx, ty, w, h, s, cloud_height)); +} + bool CloudShaderGeometry_readLocalData(Object& obj, Input& fr) { bool iteratorAdvanced = false; @@ -135,7 +172,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; } @@ -157,11 +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 - << (*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;