diff --git a/simgear/scene/sky/CloudShaderGeometry.cxx b/simgear/scene/sky/CloudShaderGeometry.cxx index 6fe9f8cf..eaa9450f 100755 --- a/simgear/scene/sky/CloudShaderGeometry.cxx +++ b/simgear/scene/sky/CloudShaderGeometry.cxx @@ -35,16 +35,36 @@ 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. + + // 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; + } + } + 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); + 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); _geometry->draw(renderInfo); } } @@ -56,10 +76,10 @@ BoundingBox CloudShaderGeometry::computeBound() const 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() )); + 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() )); } return bb; } @@ -95,7 +115,7 @@ bool CloudShaderGeometry_readLocalData(Object& obj, Input& fr) fr[4].getFloat(w) && fr[4].getFloat(h)&& fr[4].getFloat(s)) { fr += 5; //SGVec3f* v = new SGVec3f(v.x(), v.y(), v.z()); - geom._cloudsprites.push_back(CloudShaderGeometry::CloudSprite(v, tx, ty, w, h,s)); + geom._cloudsprites.push_back(new CloudShaderGeometry::CloudSprite(v, tx, ty, w, h,s)); } else { ++fr; } @@ -113,14 +133,14 @@ bool CloudShaderGeometry_writeLocalData(const Object& obj, Output& fw) fw.indent() << "instances " << geom._cloudsprites.size() << std::endl; fw.indent() << "{" << std::endl; fw.moveIn(); - for (CloudShaderGeometry::CloudSpriteList::const_iterator iter + for (CloudShaderGeometry::CloudSpriteList::const_iterator itr = geom._cloudsprites.begin(); - iter != geom._cloudsprites.end(); - ++iter) { - fw.indent() << iter->position.x() << " " << iter->position.y() << " " - << iter->position.z() << " " << iter->texture_index_x << " " - << iter->texture_index_y << " " - << iter->width << " " << iter->height << " " << iter->shade << std::endl; + 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.moveOut(); fw.indent() << "}" << std::endl; diff --git a/simgear/scene/sky/CloudShaderGeometry.hxx b/simgear/scene/sky/CloudShaderGeometry.hxx index e28928ed..1f0dd10d 100755 --- a/simgear/scene/sky/CloudShaderGeometry.hxx +++ b/simgear/scene/sky/CloudShaderGeometry.hxx @@ -66,7 +66,7 @@ class CloudShaderGeometry : public osg::Drawable META_Object(flightgear, CloudShaderGeometry); struct CloudSprite { - CloudSprite(const SGVec3f& p, int tx, int ty, float w, float h, float s) : + CloudSprite(SGVec3f& p, int tx, int ty, float w, float h, float s) : position(p), texture_index_x(tx), texture_index_y(ty), width(w), height(h), shade(s) { } @@ -78,16 +78,16 @@ class CloudShaderGeometry : public osg::Drawable float shade; }; - typedef std::vector CloudSpriteList; + typedef std::vector CloudSpriteList; - void insert(const CloudSprite& t) + void insert(CloudSprite* t) { _cloudsprites.push_back(t); } - void insert(const SGVec3f& p, int tx, int ty, float w, float h, float s) - { insert(CloudSprite(p, tx, ty, w, h, s)); } + void insert(SGVec3f& p, int tx, int ty, float w, float h, float s) + { insert(new CloudSprite(p, tx, ty, w, h, s)); } unsigned getNumCloudSprite() const { return _cloudsprites.size(); } - const CloudSprite& getCloudSprite(unsigned i) const + CloudSprite* getCloudSprite(unsigned i) const { return _cloudsprites[i]; } CloudSpriteList _cloudsprites; @@ -102,28 +102,28 @@ class CloudShaderGeometry : public osg::Drawable _geometry = geometry; } - void addSprite(const SGVec3f& p, int tx, int ty, float w, float h, float s, float cull) + void addSprite(SGVec3f& p, int tx, int ty, float w, float h, float s, float cull) { // Only add the sprite if it is further than the cull distance to all other sprites - for (CloudShaderGeometry::CloudSpriteList::const_iterator iter = _cloudsprites.begin(); + for (CloudShaderGeometry::CloudSpriteList::iterator iter = _cloudsprites.begin(); iter != _cloudsprites.end(); ++iter) { - if (distSqr(iter->position, p) < cull) + if (distSqr((*iter)->position, p) < cull) { // Too close - cull it return; } } - _cloudsprites.push_back(CloudSprite(p, tx, ty, w, h, s)); + _cloudsprites.push_back(new CloudSprite(p, tx, ty, w, h, s)); } - + osg::ref_ptr _geometry; int varieties_x; int varieties_y; - + protected: virtual ~CloudShaderGeometry() {} diff --git a/simgear/scene/sky/cloudfield.cxx b/simgear/scene/sky/cloudfield.cxx index f23b0f5c..5012d942 100644 --- a/simgear/scene/sky/cloudfield.cxx +++ b/simgear/scene/sky/cloudfield.cxx @@ -74,92 +74,109 @@ void SGCloudField::set_density(float density) { bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, double lat, double dt ) { - osg::Matrix T, LON, LAT; - + osg::Matrix T, LON, LAT; + + SGGeoc pos = SGGeoc::fromGeod(SGGeod::fromRad(lon, lat)); + + double dist = SGGeodesy::distanceM(cld_pos, pos); + + if (dist > (fieldSize * 2)) { + // First time or very large distance + SGVec3 cart; + SGGeodesy::SGGeodToCart(SGGeod::fromRad(lon, lat), cart); + T.makeTranslate(cart.osg()); + LON.makeRotate(lon, osg::Vec3(0, 0, 1)); LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0)); - osg::Vec3 u = up.osg(); - u.normalize(); - - if ((last_lon == 0.0f) || (fabs(last_lon - lon) > 1.0) || (fabs(last_lat - lat) > 1.0)) - { - // First time, or large delta requires repositioning from scratch. - // TODO: Make this calculation better - a 0.5 degree shift will take a number - // of reposition calls to correct at the moment. - - // combine p and asl (meters) to get translation offset. - osg::Vec3 pos = p.osg(); - pos += u; - - T.makeTranslate(pos); - - field_transform->setMatrix( LAT*LON*T ); - last_lon = lon; - last_lat = lat; - last_pos = p.osg(); + 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); } - else - { - // Rotation positon back to simple X-Z space. - osg::Vec3 pos = last_pos; - pos += u; - - T.makeTranslate(pos); - - osg::Matrix U = LAT*LON; - osg::Vec3 x = osg::Vec3f(fieldSize, 0.0, 0.0)*U; - osg::Vec3 y = osg::Vec3f(0.0, fieldSize, 0.0)*U; - - osg::Matrix V; - V.makeIdentity(); - V.invert(U*T); - - osg::Vec3 q = pos*V; - - // Shift the field if we've moved away from the centre box. - if (q.x() > fieldSize) last_pos = last_pos + x; - if (q.x() < -fieldSize) last_pos = last_pos - x; - if (q.y() > fieldSize) last_pos = last_pos + y; - if (q.y() < -fieldSize) last_pos = last_pos - y; - - pos = last_pos; - pos += u; - - T.makeTranslate(pos); - field_transform->setMatrix( LAT*LON*T ); + + if ((crs > 45.0) && (crs < 135.0)) { + SGGeodesy::advanceRadM(cld_pos, SGD_PI_2, fieldSize, cld_pos); } + + 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(cart.osg()); + + 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 ); + } return true; } SGCloudField::SGCloudField() : field_root(new osg::Group), field_transform(new osg::MatrixTransform), - field_group(new osg::Switch), deltax(0.0), deltay(0.0), - last_lon(0.0), - last_lat(0.0), last_course(0.0), last_density(0.0), defined3D(false) { - field_root->addChild(field_transform.get()); - field_group->setName("3Dcloud"); - - // We duplicate the defined field group in a 3x3 array. This way, - // we can simply shift entire groups around. - for(int x = -1 ; x <= 1 ; x++) { - for(int y = -1 ; y <= 1 ; y++ ) { - osg::ref_ptr transform = - new osg::PositionAttitudeTransform; - transform->addChild(field_group.get()); - transform->setPosition(osg::Vec3(x*fieldSize, y * fieldSize, 0.0)); - - field_transform->addChild(transform.get()); - } + cld_pos = SGGeoc(); + field_root->addChild(field_transform.get()); + + osg::ref_ptr quad_root = new osg::Group(); + osg::ref_ptr quad[BRANCH_SIZE][BRANCH_SIZE]; + + 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()); } + } + + 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"); + + // Work out where to put this node in the quad tree + int i = (int) (BRANCH_SIZE * ((float) x) / ((float) QUADTREE_SIZE)); + int j = (int) (BRANCH_SIZE * ((float) y) / ((float) QUADTREE_SIZE)); + quad[i][j]->addChild(field_group[x][y].get(), 0.0f, 20000.0f); + } + } + // 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)); + + field_transform->addChild(transform.get()); + } + } } SGCloudField::~SGCloudField() { @@ -167,12 +184,17 @@ SGCloudField::~SGCloudField() { void SGCloudField::clear(void) { - int num_children = field_group->getNumChildren(); + for (int x = 0; x < QUADTREE_SIZE; x++) { + for (int y = 0; y < QUADTREE_SIZE; y++) { + int num_children = field_group[x][y]->getNumChildren(); - for (int i = 0; i < num_children; i++) { - field_group->removeChild(i); + for (int i = 0; i < num_children; i++) { + field_group[x][y]->removeChild(i); + } } - SGCloudField::defined3D = false; + } + + SGCloudField::defined3D = false; } // use a table or else we see poping when moving the slider... @@ -194,18 +216,22 @@ void SGCloudField::applyDensity(void) { int row = (int) (density / 10.0); int col = 0; - int num_children = field_group->getNumChildren(); if (density != last_density) { + 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 density. - for (int i = 0; i < num_children; i++) { + 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->setValue(i, true); + field_group[x][y]->setValue(i, true); } else { - field_group->setValue(i, false); + field_group[x][y]->setValue(i, false); } + } } + } } last_density = density; @@ -213,11 +239,21 @@ void SGCloudField::applyDensity(void) { void SGCloudField::addCloud( SGVec3f& pos, SGNewCloud *cloud) { defined3D = true; - osg::ref_ptr lod = cloud->genCloud(); + osg::ref_ptr geode = cloud->genCloud(); + + // 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; + + 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; + osg::ref_ptr transform = new osg::PositionAttitudeTransform; transform->setPosition(pos.osg()); - transform->addChild(lod.get()); - - field_group->addChild(transform.get()); + transform->addChild(geode.get()); + + field_group[x][y]->addChild(transform.get()); } diff --git a/simgear/scene/sky/cloudfield.hxx b/simgear/scene/sky/cloudfield.hxx index dd43669b..cd99f8af 100644 --- a/simgear/scene/sky/cloudfield.hxx +++ b/simgear/scene/sky/cloudfield.hxx @@ -56,6 +56,10 @@ private: }; float Rnd(float); + + // We create a quadtree two levels deep + static const int BRANCH_SIZE = 16; + static const int QUADTREE_SIZE = 32; // this is a relative position only, with that we can move all clouds at once sgVec3 relative_position; @@ -63,13 +67,14 @@ private: osg::ref_ptr field_root; osg::ref_ptr field_transform; - osg::ref_ptr field_group; + osg::ref_ptr field_group[QUADTREE_SIZE][QUADTREE_SIZE]; + osg::ref_ptr field_lod; double deltax, deltay, alt; - double last_lon, last_lat, last_course; + double last_course; sgSphere field_sphere; float last_density; - osg::Vec3 last_pos; + SGGeoc cld_pos; public: diff --git a/simgear/scene/sky/newcloud.cxx b/simgear/scene/sky/newcloud.cxx index 1ab787e6..bf2ffca4 100644 --- a/simgear/scene/sky/newcloud.cxx +++ b/simgear/scene/sky/newcloud.cxx @@ -65,7 +65,6 @@ static char vertexShaderSource[] = "#version 120\n" "\n" "varying float fogFactor;\n" - "varying float alphaBlend;\n" "attribute float textureIndexX;\n" "attribute float textureIndexY;\n" "attribute float wScale;\n" @@ -103,25 +102,22 @@ static char vertexShaderSource[] = " vec4 backlight = 0.8 * gl_LightSource[0].ambient + 0.2 * gl_LightSource[0].diffuse;\n" " gl_FrontColor = mix(backlight, gl_LightSource[0].diffuse, n);\n" " gl_FrontColor += gl_FrontLightModelProduct.sceneColor;\n" +// As we get within 100m of the sprite, it is faded out " gl_FrontColor.a = smoothstep(10.0, 100.0, fogCoord);\n" " gl_BackColor = gl_FrontColor;\n" // Fog doesn't affect clouds as much as other objects. - " fogFactor = exp( -gl_Fog.density * fogCoord);\n" + " fogFactor = exp( -gl_Fog.density * fogCoord * 0.5);\n" " fogFactor = clamp(fogFactor, 0.0, 1.0);\n" -// As we get within 100m of the sprite, it is faded out - " alphaBlend = smoothstep(10.0, 100.0, fogCoord);\n" "}\n"; static char fragmentShaderSource[] = "uniform sampler2D baseTexture; \n" "varying float fogFactor;\n" - "varying float alphaBlend;\n" "\n" "void main(void)\n" "{\n" " vec4 base = texture2D( baseTexture, gl_TexCoord[0].st);\n" " vec4 finalColor = base * gl_Color;\n" -// " finalColor.a = min(alphaBlend, finalColor.a);\n" " gl_FragColor = mix(gl_Fog.color, finalColor, fogFactor );\n" "}\n"; @@ -238,12 +234,14 @@ SGNewCloud::SGNewCloud(const SGPath &tex_path, } else { stateSet = iter->second.get(); } + + quad = createOrthQuad(min_sprite_width, min_sprite_height, num_textures_x, num_textures_y); } SGNewCloud::~SGNewCloud() { } -osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y) +osg::Geometry* SGNewCloud::createOrthQuad(float w, float h, int varieties_x, int varieties_y) { // Create front and back polygons so we don't need to screw around // with two-sided lighting in the shader. @@ -292,16 +290,16 @@ static float Rnd(float n) { return n * (-0.5f + (sg_random() + sg_random()) / 2.0f); } -osg::ref_ptr SGNewCloud::genCloud() { - LOD* result = new LOD; +osg::ref_ptr SGNewCloud::genCloud() { Geode* geode = new Geode; CloudShaderGeometry* sg = new CloudShaderGeometry(num_textures_x, num_textures_y); - Geometry* quad = createOrthQuad(min_sprite_width, min_sprite_height, num_textures_x, num_textures_y); - // Determine how big this specific cloud instance is. - float width = min_width + sg_random() * (max_width - min_width); - float height = min_height + sg_random() * (max_height - min_height); + // Determine how big this specific cloud instance is. Note that we subtract + // the sprite size because the width/height is used to define the limits of + // the center of the sprites, not their edges. + float width = min_width + sg_random() * (max_width - min_width) - max_sprite_width; + float height = min_height + sg_random() * (max_height - min_height) - max_sprite_height; // Determine the cull distance. This is used to remove sprites that are too close together. // The value is squared as we use vector calculations. @@ -309,10 +307,14 @@ osg::ref_ptr SGNewCloud::genCloud() { for (int i = 0; i < num_sprites; i++) { - // Determine the position of the sprite. - SGVec3f *pos = new SGVec3f(Rnd(width), - Rnd(width), - Rnd(height)); + // Determine the position of the sprite. Rather than being completely random, + // sprites are placed on a squashed sphere. + double theta = sg_random() * SGD_2PI; + float x = width * cos(theta) * 0.5f; + float y = width * sin(theta) * 0.5f; + float z = height * cos(sg_random() * SGD_2PI) * 0.5f; + + SGVec3f *pos = new SGVec3f(x, y, z); // Determine the height and width as scaling factors on the minimum size (used to create the quad) float sprite_width = 1.0f + sg_random() * (max_sprite_width - min_sprite_width) / min_sprite_width; @@ -320,10 +322,10 @@ osg::ref_ptr SGNewCloud::genCloud() { // The shade varies from bottom_shade to 1.0 non-linearly float shade; - if (pos->z() > 0.0f) { + if (z > 0.0f) { shade = 1.0f; } else { - shade = ((2 * pos->z() + height) / height) * (1 - bottom_shade) + bottom_shade; + shade = ((2 * z + height) / height) * (1 - bottom_shade) + bottom_shade; } // Determine the sprite texture indexes; @@ -340,6 +342,5 @@ osg::ref_ptr SGNewCloud::genCloud() { geode->addDrawable(sg); geode->setName("3D cloud"); geode->setStateSet(stateSet.get()); - result->addChild(geode, 0, 20000); - return result; + return geode; } diff --git a/simgear/scene/sky/newcloud.hxx b/simgear/scene/sky/newcloud.hxx index 3cb93dd4..76ded5e9 100644 --- a/simgear/scene/sky/newcloud.hxx +++ b/simgear/scene/sky/newcloud.hxx @@ -58,7 +58,7 @@ public: ~SGNewCloud(); // Generate a Cloud - osg::ref_ptr genCloud (); + osg::ref_ptr genCloud (); private: @@ -75,9 +75,11 @@ private: int num_textures_x; int num_textures_y; const string texture; - + osg::Geometry* quad; osg::ref_ptr stateSet; + osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y); + public: }; diff --git a/simgear/scene/sky/sky.cxx b/simgear/scene/sky/sky.cxx index 4b6e4743..6772e260 100644 --- a/simgear/scene/sky/sky.cxx +++ b/simgear/scene/sky/sky.cxx @@ -187,19 +187,6 @@ SGSky::get_cloud_layer_count () const return cloud_layers.size(); } -void SGSky::set_3dClouds(bool enable) -{ - for ( unsigned i = 0; i < cloud_layers.size(); ++i ) { - cloud_layers[i]->set_enable3dClouds(enable); - } - - clouds_3d_enabled = enable; -} - -bool SGSky::get_3dClouds() const { - return clouds_3d_enabled; -} - double SGSky::get_3dCloudDensity() const { return SGCloudField::get_density(); } @@ -250,7 +237,7 @@ void SGSky::modify_vis( float alt, float time_factor ) { } if ( cloud_layers[i]->getCoverage() == SGCloudLayer::SG_CLOUD_CLEAR || - get_3dClouds()) { + cloud_layers[i]->get_layer3D()->defined3D) { // 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() == diff --git a/simgear/scene/sky/sky.hxx b/simgear/scene/sky/sky.hxx index c7308784..899213d8 100644 --- a/simgear/scene/sky/sky.hxx +++ b/simgear/scene/sky/sky.hxx @@ -414,14 +414,6 @@ public: effective_visibility = visibility = (v <= 25.0) ? 25.0 : v; } - /** Get whether 3D clouds are enabled */ - virtual bool get_3dClouds() const; - - /** Set whether 3D clouds are enabled - * @param enable Whether to enable 3D clouds - */ - virtual void set_3dClouds(bool enable); - /** Get 3D cloud density */ virtual double get_3dCloudDensity() const;