From 1cd17e9edd05233d6ca404f1eea4dda2215b1f33 Mon Sep 17 00:00:00 2001 From: Torsten Dreyer Date: Sat, 23 Apr 2011 20:56:28 +0200 Subject: [PATCH] Improvements to the global 3D clouds system Stuart Buchanan: Improvements to the global 3D clouds system - clouds now move with the wind - bug causing cloud coverage to be less than it should have been fixed - support for adding 3D clouds with an fg_command. (https://gitorious.org/fg/flightgear/merge_requests/1554) --- simgear/scene/sky/cloud.cxx | 17 +- simgear/scene/sky/cloudfield.cxx | 358 +++++++++++++++++-------------- simgear/scene/sky/cloudfield.hxx | 57 +++-- simgear/scene/sky/newcloud.cxx | 46 ++-- simgear/scene/sky/newcloud.hxx | 19 +- simgear/scene/sky/sky.cxx | 8 +- 6 files changed, 259 insertions(+), 246 deletions(-) diff --git a/simgear/scene/sky/cloud.cxx b/simgear/scene/sky/cloud.cxx index 5c62bd05..b7b40035 100644 --- a/simgear/scene/sky/cloud.cxx +++ b/simgear/scene/sky/cloud.cxx @@ -298,19 +298,6 @@ SGCloudLayer::setCoverage (Coverage coverage) if (coverage != layer_coverage) { layer_coverage = coverage; rebuild(); - - double coverage_norm = 0.0; - if( coverage == SG_CLOUD_FEW) - coverage_norm = 2.0/8.0; // <1-2 - else if( coverage == SG_CLOUD_SCATTERED ) - coverage_norm = 4.0/8.0; // 3-4 - else if( coverage == SG_CLOUD_BROKEN ) - coverage_norm = 6.0/8.0; // 5-7 - else if( coverage == SG_CLOUD_OVERCAST ) - coverage_norm = 8.0/8.0; // 8 - - layer3D->setCoverage(coverage_norm); - layer3D->applyCoverage(); } } @@ -822,13 +809,13 @@ bool SGCloudLayer::reposition( const SGVec3f& p, const SGVec3f& up, double lon, last_pos = pos; } - layer3D->reposition( p, up, lon, lat, dt, layer_asl); + layer3D->reposition( p, up, lon, lat, dt, layer_asl, speed, direction); return true; } void SGCloudLayer::set_enable3dClouds(bool enable) { - if (layer3D->defined3D && enable) { + if (layer3D->isDefined3D() && enable) { cloud_root->setChildValue(layer3D->getNode(), true); cloud_root->setChildValue(layer_root.get(), false); } else { diff --git a/simgear/scene/sky/cloudfield.cxx b/simgear/scene/sky/cloudfield.cxx index 202311e7..2973e92e 100644 --- a/simgear/scene/sky/cloudfield.cxx +++ b/simgear/scene/sky/cloudfield.cxx @@ -33,9 +33,13 @@ #include #include +#include #include #include +#include + +using namespace std; using std::vector; @@ -60,242 +64,280 @@ using std::vector; using namespace simgear; - float SGCloudField::fieldSize = 50000.0f; double SGCloudField::timer_dt = 0.0; float SGCloudField::view_distance = 20000.0f; +bool SGCloudField::wrap = true; + SGVec3f SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y; -// reposition the cloud layer at the specified origin and orientation + +// Reposition the cloud layer at the specified origin and orientation bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, double lat, - double dt, int asl ) -{ - osg::Matrix T, LON, LAT; + double dt, int asl, float speed, float direction ) { + // Determine any movement of the placed clouds + if (placed_root->getNumChildren() == 0) return false; + + SGVec3 cart; + SGGeodesy::SGGeodToCart(SGGeod::fromRadFt(lon, lat, 0.0f), cart); + osg::Vec3f osg_pos = toOsg(cart); + osg::Quat orient = toOsg(SGQuatd::fromLonLatRad(lon, lat) * SGQuatd::fromRealImag(0, SGVec3d(0, 1, 0))); // Always update the altitude transform, as this allows // the clouds to rise and fall smoothly depending on environment updates. - altitude_transform->setPosition(osg::Vec3d(0.0, 0.0, (double) asl)); - - // Calculating the reposition information is expensive. - // Only perform the reposition every 60 frames. - reposition_count = (reposition_count + 1) % 60; - if ((reposition_count != 0) || !defined3D) return false; + osg::Vec3f alt = orient * osg::Vec3f(0.0f, 0.0f, (float) asl); + altitude_transform->setPosition(alt); - SGGeoc pos = SGGeoc::fromGeod(SGGeod::fromRad(lon, lat)); + // Similarly, always determine the effects of the wind + osg::Vec3f wind = osg::Vec3f(-cos((direction + 180)* SGD_DEGREES_TO_RADIANS) * speed * dt, + sin((direction + 180)* SGD_DEGREES_TO_RADIANS) * speed * dt, + 0.0f); + //cout << "Wind: " << direction << "@" << speed << "\n"; - double dist = SGGeodesy::distanceM(cld_pos, pos); + osg::Vec3f windosg = field_transform->getAttitude() * wind; + field_transform->setPosition(field_transform->getPosition() + windosg); - if (dist > (fieldSize * 2)) { - // First time or very large distance - SGVec3 cart; - SGGeodesy::SGGeodToCart(SGGeod::fromRad(lon, lat), cart); - T.makeTranslate(toOsg(cart)); - - LON.makeRotate(lon, osg::Vec3(0, 0, 1)); - LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0)); - - field_transform->setMatrix( LAT*LON*T ); - 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. - SGGeoc pos = SGGeoc::fromGeod(SGGeod::fromRad(lon, lat)); - - float crs = SGGeoc::courseDeg(cld_pos, pos); - if ((crs < 45.0) || (crs > 315.0)) { - SGGeodesy::advanceRadM(cld_pos, 0.0, fieldSize, cld_pos); + if (!wrap) { + // If we're not wrapping the cloudfield, then we make no effort to reposition + return false; } - if ((crs > 45.0) && (crs < 135.0)) { - SGGeodesy::advanceRadM(cld_pos, SGD_PI_2, fieldSize, cld_pos); + if ((old_pos - osg_pos).length() > fieldSize*2) { + // Big movement - reposition centered to current location. + field_transform->setPosition(osg_pos); + field_transform->setAttitude(orient); + old_pos = osg_pos; + } else { + // delta is the vector from the old position to the new position in cloud-coords + osg::Vec3f delta = field_transform->getAttitude().inverse() * (osg_pos - old_pos); + //cout << "Delta: " << delta.length() << "\n"; + + for (unsigned int i = 0; i < placed_root->getNumChildren(); i++) { + osg::ref_ptr lodnode1 = (osg::LOD*) placed_root->getChild(i); + osg::Vec3f v = delta - lodnode1->getCenter(); + + if ((v.x() < -0.5*fieldSize) || + (v.x() > 0.5*fieldSize) || + (v.y() < -0.5*fieldSize) || + (v.y() > 0.5*fieldSize) ) { + //cout << "V: " << v.x() << ", " << v.y() << "\n"; + + osg::Vec3f shift = osg::Vec3f(0.0f, 0.0f, 0.0f); + if (v.x() > 0.5*fieldSize) { shift += osg::Vec3f(fieldSize, 0.0f, 0.0f); } + if (v.x() < -0.5*fieldSize) { shift -= osg::Vec3f(fieldSize, 0.0f, 0.0f); } + + if (v.y() > 0.5*fieldSize) { shift += osg::Vec3f(0.0f, fieldSize, 0.0f); } + if (v.y() < -0.5*fieldSize) { shift -= osg::Vec3f(0.0f, fieldSize, 0.0f); } + + //cout << "Shift: " << shift.x() << ", " << shift.y() << "\n\n"; + + for (unsigned int j = 0; j < lodnode1->getNumChildren(); j++) { + osg::ref_ptr lodnode2 = (osg::LOD*) lodnode1->getChild(j); + for (unsigned int k = 0; k < lodnode2->getNumChildren(); k++) { + osg::ref_ptr pat =(osg::PositionAttitudeTransform*) lodnode2->getChild(k); + pat->setPosition(pat->getPosition() + shift); + } } - - if ((crs > 135.0) && (crs < 225.0)) { - SGGeodesy::advanceRadM(cld_pos, SGD_PI, fieldSize, cld_pos); } - - if ((crs > 225.0) && (crs < 315.0)) { - SGGeodesy::advanceRadM(cld_pos, SGD_PI + SGD_PI_2, fieldSize, cld_pos); } - - SGVec3 cart; - SGGeodesy::SGGeodToCart(SGGeod::fromRad(cld_pos.getLongitudeRad(), cld_pos.getLatitudeRad()), cart); - T.makeTranslate(toOsg(cart)); - - LON.makeRotate(cld_pos.getLongitudeRad(), osg::Vec3(0, 0, 1)); - LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - cld_pos.getLatitudeRad(), osg::Vec3(0, 1, 0)); - - field_transform->setMatrix( LAT*LON*T ); } // Render the clouds in order from farthest away layer to nearest one. field_root->getStateSet()->setRenderBinDetails(CLOUDS_BIN, "DepthSortedBin"); - return true; } SGCloudField::SGCloudField() : field_root(new osg::Group), - field_transform(new osg::MatrixTransform), - altitude_transform(new osg::PositionAttitudeTransform), - deltax(0.0), - deltay(0.0), - last_course(0.0), - last_coverage(0.0), - coverage(0.0), - reposition_count(0), - defined3D(false) + field_transform(new osg::PositionAttitudeTransform), + altitude_transform(new osg::PositionAttitudeTransform) { - cld_pos = SGGeoc(); + old_pos = osg::Vec3f(0.0f, 0.0f, 0.0f); field_root->addChild(field_transform.get()); field_root->setName("3D Cloud field root"); osg::StateSet *rootSet = field_root->getOrCreateStateSet(); rootSet->setRenderBinDetails(CLOUDS_BIN, "DepthSortedBin"); rootSet->setAttributeAndModes(getFog()); - osg::ref_ptr quad_root = new osg::Group(); + field_transform->addChild(altitude_transform.get()); + placed_root = new osg::Group(); + altitude_transform->addChild(placed_root); +} - for (int i = 0; i < BRANCH_SIZE; i++) { - for (int j = 0; j < BRANCH_SIZE; j++) { - quad[i][j] = new osg::LOD(); - quad[i][j]->setName("Quad"); - quad_root->addChild(quad[i][j].get()); +SGCloudField::~SGCloudField() { } + + +void SGCloudField::clear(void) { + + for(CloudHash::const_iterator itr = cloud_hash.begin(), end = cloud_hash.end(); + itr != end; + ++itr) { + removeCloudFromTree(itr->second); } - int leafs = QUADTREE_SIZE / BRANCH_SIZE; + cloud_hash.clear(); +} - for (int x = 0; x < QUADTREE_SIZE; x++) { - for (int y = 0; y < QUADTREE_SIZE; y++) { - field_group[x][y]= new osg::Switch; - field_group[x][y]->setName("3D cloud group"); +void SGCloudField::applyVisRange(void) +{ + for (unsigned int i = 0; i < placed_root->getNumChildren(); i++) { + osg::ref_ptr lodnode1 = (osg::LOD*) placed_root->getChild(i); + for (unsigned int j = 0; j < lodnode1->getNumChildren(); j++) { + osg::ref_ptr lodnode2 = (osg::LOD*) lodnode1->getChild(j); + for (unsigned int k = 0; k < lodnode2->getNumChildren(); k++) { + lodnode2->setRange(k, 0.0f, view_distance); + } + } + } +} - // Work out where to put this node in the quad tree - int i = x / leafs; - int j = y / leafs; - quad[i][j]->addChild(field_group[x][y].get(), 0.0f, view_distance); +bool SGCloudField::addCloud(float lon, float lat, float alt, int index, osg::ref_ptr geode) { + return addCloud(lon, lat, alt, 0.0f, 0.0f, index, geode); } + +bool SGCloudField::addCloud(float lon, float lat, float alt, float x, float y, int index, osg::ref_ptr geode) { + // If this cloud index already exists, don't replace it. + if (cloud_hash[index]) return false; + + osg::ref_ptr transform = new osg::PositionAttitudeTransform; + + transform->addChild(geode.get()); + addCloudToTree(transform, lon, lat, alt, x, y); + cloud_hash[index] = transform; + return true; } - field_transform->addChild(altitude_transform.get()); +// Remove a give cloud from inside the tree, without removing it from the cloud hash +void SGCloudField::removeCloudFromTree(osg::ref_ptr transform) +{ + osg::ref_ptr lodnode = transform->getParent(0); + lodnode->removeChild(transform); + + // Clean up the LOD nodes if required + if (lodnode->getNumChildren() == 0) { + osg::ref_ptr lodnode1 = lodnode->getParent(0); - // We duplicate the defined field group in a 3x3 array. This way, - // we can simply shift entire groups around. - // TODO: "Bend" the edge groups so when shifted they line up. - // Currently the clouds "jump down" when we reposition them. - for(int x = -1 ; x <= 1 ; x++) { - for(int y = -1 ; y <= 1 ; y++ ) { - osg::ref_ptr transform = - new osg::PositionAttitudeTransform; - transform->addChild(quad_root.get()); - transform->setPosition(osg::Vec3(x*fieldSize, y * fieldSize, 0.0)); + lodnode1->removeChild(lodnode); - altitude_transform->addChild(transform.get()); + if (lodnode1->getNumChildren() == 0) { + placed_root->removeChild(lodnode1); } } } -SGCloudField::~SGCloudField() { +void SGCloudField::addCloudToTree(osg::ref_ptr transform, + float lon, float lat, float alt, float x, float y) { + // Work out where this cloud should go in OSG coordinates. + SGVec3 cart; + SGGeodesy::SGGeodToCart(SGGeod::fromDegFt(lon, lat, alt), cart); + + // Convert to the scenegraph orientation where we just rotate around + // the y axis 180 degrees. + osg::Quat orient = toOsg(SGQuatd::fromLonLatDeg(lon, lat) * SGQuatd::fromRealImag(0, SGVec3d(0, 1, 0))); + osg::Vec3f pos = toOsg(cart) + orient * osg::Vec3f(x, y, 0.0f); + + if (old_pos == osg::Vec3f(0.0f, 0.0f, 0.0f)) { + // First se tup. + SGVec3 fieldcenter; + SGGeodesy::SGGeodToCart(SGGeod::fromDegFt(lon, lat, 0.0f), fieldcenter); + + field_transform->setPosition(toOsg(fieldcenter)); + field_transform->setAttitude(orient); + old_pos = toOsg(fieldcenter); } + pos = pos - field_transform->getPosition(); -void SGCloudField::clear(void) { - for (int x = 0; x < QUADTREE_SIZE; x++) { - for (int y = 0; y < QUADTREE_SIZE; y++) { - int num_children = field_group[x][y]->getNumChildren(); - field_group[x][y]->removeChildren(0, num_children); - } - } - - SGCloudField::defined3D = false; -} + pos = orient.inverse() * pos; + + // We have a two level dynamic quad tree which the cloud will be added + // to. If there are no appropriate nodes in the quad tree, they are + // created as required. + bool found = false; + osg::ref_ptr lodnode1; + osg::ref_ptr lodnode; -// use a table or else we see poping when moving the slider... -static int densTable[][10] = { - {0,0,0,0,0,0,0,0,0,0}, - {1,0,0,0,0,0,0,0,0,0}, - {1,0,0,0,1,0,0,0,0,0}, - {1,0,0,0,1,0,0,1,0,0}, // 30% - {1,0,1,0,1,0,0,1,0,0}, - {1,0,1,0,1,0,1,1,0,0}, // 50% - {1,0,1,0,1,0,1,1,0,1}, - {1,0,1,1,1,0,1,1,0,1}, // 70% - {1,1,1,1,1,0,1,1,0,1}, - {1,1,1,1,1,0,1,1,1,1}, // 90% - {1,1,1,1,1,1,1,1,1,1} -}; - -void SGCloudField::applyCoverage(void) { - - int row = (int) (coverage * 10.0); - if (row > 9) row = 9; - int col = 0; - - if (coverage != last_coverage) { - for (int x = 0; x < QUADTREE_SIZE; x++) { - for (int y = 0; y < QUADTREE_SIZE; y++) { - // Switch on/off the children depending on the required coverage. - int num_children = field_group[x][y]->getNumChildren(); - for (int i = 0; i < num_children; i++) { - if (++col > 9) col = 0; - if ( densTable[row][col] ) { - field_group[x][y]->setValue(i, true); - } else { - field_group[x][y]->setValue(i, false); + for (unsigned int i = 0; (!found) && (i < placed_root->getNumChildren()); i++) { + lodnode1 = (osg::LOD*) placed_root->getChild(i); + if ((lodnode1->getCenter() - pos).length2() < RADIUS_LEVEL_1*RADIUS_LEVEL_1) { + // New cloud is within RADIUS_LEVEL_1 of the center of the LOD node. + //cout << "Adding cloud to existing LoD level 1 node. Distance:" << (lodnode1->getCenter() - pos).length() << "\n"; + found = true; } } + + if (!found) { + lodnode1 = new osg::LOD(); + placed_root->addChild(lodnode1.get()); + //cout << "Adding cloud to new LoD node\n"; } + + // Now check if there is a second level LOD node at an appropriate distance + found = false; + + for (unsigned int j = 0; (!found) && (j < lodnode1->getNumChildren()); j++) { + lodnode = (osg::LOD*) lodnode1->getChild(j); + if ((lodnode->getCenter() - pos).length2() < RADIUS_LEVEL_2*RADIUS_LEVEL_2) { + // We've found the right leaf LOD node + //cout << "Found existing LOD leaf node. Distance:"<< (lodnode->getCenter() - pos).length() << "\n"; + found = true; } } - last_coverage = coverage; + if (!found) { + // No suitable leave node was found, so we need to add one. + lodnode = new osg::LOD(); + lodnode1->addChild(lodnode, 0.0f, 4*RADIUS_LEVEL_1); + //cout << "Adding cloud to new LoD node\n"; } -void SGCloudField::addCloud( SGVec3f& pos, osg::ref_ptr geode) { - defined3D = true; + transform->setPosition(pos); + lodnode->addChild(transform.get(), 0.0f, view_distance); - // Determine which quadtree to put it in. - int x = (int) floor((pos.x() + fieldSize/2.0) * QUADTREE_SIZE / fieldSize); - if (x >= QUADTREE_SIZE) x = (QUADTREE_SIZE - 1); - if (x < 0) x = 0; + lodnode->dirtyBound(); + lodnode1->dirtyBound(); + field_root->dirtyBound(); +} - int y = (int) floor((pos.y() + fieldSize/2.0) * QUADTREE_SIZE / fieldSize); - if (y >= QUADTREE_SIZE) y = (QUADTREE_SIZE - 1); - if (y < 0) y = 0; +bool SGCloudField::deleteCloud(int identifier) { + osg::ref_ptr transform = cloud_hash[identifier]; + if (transform == NULL) return false; - osg::ref_ptr transform = new osg::PositionAttitudeTransform; + removeCloudFromTree(transform); + cloud_hash.erase(identifier); - transform->setPosition(toOsg(pos)); - transform->addChild(geode.get()); + return true; +} - field_group[x][y]->addChild(transform.get(), true); +bool SGCloudField::repositionCloud(int identifier, float lon, float lat, float alt) { + return repositionCloud(identifier, lon, lat, alt, 0.0f, 0.0f); } -void SGCloudField::applyVisRange(void) { +bool SGCloudField::repositionCloud(int identifier, float lon, float lat, float alt, float x, float y) { + osg::ref_ptr transform = cloud_hash[identifier]; - for (int x = 0; x < BRANCH_SIZE; x++) { - for (int y = 0; y < BRANCH_SIZE; y++) { - int num_children = quad[x][y]->getNumChildren(); - for (int i = 0; i < num_children; i++) { - quad[x][y]->setRange(i, 0.0f, view_distance); - } - } + if (transform == NULL) return false; + + removeCloudFromTree(transform); + addCloudToTree(transform, lon, lat, alt, x, y); + return true; } + +bool SGCloudField::isDefined3D(void) { + return (cloud_hash.size() > 0); } -SGCloudField::CloudFog::CloudFog() -{ +SGCloudField::CloudFog::CloudFog() { fog = new osg::Fog; fog->setMode(osg::Fog::EXP2); fog->setDataVariance(osg::Object::DYNAMIC); } -void SGCloudField::updateFog(double visibility, const osg::Vec4f& color) -{ +void SGCloudField::updateFog(double visibility, const osg::Vec4f& color) { const double sqrt_m_log01 = sqrt(-log(0.01)); osg::Fog* fog = CloudFog::instance()->fog.get(); fog->setColor(color); fog->setDensity(sqrt_m_log01 / visibility); } + diff --git a/simgear/scene/sky/cloudfield.hxx b/simgear/scene/sky/cloudfield.hxx index f09f698b..5b7bb6f7 100644 --- a/simgear/scene/sky/cloudfield.hxx +++ b/simgear/scene/sky/cloudfield.hxx @@ -25,6 +25,7 @@ #include #include +#include #include @@ -54,8 +55,10 @@ namespace simgear class EffectGeode; } +typedef std::map > CloudHash; + /** - * A layer of 3D clouds. + * A layer of 3D clouds, defined by lat/long/alt. */ class SGCloudField { @@ -69,44 +72,56 @@ private: float Rnd(float); - // We create a quadtree two levels deep - static const int BRANCH_SIZE = 16; - static const int QUADTREE_SIZE = 32; + // Radius of the LoD nodes for the dynamic quadtrees. + static const float RADIUS_LEVEL_1 = 20000.0f; + static const float RADIUS_LEVEL_2 = 5000.0f; // this is a relative position only, with that we can move all clouds at once SGVec3f relative_position; - // double lon, lat; osg::ref_ptr field_root; - osg::ref_ptr field_transform; + osg::ref_ptr placed_root; + osg::ref_ptr field_transform; osg::ref_ptr altitude_transform; - osg::ref_ptr field_group[QUADTREE_SIZE][QUADTREE_SIZE]; - osg::ref_ptr quad[BRANCH_SIZE][BRANCH_SIZE]; - osg::ref_ptr field_lod; - double deltax, deltay, alt; - double last_course; - float last_coverage; - float coverage; - SGGeoc cld_pos; - int reposition_count; + osg::Vec3f old_pos; + CloudHash cloud_hash; + struct CloudFog : public simgear::Singleton { CloudFog(); osg::ref_ptr fog; }; + + void removeCloudFromTree(osg::ref_ptr transform); + void addCloudToTree(osg::ref_ptr transform, float lon, float lat, float alt, float x, float y); + void applyVisRangeAndCoverage(void); + public: SGCloudField(); ~SGCloudField(); void clear(void); + bool isDefined3D(void); // add one cloud, data is not copied, ownership given void addCloud( SGVec3f& pos, osg::ref_ptr cloud); /** + * Add a new cloud with a given index at a specific point defined by lon/lat and an x/y offset + */ + bool addCloud(float lon, float lat, float alt, int index, osg::ref_ptr geode); + bool addCloud(float lon, float lat, float alt, float x, float y, int index, osg::ref_ptr geode); + + // Cloud handling functions. + bool deleteCloud(int identifier); + bool repositionCloud(int identifier, float lon, float lat, float alt); + bool repositionCloud(int identifier, float lon, float lat, float alt, float x, float y); + + + /** * reposition the cloud layer at the specified origin and * orientation. * @param p position vector @@ -115,9 +130,11 @@ public: * @param lat specifies a rotation about the new Y axis * @param dt the time elapsed since the last call * @param asl altitude of the layer + * @param speed of cloud layer movement (due to wind) + * @param direction of cloud layer movement (due to wind) */ bool reposition( const SGVec3f& p, const SGVec3f& up, - double lon, double lat, double dt, int asl); + double lon, double lat, double dt, int asl, float speed, float direction); osg::Group* getNode() { return field_root.get(); } @@ -129,16 +146,10 @@ public: static float view_distance; static double timer_dt; static float fieldSize; - - bool defined3D; - - float getCoverage(void) { return coverage; } - void setCoverage(float c) { coverage = c; } + static bool wrap; static float getVisRange(void) { return view_distance; } static void setVisRange(float d) { view_distance = d; } - - void applyCoverage(void); void applyVisRange(void); static osg::Fog* getFog() diff --git a/simgear/scene/sky/newcloud.cxx b/simgear/scene/sky/newcloud.cxx index 67acd064..69aa193c 100644 --- a/simgear/scene/sky/newcloud.cxx +++ b/simgear/scene/sky/newcloud.cxx @@ -69,36 +69,22 @@ EffectMap effectMap; double SGNewCloud::sprite_density = 1.0; -SGNewCloud::SGNewCloud(string type, - const SGPath &tex_path, - string tex, - double min_w, - double max_w, - double min_h, - double max_h, - double min_sprite_w, - double max_sprite_w, - double min_sprite_h, - double max_sprite_h, - double b, - int n, - int nt_x, - int nt_y) : - min_width(min_w), - max_width(max_w), - min_height(min_h), - max_height(max_h), - min_sprite_width(min_sprite_w), - max_sprite_width(max_sprite_w), - min_sprite_height(min_sprite_h), - max_sprite_height(max_sprite_h), - bottom_shade(b), - num_sprites(n), - num_textures_x(nt_x), - num_textures_y(nt_y), - texture(tex), - name(type) +SGNewCloud::SGNewCloud(const SGPath &texture_root, const SGPropertyNode *cld_def) { + min_width = cld_def->getDoubleValue("min-cloud-width-m", 500.0); + max_width = cld_def->getDoubleValue("max-cloud-width-m", 1000.0); + min_height = cld_def->getDoubleValue("min-cloud-height-m", min_width); + max_height = cld_def->getDoubleValue("max-cloud-height-m", max_width); + min_sprite_width = cld_def->getDoubleValue("min-sprite-width-m", 200.0); + max_sprite_width = cld_def->getDoubleValue("max-sprite-width-m", min_sprite_width); + min_sprite_height = cld_def->getDoubleValue("min-sprite-height-m", min_sprite_width); + max_sprite_height = cld_def->getDoubleValue("max-sprite-height-m", max_sprite_width); + num_sprites = cld_def->getIntValue("num-sprites", 20); + num_textures_x = cld_def->getIntValue("num-textures-x", 4); + num_textures_y = cld_def->getIntValue("num-textures-y", 4); + bottom_shade = cld_def->getDoubleValue("bottom-shade", 1.0); + texture = cld_def->getStringValue("texture", "cl_cumulus.png"); + // Create a new Effect for the texture, if required. EffectMap::iterator iter = effectMap.find(texture); if (iter == effectMap.end()) { @@ -109,7 +95,7 @@ SGNewCloud::SGNewCloud(string type, "image"), texture); ref_ptr options - = makeOptionsFromPath(tex_path); + = makeOptionsFromPath(texture_root); ref_ptr sgOptions = new SGReaderWriterXMLOptions(*options.get()); if ((effect = makeEffect(pcloudEffect, true, sgOptions.get()))) diff --git a/simgear/scene/sky/newcloud.hxx b/simgear/scene/sky/newcloud.hxx index 26987933..941b9ba1 100644 --- a/simgear/scene/sky/newcloud.hxx +++ b/simgear/scene/sky/newcloud.hxx @@ -40,21 +40,7 @@ using std::vector; class SGNewCloud { public: - SGNewCloud(string type, - const SGPath &tex_path, - string tex, - double min_w, - double max_w, - double min_h, - double max_h, - double min_sprite_w, - double max_sprite_w, - double min_sprite_h, - double max_sprite_h, - double b, - int n, - int nt_x, - int nt_y); + SGNewCloud(const SGPath &texture_root, const SGPropertyNode *cld_def); ~SGNewCloud(); @@ -87,8 +73,7 @@ private: int num_sprites; int num_textures_x; int num_textures_y; - const string texture; - const string name; + string texture; osg::Geometry* quad; osg::ref_ptr effect; static double sprite_density; diff --git a/simgear/scene/sky/sky.cxx b/simgear/scene/sky/sky.cxx index 01f5a256..e21adaa3 100644 --- a/simgear/scene/sky/sky.cxx +++ b/simgear/scene/sky/sky.cxx @@ -178,11 +178,13 @@ bool SGSky::reposition( const SGSkyState &st, const SGEphemeris& eph, double dt moon->reposition( moon_ra, moon_dec, st.moon_dist ); for ( unsigned i = 0; i < cloud_layers.size(); ++i ) { - if ( cloud_layers[i]->getCoverage() != SGCloudLayer::SG_CLOUD_CLEAR ) { + if ( cloud_layers[i]->getCoverage() != SGCloudLayer::SG_CLOUD_CLEAR || + cloud_layers[i]->get_layer3D()->isDefined3D() ) { cloud_layers[i]->reposition( zero_elev, view_up, lon, lat, alt, dt); - } else + } else { cloud_layers[i]->getNode()->setAllChildrenOff(); } + } return true; } @@ -272,7 +274,7 @@ void SGSky::modify_vis( float alt, float time_factor ) { } if ( cloud_layers[i]->getCoverage() == SGCloudLayer::SG_CLOUD_CLEAR || - cloud_layers[i]->get_layer3D()->defined3D) { + cloud_layers[i]->get_layer3D()->isDefined3D()) { // do nothing, clear layers aren't drawn, don't affect // visibility andn dont' need to be faded in or out. } else if ( (cloud_layers[i]->getCoverage() == -- 2.39.5