From ddd72b2b372b93a6e02386bd593b515e86208e79 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Thu, 26 Nov 2009 11:40:41 +0100 Subject: [PATCH] Use an effect for 3d clouds --- simgear/scene/sky/cloudfield.cxx | 1 - simgear/scene/sky/cloudfield.hxx | 3 - simgear/scene/sky/newcloud.cxx | 161 +++++-------------------------- simgear/scene/sky/newcloud.hxx | 7 +- 4 files changed, 30 insertions(+), 142 deletions(-) diff --git a/simgear/scene/sky/cloudfield.cxx b/simgear/scene/sky/cloudfield.cxx index 770f4da0..013efe16 100644 --- a/simgear/scene/sky/cloudfield.cxx +++ b/simgear/scene/sky/cloudfield.cxx @@ -71,7 +71,6 @@ float SGCloudField::fieldSize = 50000.0f; double SGCloudField::timer_dt = 0.0; float SGCloudField::view_distance = 20000.0f; sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y; -SGCloudField::StateSetMap SGCloudField::cloudTextureMap; // reposition the cloud layer at the specified origin and orientation bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, double lat, diff --git a/simgear/scene/sky/cloudfield.hxx b/simgear/scene/sky/cloudfield.hxx index beab904d..1b2f97f1 100644 --- a/simgear/scene/sky/cloudfield.hxx +++ b/simgear/scene/sky/cloudfield.hxx @@ -137,9 +137,6 @@ public: void applyCoverage(void); void applyVisRange(void); - typedef std::map > StateSetMap; - static StateSetMap cloudTextureMap; - static osg::Fog* getFog() { return CloudFog::instance()->fog.get(); diff --git a/simgear/scene/sky/newcloud.cxx b/simgear/scene/sky/newcloud.cxx index 1c1b0d24..d4219210 100644 --- a/simgear/scene/sky/newcloud.cxx +++ b/simgear/scene/sky/newcloud.cxx @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -60,75 +61,14 @@ using namespace simgear; using namespace osg; -typedef std::map > StateSetMap; +namespace +{ +typedef std::map > EffectMap; +EffectMap effectMap; +} -StateSetMap cloudTextureMap; double SGNewCloud::sprite_density = 1.0; -static char vertexShaderSource[] = - "#version 120\n" - "\n" - "varying float fogFactor;\n" - "attribute vec3 usrAttr1;\n" - "attribute vec3 usrAttr2;\n" - "float textureIndexX = usrAttr1.r;\n" - "float textureIndexY = usrAttr1.g;\n" - "float wScale = usrAttr1.b;\n" - "float hScale = usrAttr2.r;\n" - "float shade = usrAttr2.g;\n" - "float cloud_height = usrAttr2.b;\n" - "void main(void)\n" - "{\n" - " gl_TexCoord[0] = gl_MultiTexCoord0 + vec4(textureIndexX, textureIndexY, 0.0, 0.0);\n" - " vec4 ep = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0);\n" - " vec4 l = gl_ModelViewMatrixInverse * vec4(0.0,0.0,1.0,1.0);\n" - " vec3 u = normalize(ep.xyz - l.xyz);\n" -// Find a rotation matrix that rotates 1,0,0 into u. u, r and w are -// the columns of that matrix. - " vec3 absu = abs(u);\n" - " vec3 r = normalize(vec3(-u.y, u.x, 0));\n" - " vec3 w = cross(u, r);\n" -// 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_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" -// 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" - " 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. - " 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" - " fogFactor = clamp(fogFactor, 0.0, 1.0);\n" - "}\n"; - -static char fragmentShaderSource[] = - "uniform sampler2D baseTexture; \n" - "varying float fogFactor;\n" - "\n" - "void main(void)\n" - "{\n" - " 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" - "}\n"; SGNewCloud::SGNewCloud(string type, const SGPath &tex_path, @@ -160,75 +100,24 @@ SGNewCloud::SGNewCloud(string type, texture(tex), name(type) { - // Create a new StateSet for the texture, if required. - StateSetMap::iterator iter = SGCloudField::cloudTextureMap.find(texture); - - if (iter == SGCloudField::cloudTextureMap.end()) { - stateSet = new osg::StateSet; - - osg::ref_ptr options = makeOptionsFromPath(tex_path); - - osg::Texture2D *tex = new osg::Texture2D; - tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP ); - tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP ); - tex->setImage(osgDB::readImageFile(texture, options.get())); - - StateAttributeFactory* attribFactory = StateAttributeFactory::instance(); - - stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON); - stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - - // Fog handling - stateSet->setAttributeAndModes(attribFactory->getSmoothShadeModel()); - stateSet->setAttributeAndModes(attribFactory->getStandardBlendFunc()); - - 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; - static ref_ptr material; - - // Generate the shader etc, if we don't already have one. - if (!program.valid()) { - alphaFunc = new AlphaFunc; - alphaFunc->setFunction(AlphaFunc::GREATER,0.05f); - program = new Program; - baseTextureSampler = new osg::Uniform("baseTexture", 0); - Shader* vertex_shader = new Shader(Shader::VERTEX, vertexShaderSource); - program->addShader(vertex_shader); - program->addBindAttribLocation("usrAttr1", CloudShaderGeometry::USR_ATTR_1); - program->addBindAttribLocation("usrAttr2", CloudShaderGeometry::USR_ATTR_2); - Shader* fragment_shader = new Shader(Shader::FRAGMENT, fragmentShaderSource); - program->addShader(fragment_shader); - material = new Material; - // Don´t track vertex color - material->setColorMode(Material::OFF); - - // We don't actually use the material information either - see shader. - material->setAmbient(Material::FRONT_AND_BACK, - Vec4(0.5f, 0.5f, 0.5f, 1.0f)); - material->setDiffuse(Material::FRONT_AND_BACK, - Vec4(0.5f, 0.5f, 0.5f, 1.0f)); - } - - stateSet->setAttributeAndModes(alphaFunc.get()); - stateSet->setAttribute(program.get()); - stateSet->addUniform(baseTextureSampler.get()); - stateSet->setMode(GL_VERTEX_PROGRAM_TWO_SIDE, StateAttribute::ON); - stateSet->setAttribute(material.get()); - - // Add the newly created texture to the map for use later. - SGCloudField::cloudTextureMap.insert(StateSetMap::value_type(texture, stateSet)); + // Create a new Effect for the texture, if required. + EffectMap::iterator iter = effectMap.find(texture); + if (iter == effectMap.end()) { + SGPropertyNode_ptr pcloudEffect = new SGPropertyNode; + makeChild(pcloudEffect, "inherits-from")->setValue("Effects/cloud"); + setValue(makeChild(makeChild(makeChild(pcloudEffect, "parameters"), + "texture"), + "image"), + texture); + osg::ref_ptr options + = makeOptionsFromPath(tex_path); + if ((effect = makeEffect(pcloudEffect, true, options))) + effectMap.insert(EffectMap::value_type(texture, effect)); } else { - stateSet = iter->second.get(); + effect = iter->second.get(); } - - quad = createOrthQuad(min_sprite_width, min_sprite_height, num_textures_x, num_textures_y); + quad = createOrthQuad(min_sprite_width, min_sprite_height, + num_textures_x, num_textures_y); } SGNewCloud::~SGNewCloud() { @@ -285,9 +174,9 @@ static float Rnd(float n) { } #endif -osg::ref_ptr SGNewCloud::genCloud() { +osg::ref_ptr SGNewCloud::genCloud() { - osg::ref_ptr geode = new Geode; + osg::ref_ptr geode = new EffectGeode; CloudShaderGeometry* sg = new CloudShaderGeometry(num_textures_x, num_textures_y, max_width, max_height); @@ -365,7 +254,7 @@ osg::ref_ptr SGNewCloud::genCloud() { sg->setGeometry(quad); geode->addDrawable(sg); geode->setName("3D cloud"); - geode->setStateSet(stateSet.get()); + geode->setEffect(effect.get()); return geode; } diff --git a/simgear/scene/sky/newcloud.hxx b/simgear/scene/sky/newcloud.hxx index be5549ff..28f8a9c3 100644 --- a/simgear/scene/sky/newcloud.hxx +++ b/simgear/scene/sky/newcloud.hxx @@ -31,6 +31,9 @@ #include "bbcache.hxx" +#include +#include + using std::string; using std::vector; @@ -59,7 +62,7 @@ public: ~SGNewCloud(); // Generate a Cloud - osg::ref_ptr genCloud (); + osg::ref_ptr genCloud (); static double getDensity(void) { @@ -90,7 +93,7 @@ private: const string texture; const string name; osg::Geometry* quad; - osg::ref_ptr stateSet; + osg::ref_ptr effect; static double sprite_density; osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y); -- 2.39.5