]> git.mxchange.org Git - simgear.git/commitdiff
Stuart Buchanan :
authorfredb <fredb>
Thu, 6 Nov 2008 21:58:07 +0000 (21:58 +0000)
committerfredb <fredb>
Thu, 6 Nov 2008 21:58:07 +0000 (21:58 +0000)
It fixes the following issues (to a greater or lesser extent):
1) Performance. Quad trees used to improve culling, and the sprites are placed on the surface of a sphere rather than
randomly throughout the cloud, requiring fewer textures. This saves about 5-10fps on my machine.
2) Disabled 3D clouds have no performance impact. Previously they were still in the scenegraph. Now they are removed.
3) Clouds are now loaded on start-up, and don't require the scenario to be changed, they also work with METAR.
4) The cloud field is shifted as you travel. There's a small bug in that the clouds "jump" as you reach the edge of the field.
5) Iterative sorting of sprites. This doesn't appear to solve the alpha blending problem completely, but may help a bit.

simgear/scene/sky/CloudShaderGeometry.cxx
simgear/scene/sky/CloudShaderGeometry.hxx
simgear/scene/sky/cloudfield.cxx
simgear/scene/sky/cloudfield.hxx
simgear/scene/sky/newcloud.cxx
simgear/scene/sky/newcloud.hxx
simgear/scene/sky/sky.cxx
simgear/scene/sky/sky.hxx

index 6fe9f8cfbaf28f2584aafd789a764af0e687e5f2..eaa9450fe9ea1f36f2345462e12605e0dffb4447 100755 (executable)
@@ -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;
index e28928ed56f7d0d102cfbd9aa450d75efd48b045..1f0dd10d413b27aae12356b6a78e6084db43c11e 100755 (executable)
@@ -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<CloudSprite> CloudSpriteList;
+        typedef std::vector<CloudSprite*> 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<osg::Drawable> _geometry;
 
         int varieties_x;
         int varieties_y;
-
+        
     protected:
     
         virtual ~CloudShaderGeometry() {}
index f23b0f5c8dde471d4220e282513fdbb956e5d676..5012d942a2a2fa4dca7479dec900bd86e6743b2e 100644 (file)
@@ -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<double> 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);
+        }
+        
+        if ((crs > 45.0) && (crs < 135.0)) {
+            SGGeodesy::advanceRadM(cld_pos, SGD_PI_2, 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 > 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<double> 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<osg::PositionAttitudeTransform> 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<osg::Group> quad_root = new osg::Group();
+    osg::ref_ptr<osg::LOD> 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<osg::PositionAttitudeTransform> 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<osg::LOD> lod = cloud->genCloud();
+        osg::ref_ptr<osg::Geode> 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<osg::PositionAttitudeTransform> 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());
 }
index dd43669b95e382072655d2af529c467574b05144..cd99f8afb230a8ea2bd45c27ddbb7246f566c406 100644 (file)
@@ -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<osg::Group> field_root;
         osg::ref_ptr<osg::MatrixTransform> field_transform;
-        osg::ref_ptr<osg::Switch> field_group;
+        osg::ref_ptr<osg::Switch> field_group[QUADTREE_SIZE][QUADTREE_SIZE];
+        osg::ref_ptr<osg::LOD> 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:
 
index 1ab787e6bcfaa09560b9dffff00e4baca20b45b0..bf2ffca4de769d9c4b2d1c454e94083456d62a64 100644 (file)
@@ -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<LOD> SGNewCloud::genCloud() {
-    LOD* result = new LOD;
+osg::ref_ptr<Geode> 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<LOD> 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<LOD> 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<LOD> SGNewCloud::genCloud() {
     geode->addDrawable(sg);
     geode->setName("3D cloud");
     geode->setStateSet(stateSet.get());
-    result->addChild(geode, 0, 20000);
-    return result;
+    return geode;
 }
index 3cb93dd42144c0229be2cc628ad30772a83e42e1..76ded5e93f6df839d0d82a4938e549d82c0b2c53 100644 (file)
@@ -58,7 +58,7 @@ public:
        ~SGNewCloud();
 
         // Generate a Cloud
-        osg::ref_ptr<osg::LOD> genCloud ();
+        osg::ref_ptr<osg::Geode> genCloud ();
 
 private:
 
@@ -75,9 +75,11 @@ private:
         int num_textures_x;
         int num_textures_y;
         const string texture;
-        
+        osg::Geometry* quad;
         osg::ref_ptr<osg::StateSet> stateSet;
 
+        osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y);
+
 public:
 
 };
index 4b6e47438dd92aaa7bf1f0f6a026ef6eb81f4bfa..6772e2603341449d9ae98bcfd1273c2968697dc6 100644 (file)
@@ -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() == 
index c73087849f28ae90d004770ad0d8c9fa7d73a13e..899213d89d5e329bd4e3971908b734ee5c6c2e9e 100644 (file)
@@ -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;