osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthUtil/OceanSurfaceNode.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003 * Copyright 2008-2010 Pelican Mapping
00004 * http://osgearth.org
00005 *
00006 * osgEarth is free software; you can redistribute it and/or modify
00007 * it under the terms of the GNU Lesser General Public License as published by
00008 * the Free Software Foundation; either version 2 of the License, or
00009 * (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU Lesser General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU Lesser General Public License
00017 * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018 */
00019 
00020 #include <osgEarthUtil/OceanSurfaceNode>
00021 
00022 #include <osgEarth/FindNode>
00023 #include <osgEarth/Notify>
00024 #include <osgEarth/Registry>
00025 #include <osgEarth/ShaderComposition>
00026 #include <osgEarth/TextureCompositor>
00027 #include <osgEarth/MapNode>
00028 #include <osgEarth/FindNode>
00029 
00030 #include <osg/Texture3D>
00031 #include <osgDB/ReadFile>
00032 
00033 #include <sstream>
00034 #include <iomanip>
00035 
00036 #define LC "[OceanSurfaceNode] "
00037 
00038 using namespace osgEarth;
00039 using namespace osgEarth::Util;
00040 
00041 typedef std::vector< osg::ref_ptr< osg::Image > > ImageList;
00042 
00043 OceanSurfaceNode::OceanSurfaceNode() :
00044 _shadersDirty(false),
00045 _maxRange(800000),
00046 _oceanMaskLayerUID(-1),
00047 _oceanSurfaceTextureUnit(-1),
00048 _oceanSurfaceTextureApplied(false),
00049 _waveHeight(100),
00050 _period(1024),
00051 _enabled(true),
00052 _invertMask(false),
00053 _adjustToMSL(true),
00054 _oceanColor(osg::Vec4f(0,0,1,0)),
00055 _oceanAnimationPeriod(6.0),
00056 _oceanSurfaceImageSizeRadians(osg::PI/500.0)
00057 {
00058     rebuildShaders();
00059  
00060     getOrCreateStateSet()->getOrCreateUniform("osgearth_OceanPeriod", osg::Uniform::FLOAT)->set(_period);   
00061     getOrCreateStateSet()->getOrCreateUniform("osgearth_OceanAnimationPeriod", osg::Uniform::FLOAT)->set(_oceanAnimationPeriod); 
00062 
00063     osg::Uniform* oceanHeightUniform = getOrCreateStateSet()->getOrCreateUniform("osgearth_OceanHeight", osg::Uniform::FLOAT);
00064     oceanHeightUniform->set( _waveHeight);
00065     oceanHeightUniform->setDataVariance( osg::Object::DYNAMIC);
00066 
00067     //Initialize the ocean surface texture
00068     _oceanSurfaceTexture = new osg::Texture3D();
00069     _oceanSurfaceTexture->setWrap(osg::Texture::WRAP_S,osg::Texture::REPEAT);
00070     _oceanSurfaceTexture->setWrap(osg::Texture::WRAP_T,osg::Texture::REPEAT);
00071     _oceanSurfaceTexture->setWrap(osg::Texture::WRAP_R,osg::Texture::REPEAT);
00072     _oceanSurfaceTexture->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::LINEAR);
00073     _oceanSurfaceTexture->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::LINEAR);
00074 }
00075 
00076 void
00077 OceanSurfaceNode::shadersDirty(bool value)
00078 {
00079     if ( _shadersDirty != value )
00080     {
00081         _shadersDirty = value;
00082         ADJUST_UPDATE_TRAV_COUNT( this, _shadersDirty ? 1 : -1 );
00083     }
00084 }
00085 
00086 void
00087 OceanSurfaceNode::setOceanMaskImageLayer( const ImageLayer* layer )
00088 {
00089     if ( _maskLayer.get() != layer )
00090     {
00091         _maskLayer = layer;
00092         shadersDirty(true);
00093     }
00094 }
00095 
00096 bool
00097 OceanSurfaceNode::getAdjustToMSL() const
00098 {
00099         return _adjustToMSL;
00100 }
00101 
00102 void
00103 OceanSurfaceNode::setAdjustToMSL(bool adjustToMSL)
00104 {
00105         if (_adjustToMSL != adjustToMSL)
00106         {
00107                 _adjustToMSL = adjustToMSL;
00108         shadersDirty( true );
00109         }
00110 }
00111 
00112 osg::Image*
00113 OceanSurfaceNode::getOceanSurfaceImage() const
00114 {
00115     return _oceanSurfaceImage.get();
00116 }
00117 
00118 void
00119 OceanSurfaceNode::setOceanSurfaceImage(osg::Image* image)
00120 {
00121     if (_oceanSurfaceImage.get() != image)
00122     {
00123         _oceanSurfaceImage = image;
00124         _oceanSurfaceTexture->setImage( _oceanSurfaceImage.get() );
00125         
00126         shadersDirty( true );
00127     }
00128 }
00129 
00130 float
00131 OceanSurfaceNode::getWaveHeight() const
00132 {
00133     return _waveHeight;
00134 }
00135 
00136 void
00137 OceanSurfaceNode::setWaveHeight(float waveHeight)
00138 {
00139     if (_waveHeight != waveHeight)
00140     {
00141         _waveHeight = waveHeight;
00142         getOrCreateStateSet()->getOrCreateUniform("osgearth_OceanHeight", osg::Uniform::FLOAT)->set(_waveHeight);
00143         //TODO: consider rebuildShaders() instead..
00144     }
00145 }
00146 
00147 float
00148 OceanSurfaceNode::getMaxRange() const
00149 {
00150     return _maxRange;
00151 }
00152 
00153 void
00154 OceanSurfaceNode::setMaxRange(float maxRange)
00155 {
00156     if (_maxRange != maxRange)
00157     {
00158         _maxRange = maxRange;
00159         shadersDirty(true);
00160     }
00161 }
00162 
00163 float
00164 OceanSurfaceNode::getPeriod() const
00165 {
00166     return _period;
00167 }
00168 
00169 void
00170 OceanSurfaceNode::setPeriod(float period)
00171 {
00172     if (_period !=period)
00173     {
00174         _period = period;
00175         getOrCreateStateSet()->getOrCreateUniform("osgearth_OceanPeriod", osg::Uniform::FLOAT)->set(_period); 
00176         //TODO: consider rebuildShaders() instead..    
00177     }
00178 }
00179 
00180 bool
00181 OceanSurfaceNode::getEnabled() const
00182 {
00183     return _enabled;
00184 }
00185 
00186 void
00187 OceanSurfaceNode::setEnabled(bool enabled)
00188 {
00189     if (_enabled != enabled)
00190     {
00191         _enabled = enabled;
00192         shadersDirty(true);
00193     }
00194 }
00195 
00196 bool
00197 OceanSurfaceNode::getInvertMask() const
00198 {
00199     return _invertMask;
00200 }
00201 
00202 void
00203 OceanSurfaceNode::setInvertMask(bool invertMask)
00204 {
00205     if (_invertMask != invertMask)
00206     {
00207         _invertMask = invertMask;
00208         shadersDirty( true );
00209     }
00210 }
00211 
00212 void
00213 OceanSurfaceNode::setModulationColor( const osg::Vec4f& color )
00214 {
00215     if ( !_oceanColor.isSetTo( color ) )
00216     {
00217         _oceanColor = color;
00218         shadersDirty( true );
00219     }
00220 }
00221 
00222 osg::Vec4f
00223 OceanSurfaceNode::getModulationColor() const
00224 {
00225     return _oceanColor.value();
00226 }
00227 
00228 float
00229 OceanSurfaceNode::getOceanAnimationPeriod() const
00230 {
00231     return _oceanAnimationPeriod;
00232 }
00233 
00234 void
00235 OceanSurfaceNode::setOceanAnimationPeriod(float oceanAnimationPeriod)
00236 {
00237     if (_oceanAnimationPeriod != oceanAnimationPeriod)
00238     {
00239         _oceanAnimationPeriod = oceanAnimationPeriod;
00240         getOrCreateStateSet()->getOrCreateUniform("osgearth_OceanAnimationPeriod", osg::Uniform::FLOAT)->set(oceanAnimationPeriod); 
00241         //TODO: consider rebuildShaders() instead..
00242     }
00243 }
00244 
00245 float
00246 OceanSurfaceNode::getOceanSurfaceImageSizeRadians() const
00247 {
00248     return _oceanSurfaceImageSizeRadians;
00249 }
00250 
00251 void
00252 OceanSurfaceNode::setOceanSurfaceImageSizeRadians(float size)
00253 {
00254     if (_oceanSurfaceImageSizeRadians != size)
00255     {
00256         _oceanSurfaceImageSizeRadians = size;
00257         shadersDirty( true );
00258     }
00259 }
00260 
00261 void
00262 OceanSurfaceNode::traverse( osg::NodeVisitor& nv )
00263 {
00264     if ( _shadersDirty && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR )
00265     {
00266         rebuildShaders();
00267         shadersDirty( false );
00268     }
00269 
00270     osg::Group::traverse( nv );
00271 }
00272 
00273 #define MASK_SAMPLER_FUNC "osgearth_ocean_sampleMask"
00274 
00275 void
00276 OceanSurfaceNode::rebuildShaders()
00277 {
00278     // need the terrain engine so we can get at the compositor.
00279     TerrainEngineNode* engine = osgEarth::findTopMostNodeOfType<TerrainEngineNode>( this );
00280     if ( !engine ) {
00281         OE_DEBUG << LC << "No terrain engine found in the map node; abort" << std::endl;
00282         return;
00283     }
00284 
00285     // access the compositor because we are going to be sampling map layers.
00286     TextureCompositor* comp = engine->getTextureCompositor();
00287     if ( !comp ) {
00288         OE_INFO << LC << "No texture compositor found in the terrain engine; abort" << std::endl;
00289         return;
00290     }
00291 
00292     // reserve a texture unit for the surface texture (if we haven't already)
00293     if ( !_oceanSurfaceTextureApplied && _oceanSurfaceTextureUnit < 0 && _oceanSurfaceTexture.valid() )
00294     {
00295         if ( comp->reserveTextureImageUnit( _oceanSurfaceTextureUnit ) )
00296         {
00297             getOrCreateStateSet()->setTextureAttributeAndModes(
00298                 _oceanSurfaceTextureUnit, _oceanSurfaceTexture.get(), osg::StateAttribute::ON);
00299             _oceanSurfaceTextureApplied = true;
00300         }
00301         else
00302         {
00303             OE_WARN << LC << "Sorry, failed to allocate a texture image unit for the surface texture." << std::endl;
00304         }
00305     }
00306 
00307     // create a VP to store our custom shader components.
00308     osgEarth::VirtualProgram* vp = new osgEarth::VirtualProgram();
00309     getOrCreateStateSet()->setAttributeAndModes( vp, osg::StateAttribute::ON );
00310 
00311     // if the ocean is disabled, just return without injecting any shaders.
00312     if ( !_enabled )
00313         return;
00314 
00315     // build the sampler function if necessary
00316     osg::ref_ptr<const ImageLayer> safeMaskLayer = _maskLayer.get();
00317     osg::Shader* maskSampler = 0L;
00318     if ( safeMaskLayer.valid() )
00319     {
00320         maskSampler = comp->createSamplerFunction( safeMaskLayer->getUID(), MASK_SAMPLER_FUNC, osg::Shader::VERTEX );        
00321         if ( maskSampler )
00322             vp->setShader( MASK_SAMPLER_FUNC, maskSampler );
00323     }
00324 
00325     // make the helper functions.
00326     {
00327         std::stringstream buf;
00328 
00329         buf << "vec3 xyz_to_lat_lon_height(in vec3 xyz) \n"
00330             << "{ \n"
00331             << "    float X = xyz.x;\n"
00332             << "    float Y = xyz.y;\n"
00333             << "    float Z = xyz.z;\n"
00334             << "    float _radiusEquator = 6378137.0;\n"
00335             << "    float _radiusPolar   = 6356752.3142;\n"
00336             << "    float flattening = (_radiusEquator-_radiusPolar)/_radiusEquator;\n"
00337             << "    float _eccentricitySquared = 2.0*flattening - flattening*flattening;\n"
00338             << "    float p = sqrt(X*X + Y*Y);\n"
00339             << "    float theta = atan(Z*_radiusEquator , (p*_radiusPolar));\n"
00340             << "    float eDashSquared = (_radiusEquator*_radiusEquator - _radiusPolar*_radiusPolar)/(_radiusPolar*_radiusPolar);\n"
00341             << "    float sin_theta = sin(theta);\n"
00342             << "    float cos_theta = cos(theta);\n"
00343             << "    float latitude = atan( (Z + eDashSquared*_radiusPolar*sin_theta*sin_theta*sin_theta), (p - _eccentricitySquared*_radiusEquator*cos_theta*cos_theta*cos_theta) );\n"
00344             << "    float longitude = atan(Y,X);\n"
00345             << "    float sin_latitude = sin(latitude);\n"
00346             << "    float N = _radiusEquator / sqrt( 1.0 - _eccentricitySquared*sin_latitude*sin_latitude);\n"
00347             << "    float height = p/cos(latitude) - N;\n"
00348             << "    return vec3(longitude, latitude, height);\n"
00349             << "} \n"
00350             << "\n";
00351 
00352         std::string str = buf.str();
00353         vp->setShader( "xyz_to_lat_lon_height", new osg::Shader(osg::Shader::VERTEX, str) );
00354     }
00355 
00356     // next make the vertex shader function that will morph the ocean verts and prepare
00357     // the texture coordinates for the surface effects.
00358     {
00359         std::stringstream buf;
00360 
00361         buf << std::fixed;
00362 
00363         buf << "uniform float osg_SimulationTime; \n"
00364             << "uniform mat4  osg_ViewMatrixInverse;\n"
00365             << "uniform mat4  osg_ViewMatrix;\n"
00366             << "uniform float osgearth_OceanHeight;\n"
00367             << "uniform float osgearth_OceanPeriod;\n"
00368             << "uniform float osgearth_OceanAnimationPeriod;\n"
00369             << "varying float osgearth_OceanAlpha;\n"
00370             << "varying float osgearth_CameraRange; \n"
00371 
00372             << "vec3 xyz_to_lat_lon_height(in vec3 xyz); \n";
00373 
00374         if ( _oceanSurfaceTextureApplied )
00375         {
00376             buf << "varying vec3 osgearth_oceanSurfaceTexCoord; \n";
00377         }
00378 
00379         if ( maskSampler )
00380         {
00381             buf << "vec4 " << MASK_SAMPLER_FUNC << "(); \n";
00382         }
00383 
00384         buf << "void osgearth_ocean_morphSurface() \n"
00385             << "{ \n"
00386             << "   mat4 modelMatrix = osg_ViewMatrixInverse * gl_ModelViewMatrix; \n"
00387             << "   vec4 vert = modelMatrix  * gl_Vertex; \n"           
00388             << "   vec3 vert3 = vec3(vert.x, vert.y, vert.z); \n"
00389             << "   vec3 latlon = xyz_to_lat_lon_height(vert3); \n"
00390             << "   osgearth_OceanAlpha = 1.0; \n";
00391 
00392         if ( maskSampler )
00393         {
00394             buf << "    osgearth_OceanAlpha = 1.0 - (" << MASK_SAMPLER_FUNC << "()).a; \n";
00395         }
00396 
00397         if ( _invertMask )
00398             buf << "    osgearth_OceanAlpha = 1.0 - osgearth_OceanAlpha; \n";
00399 
00400         buf << "   if ( osgearth_CameraRange <= " << _maxRange << " ) \n"
00401             << "   { \n"
00402             << "       float s = mix(1.0, 0.0, osgearth_CameraRange / " << _maxRange << "); \n" //Invert so it's between 0 and 1
00403             << "       osgearth_OceanAlpha *= s; \n"
00404             << "   } \n"
00405             << "   else \n"
00406             << "   { \n"
00407             << "        osgearth_OceanAlpha = 0.0; \n"
00408             << "   } \n"
00409 
00410             << "   if (osgearth_OceanAlpha > 0.0) \n"
00411             << "   { \n"
00412             << "       float PI_2 = 3.14158 * 2.0; \n"
00413             << "       float period = PI_2/osgearth_OceanPeriod; \n"
00414             << "       float half_period = period / 2.0; \n"
00415             << "       vec3 n = normalize(vert3);\n"
00416             << "       float theta = (mod(latlon.x, period) / period) * PI_2; \n"  
00417             << "       float phi = (mod(latlon.y, half_period) / half_period) * PI_2; \n"
00418             << "       float phase1 = osg_SimulationTime * 2.0; \n"
00419             << "       float phase2 = osg_SimulationTime * 4.0; \n"
00420             << "       float waveHeight = (osgearth_OceanAlpha) * osgearth_OceanHeight; \n"
00421             << "       float scale1 = sin(theta + phase1) * waveHeight; \n"
00422             << "       float scale2 = cos(phi + phase2) * waveHeight; \n"
00423             << "       float scale3 = sin(theta + phase2) * cos(phi + phase1) * waveHeight * 1.6; \n"
00424             << "       float scale = (scale1 + scale2 + scale3)/3.0; \n";
00425 
00426         // flatten verts to MSL:
00427         if ( _adjustToMSL )
00428         {
00429             buf << "        vec3 offset = n * -latlon.z; \n"
00430                 << "        vert += vec4( offset.xyz, 0 ); \n";
00431         }
00432 
00433         // apply the save scale:
00434         buf << "       n = n * scale; \n"
00435             << "       vert += vec4(n.x, n.y,n.z,0); \n"
00436             << "       vert = osg_ViewMatrix * vert; \n"
00437             << "       gl_Position = gl_ProjectionMatrix * vert; \n"
00438             << "   }\n";
00439 
00440         // set up the coords for the surface texture:
00441         if ( _oceanSurfaceTextureApplied )
00442         {
00443             buf << "   osgearth_oceanSurfaceTexCoord.x =  latlon.x / " << _oceanSurfaceImageSizeRadians << "; \n"
00444                 << "   osgearth_oceanSurfaceTexCoord.y =  latlon.y / " << _oceanSurfaceImageSizeRadians << "; \n"
00445                 << "   osgearth_oceanSurfaceTexCoord.z = fract(osg_SimulationTime/osgearth_OceanAnimationPeriod); \n";
00446         }
00447 
00448         buf << "}\n";
00449 
00450         // add as a custom user function in the shader composition:
00451         std::string vertSource = buf.str();
00452         vp->setFunction( "osgearth_ocean_morphSurface", vertSource, osgEarth::ShaderComp::LOCATION_VERTEX_PRE_TEXTURING );
00453     }
00454     
00455     // now we need a fragment function that will apply the ocean surface texture.
00456     if ( _oceanSurfaceTextureApplied )
00457     {
00458         getOrCreateStateSet()->getOrCreateUniform( "osgearth_oceanSurfaceTex", osg::Uniform::SAMPLER_3D )->set( _oceanSurfaceTextureUnit );
00459 
00460         std::stringstream buf;
00461 
00462         buf << "uniform sampler3D osgearth_oceanSurfaceTex; \n"
00463             << "varying vec3      osgearth_oceanSurfaceTexCoord; \n"
00464             << "varying float     osgearth_OceanAlpha; \n"
00465 
00466             << "void osgearth_ocean_applySurfaceTex( inout vec4 color ) \n"
00467             << "{ \n"
00468             << "    vec4 texel = texture3D(osgearth_oceanSurfaceTex, osgearth_oceanSurfaceTexCoord); \n"
00469             << "    color = vec4( mix( color.rgb, texel.rgb, texel.a * osgearth_OceanAlpha ), color.a); \n"
00470             << "} \n";
00471 
00472         std::string str = buf.str();
00473         vp->setFunction( "osgearth_ocean_applySurfaceTex", str, osgEarth::ShaderComp::LOCATION_FRAGMENT_PRE_LIGHTING );
00474     }
00475 }
00476 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines