X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Fsky%2Fnewcloud.cxx;h=efdf0c559d5768d152851092167841d6dda1c345;hb=342de209a21c49121bb2906d7ae58ee1d5f52866;hp=61dcb8b6fc73653fa279007ef729dba6c940c38c;hpb=966b9e5c2bbcb27a3ad90d6f4d059d3a4fa1fd27;p=simgear.git diff --git a/simgear/scene/sky/newcloud.cxx b/simgear/scene/sky/newcloud.cxx index 61dcb8b6..efdf0c55 100644 --- a/simgear/scene/sky/newcloud.cxx +++ b/simgear/scene/sky/newcloud.cxx @@ -25,6 +25,7 @@ #endif #include +#include #include #include #include @@ -60,13 +61,9 @@ using namespace simgear; using namespace osg; typedef std::map > StateSetMap; -typedef std::vector< osg::ref_ptr > GeodeList; -typedef std::map 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 +110,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" @@ -187,7 +184,10 @@ SGNewCloud::SGNewCloud(string type, stateSet->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON ); stateSet->setRenderBinDetails(osg::StateSet::TRANSPARENT_BIN, "DepthSortedBin"); - + // Turn off z buffer writes. Standard hack for + // semi-transparent geometry to avoid sorting / flickering + // artifacts. + stateSet->setAttributeAndModes(attribFactory->getDepthWritesDisabled()); static ref_ptr alphaFunc; static ref_ptr program; static ref_ptr baseTextureSampler; @@ -196,7 +196,7 @@ SGNewCloud::SGNewCloud(string type, // Generate the shader etc, if we don't already have one. if (!program.valid()) { alphaFunc = new AlphaFunc; - alphaFunc->setFunction(AlphaFunc::GREATER,0.001f); + alphaFunc->setFunction(AlphaFunc::GREATER,0.05f); program = new Program; baseTextureSampler = new osg::Uniform("baseTexture", 0); Shader* vertex_shader = new Shader(Shader::VERTEX, vertexShaderSource); @@ -285,119 +285,86 @@ static float Rnd(float n) { osg::ref_ptr SGNewCloud::genCloud() { - CloudMap::iterator iter = cloudMap.find(name); - osg::ref_ptr geode; + osg::ref_ptr 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; - // 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 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; - if (iter == cloudMap.end() || (*iter).second->size() < num_flavours) + // 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; }