- Removes the cloud type re-use code - I think they aren't worth the graphical artefacts that they cause in light of Tim's improvements
- Changes the transparency of the clouds. Previously, the clouds were transparent at 0m distance, opaque at 200m, then gradually more transparent to the fog limits. This meant they were generally quite transparent. Now, they are opaque from 200m to 15km, then become transparent at 20km. A side effect of this is that the current textures could probably benefit from being made slightly transparent to improve the blending of the sprites against each other.
This commit is contained in:
fredb
2008-12-11 08:24:35 +00:00
parent 4da58e8846
commit e0a07b7a92
4 changed files with 70 additions and 138 deletions

View File

@@ -60,13 +60,9 @@ using namespace simgear;
using namespace osg;
typedef std::map<std::string, osg::ref_ptr<osg::StateSet> > StateSetMap;
typedef std::vector< osg::ref_ptr<osg::Geode> > GeodeList;
typedef std::map<std::string, GeodeList*> CloudMap;
StateSetMap cloudTextureMap;
static CloudMap cloudMap;
double SGNewCloud::sprite_density = 1.0;
unsigned int SGNewCloud::num_flavours = 10;
static char vertexShaderSource[] =
"#version 120\n"
@@ -113,8 +109,8 @@ static char vertexShaderSource[] =
" vec4 backlight = 0.9 * gl_LightSource[0].ambient + 0.1 * 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"
// As we get within 100m of the sprite, it is faded out. Equally at large distances it also fades out.
" gl_FrontColor.a = min(smoothstep(10.0, 100.0, fogCoord), 1 - smoothstep(15000.0, 20000.0, fogCoord));\n"
" gl_BackColor = gl_FrontColor;\n"
// Fog doesn't affect clouds as much as other objects.
" fogFactor = exp( -gl_Fog.density * fogCoord * 0.5);\n"
@@ -285,119 +281,86 @@ static float Rnd(float n) {
osg::ref_ptr<Geode> SGNewCloud::genCloud() {
CloudMap::iterator iter = cloudMap.find(name);
osg::ref_ptr<osg::Geode> geode;
osg::ref_ptr<osg::Geode> geode = new Geode;
CloudShaderGeometry* sg = new CloudShaderGeometry(num_textures_x, num_textures_y, max_width, max_height);
// We generate up to num_flavours of different versions
// of the same cloud before we start re-using them. This
// allows us to strike a balance between performance and
// visual complexity.
// 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) - min_sprite_width;
float height = min_height + sg_random() * (max_height - min_height) - min_sprite_height;
if (iter == cloudMap.end() || (*iter).second->size() < num_flavours)
// Determine the cull distance. This is used to remove sprites that are too close together.
// The value is squared as we use vector calculations.
float cull_distance_squared = min_sprite_height * min_sprite_height * 0.1f;
// The number of sprites we actually used is a function of the (user-controlled) density
int n_sprites = num_sprites * sprite_density;
for (int i = 0; i < n_sprites; i++)
{
// Determine the position of the sprite. Rather than being completely random,
// we place them on the surface of a distorted sphere. However, we place
// the first and second sprites on the top and bottom, and the third in the
// center of the sphere (and at maximum size) to ensure good coverage and
// reduce the chance of there being "holes" in our cloud.
float x, y, z;
geode = new Geode;
CloudShaderGeometry* sg = new CloudShaderGeometry(num_textures_x, num_textures_y, max_width, max_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) - min_sprite_width;
float height = min_height + sg_random() * (max_height - min_height) - min_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.
float cull_distance_squared = min_sprite_height * min_sprite_height * 0.1f;
// The number of sprites we actually used is a function of the (user-controlled) density
int n_sprites = num_sprites * sprite_density;
for (int i = 0; i < n_sprites; i++)
{
// Determine the position of the sprite. Rather than being completely random,
// we place them on the surface of a distorted sphere. However, we place
// the first and second sprites on the top and bottom, and the third in the
// center of the sphere (and at maximum size) to ensure good coverage and
// reduce the chance of there being "holes" in our cloud.
float x, y, z;
if (i == 0) {
x = 0;
y = 0;
z = height * 0.5f;
} else if (i == 1) {
x = 0;
y = 0;
z = - height * 0.5f;
} else if (i == 2) {
x = 0;
y = 0;
z = 0;
} else {
double theta = sg_random() * SGD_2PI;
double elev = sg_random() * SGD_PI;
x = width * cos(theta) * 0.5f * sin(elev);
y = width * sin(theta) * 0.5f * sin(elev);
z = height * cos(elev) * 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;
float sprite_height = 1.0f + sg_random() * (max_sprite_height - min_sprite_height) / min_sprite_height;
if (i == 2) {
// The center sprite is always maximum size to fill up any holes.
sprite_width = 1.0f + (max_sprite_width - min_sprite_width) / min_sprite_width;
sprite_height = 1.0f + (max_sprite_height - min_sprite_height) / min_sprite_height;
}
// Determine the sprite texture indexes;
int index_x = (int) floor(sg_random() * num_textures_x);
if (index_x == num_textures_x) { index_x--; }
int index_y = (int) floor(sg_random() * num_textures_y);
if (index_y == num_textures_y) { index_y--; }
sg->addSprite(*pos,
index_x,
index_y,
sprite_width,
sprite_height,
bottom_shade,
cull_distance_squared,
height * 0.5f);
if (i == 0) {
x = 0;
y = 0;
z = height * 0.5f;
} else if (i == 1) {
x = 0;
y = 0;
z = - height * 0.5f;
} else if (i == 2) {
x = 0;
y = 0;
z = 0;
} else {
double theta = sg_random() * SGD_2PI;
double elev = sg_random() * SGD_PI;
x = width * cos(theta) * 0.5f * sin(elev);
y = width * sin(theta) * 0.5f * sin(elev);
z = height * cos(elev) * 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;
float sprite_height = 1.0f + sg_random() * (max_sprite_height - min_sprite_height) / min_sprite_height;
sg->setGeometry(quad);
geode->addDrawable(sg);
geode->setName("3D cloud");
geode->setStateSet(stateSet.get());
if (iter == cloudMap.end())
{
// This is the first of this cloud to be generated.
GeodeList* geodelist = new GeodeList;
geodelist->push_back(geode);
cloudMap.insert(CloudMap::value_type(name, geodelist));
if (i == 2) {
// The center sprite is always maximum size to fill up any holes.
sprite_width = 1.0f + (max_sprite_width - min_sprite_width) / min_sprite_width;
sprite_height = 1.0f + (max_sprite_height - min_sprite_height) / min_sprite_height;
}
else
{
// Add the new cloud to the list of geodes
(*iter).second->push_back(geode);
}
} else {
int index = sg_random() * num_flavours;
if (index == num_flavours) index--;
// Determine the sprite texture indexes;
int index_x = (int) floor(sg_random() * num_textures_x);
if (index_x == num_textures_x) { index_x--; }
geode = iter->second->at(index);
int index_y = (int) floor(sg_random() * num_textures_y);
if (index_y == num_textures_y) { index_y--; }
sg->addSprite(*pos,
index_x,
index_y,
sprite_width,
sprite_height,
bottom_shade,
cull_distance_squared,
height * 0.5f);
}
sg->setGeometry(quad);
geode->addDrawable(sg);
geode->setName("3D cloud");
geode->setStateSet(stateSet.get());
return geode;
}

View File

@@ -72,19 +72,6 @@ public:
sprite_density = d;
}
static int getNumFlavours(void)
{
return num_flavours;
}
// Set the number of flavours of this cloud.
// This is the number of different instances
// to generate.
static void setNumFlavours(int d)
{
num_flavours = d;
}
private:
@@ -105,7 +92,6 @@ private:
osg::Geometry* quad;
osg::ref_ptr<osg::StateSet> stateSet;
static double sprite_density;
static unsigned int num_flavours;
osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y);

View File

@@ -216,15 +216,6 @@ void SGSky::set_3dCloudVisRange(float vis)
}
}
float SGSky::get_3dCloudNumFlavours() const {
return (float) SGNewCloud::getNumFlavours();
}
void SGSky::set_3dCloudNumFlavours(float n)
{
SGNewCloud::setNumFlavours((int) n);
}
void SGSky::texture_path( const string& path ) {
tex_path = SGPath( path );
}

View File

@@ -430,14 +430,6 @@ public:
*/
virtual void set_3dCloudVisRange(float vis);
/** Get 3D cloud number of flavours*/
virtual float get_3dCloudNumFlavours() const;
/** Set 3D cloud number of flavours
* @param density 3D cloud number of flavours
*/
virtual void set_3dCloudNumFlavours(float n);
};