From 4a5853c1c2c24704847fe360f6709fec9798cf05 Mon Sep 17 00:00:00 2001 From: durk Date: Fri, 2 Oct 2009 05:44:25 +0000 Subject: [PATCH] Stuart Buchanan: Improvements to the cloudsystem: - A new xml format - Texture indexing based on the position of the sprite in the cloud mass, allowing more control over the texture set. - Improved fog and shading - Better sprite distribution - A more natural distribution of clouds, so no more obvious grids. --- simgear/scene/sky/CloudShaderGeometry.cxx | 17 +++--- simgear/scene/sky/newcloud.cxx | 65 ++++++++++++----------- 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/simgear/scene/sky/CloudShaderGeometry.cxx b/simgear/scene/sky/CloudShaderGeometry.cxx index 49244faf..10d50acb 100755 --- a/simgear/scene/sky/CloudShaderGeometry.cxx +++ b/simgear/scene/sky/CloudShaderGeometry.cxx @@ -40,7 +40,7 @@ struct SpriteComp bool operator() (const CloudShaderGeometry::SortData::SortItem& lhs, const CloudShaderGeometry::SortData::SortItem& rhs) const { - return lhs.depth < rhs.depth; + return lhs.depth > rhs.depth; } }; } @@ -108,11 +108,11 @@ void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const itr != end; ++itr) { const CloudSprite& t = _cloudsprites[itr->idx]; - GLfloat ua1[3] = { (GLfloat)t.texture_index_x/varieties_x, - (GLfloat)t.texture_index_y/varieties_y, - t.width }; - GLfloat ua2[3] = { (GLfloat)t.height, - t.shade, + GLfloat ua1[3] = { (GLfloat) t.texture_index_x/varieties_x, + (GLfloat) t.texture_index_y/varieties_y, + (GLfloat) t.width }; + GLfloat ua2[3] = { (GLfloat) t.height, + (GLfloat) t.shade, (GLfloat) t.cloud_height }; extensions->glVertexAttrib3fv(USR_ATTR_1, ua1 ); extensions->glVertexAttrib3fv(USR_ATTR_2, ua2 ); @@ -126,15 +126,18 @@ void CloudShaderGeometry::addSprite(SGVec3f& p, int tx, int ty, float s, float cull, float cloud_height) { // Only add the sprite if it is further than the cull distance to all other sprites + // except for the center sprite. for (CloudShaderGeometry::CloudSpriteList::iterator iter = _cloudsprites.begin(); iter != _cloudsprites.end(); ++iter) { - if (distSqr(iter->position, p) < cull) { + if ((iter != _cloudsprites.begin()) && + (distSqr(iter->position, p) < cull)) { // Too close - cull it return; } } + _cloudsprites.push_back(CloudSprite(p, tx, ty, w, h, s, cloud_height)); } diff --git a/simgear/scene/sky/newcloud.cxx b/simgear/scene/sky/newcloud.cxx index 1c1b0d24..d641b2c9 100644 --- a/simgear/scene/sky/newcloud.cxx +++ b/simgear/scene/sky/newcloud.cxx @@ -91,23 +91,23 @@ static char vertexShaderSource[] = // Do the matrix multiplication by [ u r w pos]. Assume no // scaling in the homogeneous component of pos. " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" - " gl_Position.xyz = gl_Vertex.x * u * wScale;\n" - " gl_Position.xyz += gl_Vertex.y * r * hScale;\n" - " gl_Position.xyz += gl_Vertex.z * w;\n" + " gl_Position.xyz = gl_Vertex.x * u;\n" + " gl_Position.xyz += gl_Vertex.y * r * wScale;\n" + " gl_Position.xyz += gl_Vertex.z * w * hScale;\n" " gl_Position.xyz += gl_Color.xyz;\n" // Determine a lighting normal based on the vertex position from the // center of the cloud, so that sprite on the opposite side of the cloud to the sun are darker. - " float n = dot(normalize(gl_LightSource[0].position.xyz), normalize(mat3x3(gl_ModelViewMatrix) * gl_Position.xyz));\n" + " float n = dot(normalize(- gl_LightSource[0].position.xyz), normalize(mat3x3(gl_ModelViewMatrix) * (- gl_Position.xyz)));\n" // Determine the position - used for fog and shading calculations " vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Position);\n" " float fogCoord = abs(ecPosition.z);\n" " float fract = smoothstep(0.0, cloud_height, gl_Position.z + cloud_height);\n" // Final position of the sprite " gl_Position = gl_ModelViewProjectionMatrix * gl_Position;\n" -// Limit the normal range from [0,1.0], and apply the shading (vertical factor) - " n = min(smoothstep(-0.5, 0.5, n), shade * (1.0 - fract) + fract);\n" -// This lighting normal is then used to mix between almost pure ambient (0) and diffuse (1.0) light - " vec4 backlight = 0.9 * gl_LightSource[0].ambient + 0.1 * gl_LightSource[0].diffuse;\n" +// Determine the shading of the sprite based on its vertical position and position relative to the sun. + " n = min(smoothstep(-0.5, 0.0, n), fract);\n" +// Determine the shading based on a mixture from the backlight to the front + " vec4 backlight = gl_LightSource[0].diffuse * shade;\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. Equally at large distances it also fades out. @@ -127,7 +127,7 @@ static char fragmentShaderSource[] = " vec4 base = texture2D( baseTexture, gl_TexCoord[0].st);\n" " vec4 finalColor = base * gl_Color;\n" " gl_FragColor.rgb = mix(gl_Fog.color.rgb, finalColor.rgb, fogFactor );\n" - " gl_FragColor.a = finalColor.a;\n" + " gl_FragColor.a = mix(0.0, finalColor.a, fogFactor);\n" "}\n"; SGNewCloud::SGNewCloud(string type, @@ -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.05f); + alphaFunc->setFunction(AlphaFunc::GREATER,0.01f); program = new Program; baseTextureSampler = new osg::Uniform("baseTexture", 0); Shader* vertex_shader = new Shader(Shader::VERTEX, vertexShaderSource); @@ -301,27 +301,19 @@ osg::ref_ptr SGNewCloud::genCloud() { // 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; + // The number of sprites we actually use is a function of the (user-controlled) density + int n_sprites = num_sprites * sprite_density * (0.5 + sg_random()); 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. + // the first sprite in the center of the sphere (and at maximum size) to + // ensure good coverage and reduce the chance of there being "holes" in our + 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; @@ -330,26 +322,35 @@ osg::ref_ptr SGNewCloud::genCloud() { 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; + 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) + // 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) { + + // Sprites are never taller than square. + if (sprite_height * min_sprite_height > sprite_width * min_sprite_width) + { + sprite_height = sprite_width * min_sprite_width / min_sprite_height; + } + + if (i == 0) { // 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; + + // 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); + + // The y index depends on the positing of the sprite within the cloud. + // This allows cloud designers to have particular sprites for the base + // and tops of the cloud. + int index_y = (int) floor((z / height + 0.5f) * num_textures_y); if (index_y == num_textures_y) { index_y--; } sg->addSprite(*pos, -- 2.39.5