From fa7490fb384f5127beb6f8f4cc60292c8c07c3b3 Mon Sep 17 00:00:00 2001 From: fredb Date: Wed, 26 Nov 2008 07:28:10 +0000 Subject: [PATCH] Stuart: > Something has changed in the environment manager which means that clouds > generateion is now inconsistent. I'm still tracking it down, as my recent > changes shouldn't have affected this. Well, the cause was a bug in my code, but it didn't expose itself until we moved to multiple cameras. The attached patch fixes the problem. I've also put in a new heuristic to improve the frame-rate. Clouds that are already sorted are likely to still be sorted in subsequent frames. Therefore I've put in a back-off mechanism for the bubble-sort pass. This should mean that if you stay completely stationary, once the clouds become sorted they will eventually only perform a bubble sort pass every 128 frames. --- simgear/scene/sky/CloudShaderGeometry.cxx | 63 +++++++++++++++++------ simgear/scene/sky/CloudShaderGeometry.hxx | 19 ++++++- simgear/scene/sky/cloud.cxx | 2 +- simgear/scene/sky/cloudfield.cxx | 10 ++-- simgear/scene/sky/cloudfield.hxx | 2 +- 5 files changed, 70 insertions(+), 26 deletions(-) diff --git a/simgear/scene/sky/CloudShaderGeometry.cxx b/simgear/scene/sky/CloudShaderGeometry.cxx index 87905434..a556afb0 100755 --- a/simgear/scene/sky/CloudShaderGeometry.cxx +++ b/simgear/scene/sky/CloudShaderGeometry.cxx @@ -37,27 +37,56 @@ void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const if (!_cloudsprites.size()) return; osg::State& state = *renderInfo.getState(); - osg::Matrix vm = state.getModelViewMatrix(); - //TODO: It isn't clear whether this is worth the perf hit ATM. + // 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. - // 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++) + skip_info->skip_count = (skip_info->skip_count + 1) % skip_info->skip_limit; + + if (skip_info->skip_count == 0) { - 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; + 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 (sorted) + { + // 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; + } } else - p = q; + { + // This cloud is unsorted, so we need to sort next frame + skip_info->skip_limit = 1; + } } const Extensions* extensions = getExtensions(state.getContextID(),true); @@ -74,7 +103,7 @@ void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const _geometry->draw(renderInfo); } } - + BoundingBox CloudShaderGeometry::computeBound() const { BoundingBox geom_box = _geometry->getBound(); diff --git a/simgear/scene/sky/CloudShaderGeometry.hxx b/simgear/scene/sky/CloudShaderGeometry.hxx index 50225f65..2401e962 100755 --- a/simgear/scene/sky/CloudShaderGeometry.hxx +++ b/simgear/scene/sky/CloudShaderGeometry.hxx @@ -52,12 +52,14 @@ class CloudShaderGeometry : public osg::Drawable CloudShaderGeometry() { setUseDisplayList(false); + skip_info = new SkipInfo(); } CloudShaderGeometry(int vx, int vy) : varieties_x(vx), varieties_y(vy) { setUseDisplayList(false); + skip_info = new SkipInfo(); } /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ @@ -66,6 +68,14 @@ 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) @@ -128,8 +138,13 @@ class CloudShaderGeometry : public osg::Drawable protected: - virtual ~CloudShaderGeometry() {} - + virtual ~CloudShaderGeometry() { + delete skip_info; + for (int i = 0; i < _cloudsprites.size(); i++) + { + delete _cloudsprites[i]; + } + } }; } diff --git a/simgear/scene/sky/cloud.cxx b/simgear/scene/sky/cloud.cxx index 0ec7139b..4a9bf2e1 100644 --- a/simgear/scene/sky/cloud.cxx +++ b/simgear/scene/sky/cloud.cxx @@ -731,7 +731,7 @@ void SGCloudLayer::set_enable3dClouds(bool enable) { } else { cloud_root->setChildValue(layer3D->getNode(), false); cloud_root->setChildValue(layer_root.get(), true); - } + } } void SGCloudLayer::applyDensity() { diff --git a/simgear/scene/sky/cloudfield.cxx b/simgear/scene/sky/cloudfield.cxx index f901b0f4..7fd7ce98 100644 --- a/simgear/scene/sky/cloudfield.cxx +++ b/simgear/scene/sky/cloudfield.cxx @@ -64,7 +64,6 @@ using std::vector; float SGCloudField::fieldSize = 50000.0f; float SGCloudField::density = 100.0f; double SGCloudField::timer_dt = 0.0; -int reposition_count = 0; sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y; void SGCloudField::set_density(float density) { @@ -99,7 +98,6 @@ bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, cld_pos = SGGeoc::fromGeod(SGGeod::fromRad(lon, lat)); } else if (dist > fieldSize) { // Distance requires repositioning of cloud field. - // We can easily work out the direction to reposition // from the course between the cloud position and the // camera position. @@ -141,10 +139,12 @@ SGCloudField::SGCloudField() : deltay(0.0), last_course(0.0), last_density(0.0), - defined3D(false) + defined3D(false), + reposition_count(0) { cld_pos = SGGeoc(); - field_root->addChild(field_transform.get()); + field_root->addChild(field_transform.get()); + field_root->setName("3D Cloud field root"); osg::ref_ptr quad_root = new osg::Group(); osg::ref_ptr quad[BRANCH_SIZE][BRANCH_SIZE]; @@ -263,5 +263,5 @@ void SGCloudField::addCloud( SGVec3f& pos, SGNewCloud *cloud) { transform->setPosition(pos.osg()); transform->addChild(geode.get()); - field_group[x][y]->addChild(transform.get()); + field_group[x][y]->addChild(transform.get(), true); } diff --git a/simgear/scene/sky/cloudfield.hxx b/simgear/scene/sky/cloudfield.hxx index 40333d6d..50207aac 100644 --- a/simgear/scene/sky/cloudfield.hxx +++ b/simgear/scene/sky/cloudfield.hxx @@ -75,7 +75,7 @@ private: sgSphere field_sphere; float last_density; SGGeoc cld_pos; - + int reposition_count; public: SGCloudField(); -- 2.39.2