osgEarth 2.1.1
|
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 #include <osgEarth/ShaderComposition> 00020 00021 #include <osgEarth/Registry> 00022 #include <osg/Shader> 00023 #include <osg/Program> 00024 #include <osg/State> 00025 #include <osg/Notify> 00026 #include <sstream> 00027 00028 #define LC "[VirtualProgram] " 00029 00030 using namespace osgEarth; 00031 using namespace osgEarth::ShaderComp; 00032 00033 //------------------------------------------------------------------------ 00034 00035 namespace 00036 { 00038 class StateHack : public osg::State 00039 { 00040 public: 00041 typedef std::pair<const osg::StateAttribute*,osg::StateAttribute::OverrideValue> AttributePair; 00042 typedef std::vector<AttributePair> AttributeVec; 00043 00044 const AttributeVec* getAttributeVec( const osg::StateAttribute* attribute ) const 00045 { 00046 osg::State::AttributeMap::const_iterator i = _attributeMap.find( attribute->getTypeMemberPair() ); 00047 return i != _attributeMap.end() ? &(i->second.attributeVec) : 0L; 00048 } 00049 00050 static const AttributeVec* GetAttributeVec( const osg::State& state, const osg::StateAttribute* attribute ) 00051 { 00052 const StateHack* sh = reinterpret_cast< const StateHack* >( &state ); 00053 return sh->getAttributeVec( attribute ); 00054 } 00055 }; 00056 } 00057 00058 //------------------------------------------------------------------------ 00059 00060 // If graphics board has program linking problems set MERGE_SHADERS to 1 00061 // Merge shaders can be used to merge shaders strings into one shader. 00062 #define MERGE_SHADERS 0 00063 #define NOTIFICATION_MESSAGES 0 00064 00065 VirtualProgram::VirtualProgram( unsigned int mask ) : 00066 _mask( mask ) 00067 { 00068 // because we sometimes update/change the attribute's members from within the apply() method 00069 this->setDataVariance( osg::Object::DYNAMIC ); 00070 } 00071 00072 VirtualProgram::VirtualProgram(const VirtualProgram& rhs, const osg::CopyOp& copyop ) : 00073 osg::Program( rhs, copyop ), 00074 _shaderMap( rhs._shaderMap ), 00075 _mask( rhs._mask ), 00076 _functions( rhs._functions ) 00077 { 00078 //nop 00079 } 00080 00081 osg::Shader* 00082 VirtualProgram::getShader( const std::string& shaderSemantic, osg::Shader::Type type ) 00083 { 00084 ShaderMap::key_type key( shaderSemantic, type ); 00085 return _shaderMap[ key ].get(); 00086 } 00087 00088 osg::Shader* 00089 VirtualProgram::setShader( const std::string& shaderSemantic, osg::Shader * shader ) 00090 { 00091 if( shader->getType() == osg::Shader::UNDEFINED ) 00092 return NULL; 00093 00094 ShaderMap::key_type key( shaderSemantic, shader->getType() ); 00095 00096 osg::ref_ptr< osg::Shader > shaderNew = shader; 00097 osg::ref_ptr< osg::Shader >& shaderCurrent = _shaderMap[ key ]; 00098 00099 shaderNew->setName( shaderSemantic ); 00100 00101 if( shaderCurrent != shaderNew ) 00102 { 00103 shaderCurrent = shaderNew; 00104 } 00105 00106 //OE_NOTICE << shader->getShaderSource() << std::endl; 00107 00108 return shaderCurrent.get(); 00109 } 00110 00111 void 00112 VirtualProgram::setFunction(const std::string& functionName, 00113 const std::string& shaderSource, 00114 FunctionLocation location, 00115 float priority) 00116 { 00117 Threading::ScopedMutexLock lock( _functionsMutex ); 00118 00119 OrderedFunctionMap& ofm = _functions[location]; 00120 ofm.insert( std::pair<float,std::string>( priority, functionName ) ); 00121 osg::Shader::Type type = (int)location <= (int)LOCATION_VERTEX_POST_LIGHTING ? 00122 osg::Shader::VERTEX : osg::Shader::FRAGMENT; 00123 setShader( functionName, new osg::Shader( type, shaderSource ) ); 00124 } 00125 00126 void 00127 VirtualProgram::removeShader( const std::string& shaderSemantic, osg::Shader::Type type ) 00128 { 00129 _shaderMap.erase( ShaderMap::key_type( shaderSemantic, type ) ); 00130 } 00131 00132 static unsigned s_applies = 0; 00133 static int s_framenum = 0; 00134 00135 void 00136 VirtualProgram::apply( osg::State & state ) const 00137 { 00138 if( _shaderMap.empty() ) // Virtual Program works as normal Program 00139 return Program::apply( state ); 00140 00141 // first, find and collect all the VirtualProgram attributes: 00142 ShaderMap shaderMap; 00143 const StateHack::AttributeVec* av = StateHack::GetAttributeVec( state, this ); 00144 if ( av ) 00145 { 00146 for( StateHack::AttributeVec::const_iterator i = av->begin(); i != av->end(); ++i ) 00147 { 00148 const osg::StateAttribute* sa = i->first; 00149 const VirtualProgram* vp = dynamic_cast< const VirtualProgram* >( sa ); 00150 if( vp && ( vp->_mask & _mask ) ) 00151 { 00152 for( ShaderMap::const_iterator i = vp->_shaderMap.begin(); i != vp->_shaderMap.end(); ++i ) 00153 { 00154 shaderMap[ i->first ] = i->second; 00155 } 00156 } 00157 } 00158 } 00159 00160 // next add the local shader components to the map: 00161 for( ShaderMap::const_iterator i = _shaderMap.begin(); i != _shaderMap.end(); ++i ) 00162 shaderMap[ i->first ] = i->second; 00163 00164 if( shaderMap.size() ) 00165 { 00166 // next, assemble a list of the shaders in the map so we can compare it: 00167 ShaderList sl; 00168 for( ShaderMap::iterator i = shaderMap.begin(); i != shaderMap.end(); ++i ) 00169 sl.push_back( i->second ); 00170 00171 // see if there's already a program associated with this list: 00172 osg::Program* program = 0L; 00173 ProgramMap::iterator p = _programMap.find( sl ); 00174 if ( p != _programMap.end() ) 00175 { 00176 program = p->second.get(); 00177 } 00178 else 00179 { 00180 ShaderFactory* sf = osgEarth::Registry::instance()->getShaderFactory(); 00181 00182 // build a new set of accumulated functions, to support the creation of main() 00183 const_cast<VirtualProgram*>(this)->refreshAccumulatedFunctions( state ); 00184 00185 osg::Shader* vert_main = sf->createVertexShaderMain( _accumulatedFunctions ); 00186 const_cast<VirtualProgram*>(this)->setShader( "osgearth_vert_main", vert_main ); 00187 shaderMap[ ShaderSemantic("osgearth_vert_main", osg::Shader::VERTEX) ] = vert_main; 00188 00189 osg::Shader* frag_main = sf->createFragmentShaderMain( _accumulatedFunctions ); 00190 const_cast<VirtualProgram*>(this)->setShader( "osgearth_frag_main", frag_main ); 00191 shaderMap[ ShaderSemantic("osgearth_frag_main", osg::Shader::FRAGMENT) ] = frag_main; 00192 00193 // rebuild the shader list now that we've changed the shader map. 00194 sl.clear(); 00195 for( ShaderMap::iterator i = shaderMap.begin(); i != shaderMap.end(); ++i ) 00196 sl.push_back( i->second ); 00197 00198 // Create a new program and add all our shaders. 00199 program = new osg::Program(); 00200 00201 #if !MERGE_SHADERS 00202 for( ShaderList::iterator i = sl.begin(); i != sl.end(); ++i ) 00203 { 00204 program->addShader( i->get() ); 00205 } 00206 #else 00207 std::string strFragment; 00208 std::string strVertex; 00209 std::string strGeometry; 00210 00211 for( ShaderList::iterator i = sl.begin(); i != sl.end(); ++i ) 00212 { 00213 if( i->get()->getType() == osg::Shader::FRAGMENT ) 00214 strFragment += i->get()->getShaderSource(); 00215 else if ( i->get()->getType() == osg::Shader::VERTEX ) 00216 strVertex += i->get()->getShaderSource(); 00217 else if ( i->get()->getType() == osg::Shader::GEOMETRY ) 00218 strGeometry += i->get()->getShaderSource(); 00219 } 00220 00221 if( strFragment.length() > 0 ) 00222 { 00223 program->addShader( new osg::Shader( osg::Shader::FRAGMENT, strFragment ) ); 00224 } 00225 00226 if( strVertex.length() > 0 ) 00227 { 00228 program->addShader( new osg::Shader( osg::Shader::VERTEX, strVertex ) ); 00229 } 00230 00231 if( strGeometry.length() > 0 ) 00232 { 00233 program->addShader( new osg::Shader( osg::Shader::GEOMETRY, strGeometry ) ); 00234 } 00235 #endif 00236 // finally, cache the program so we only regenerate it when it changes. 00237 _programMap[ sl ] = program; 00238 } 00239 00240 // finally, apply the program attribute. 00241 program->apply( state ); 00242 } 00243 else 00244 { 00245 Program::apply( state ); 00246 } 00247 } 00248 00249 void 00250 VirtualProgram::getFunctions( FunctionLocationMap& out ) const 00251 { 00252 Threading::ScopedMutexLock lock( const_cast<VirtualProgram*>(this)->_functionsMutex ); 00253 out = _functions; 00254 } 00255 00256 void 00257 VirtualProgram::refreshAccumulatedFunctions( const osg::State& state ) 00258 { 00259 // This method searches the state's attribute stack and accumulates all 00260 // the user functions (including those in this program). 00261 00262 Threading::ScopedMutexLock lock( _functionsMutex ); 00263 00264 _accumulatedFunctions.clear(); 00265 00266 const StateHack::AttributeVec* av = StateHack::GetAttributeVec( state, this ); 00267 for( StateHack::AttributeVec::const_iterator i = av->begin(); i != av->end(); ++i ) 00268 { 00269 const osg::StateAttribute* sa = i->first; 00270 const VirtualProgram* vp = dynamic_cast< const VirtualProgram* >( sa ); 00271 if( vp && vp != this && ( vp->_mask & _mask ) ) 00272 { 00273 FunctionLocationMap rhs; 00274 vp->getFunctions( rhs ); 00275 00276 for( FunctionLocationMap::const_iterator j = rhs.begin(); j != rhs.end(); ++j ) 00277 { 00278 const OrderedFunctionMap& ofm = j->second; 00279 for( OrderedFunctionMap::const_iterator k = ofm.begin(); k != ofm.end(); ++k ) 00280 { 00281 _accumulatedFunctions[j->first].insert( *k ); 00282 } 00283 } 00284 } 00285 } 00286 00287 // add the local ones too: 00288 for( FunctionLocationMap::const_iterator j = _functions.begin(); j != _functions.end(); ++j ) 00289 { 00290 const OrderedFunctionMap& ofm = j->second; 00291 for( OrderedFunctionMap::const_iterator k = ofm.begin(); k != ofm.end(); ++k ) 00292 { 00293 _accumulatedFunctions[j->first].insert( *k ); 00294 } 00295 } 00296 } 00297 00298 //---------------------------------------------------------------------------- 00299 00300 osg::Shader* 00301 ShaderFactory::createVertexShaderMain( const FunctionLocationMap& functions ) const 00302 { 00303 FunctionLocationMap::const_iterator i = functions.find( LOCATION_VERTEX_PRE_TEXTURING ); 00304 const OrderedFunctionMap* preTexture = i != functions.end() ? &i->second : 0L; 00305 00306 FunctionLocationMap::const_iterator j = functions.find( LOCATION_VERTEX_PRE_LIGHTING ); 00307 const OrderedFunctionMap* preLighting = j != functions.end() ? &j->second : 0L; 00308 00309 FunctionLocationMap::const_iterator k = functions.find( LOCATION_VERTEX_POST_LIGHTING ); 00310 const OrderedFunctionMap* postLighting = k != functions.end() ? &k->second : 0L; 00311 00312 std::stringstream buf; 00313 buf << "void osgearth_vert_setupTexturing(); \n" 00314 << "void osgearth_vert_setupLighting(); \n" 00315 << "uniform bool osgearth_LightingEnabled; \n" 00316 << "uniform float osgearth_CameraElevation; \n" 00317 << "varying float osgearth_CameraRange; \n"; 00318 00319 if ( preTexture ) 00320 for( OrderedFunctionMap::const_iterator i = preTexture->begin(); i != preTexture->end(); ++i ) 00321 buf << "void " << i->second << "(); \n"; 00322 00323 if ( preLighting ) 00324 for( OrderedFunctionMap::const_iterator i = preLighting->begin(); i != preLighting->end(); ++i ) 00325 buf << "void " << i->second << "(); \n"; 00326 00327 if ( postLighting ) 00328 for( OrderedFunctionMap::const_iterator i = postLighting->begin(); i != postLighting->end(); ++i ) 00329 buf << "void " << i->second << "(); \n"; 00330 00331 buf << "void main(void) \n" 00332 << "{ \n" 00333 << " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n" 00334 00335 << " vec4 position4 = gl_ModelViewMatrix * gl_Vertex; \n" 00336 << " osgearth_CameraRange = length( position4.xyz ); \n" 00337 00338 // << " vec3 cameraPos = normalize(vec3( osg_ViewMatrixInverse[3][0], osg_ViewMatrixInverse[3][1], osg_ViewMatrixInverse[3][2] )); 00339 00340 << " vec3 position = position4.xyz / position4.w; \n" 00341 << " vec3 normal = normalize( gl_NormalMatrix * gl_Normal ); \n"; 00342 00343 if ( preTexture ) 00344 for( OrderedFunctionMap::const_iterator i = preTexture->begin(); i != preTexture->end(); ++i ) 00345 buf << " " << i->second << "(); \n"; 00346 00347 buf << " osgearth_vert_setupTexturing(); \n"; 00348 00349 if ( preLighting ) 00350 for( OrderedFunctionMap::const_iterator i = preLighting->begin(); i != preLighting->end(); ++i ) 00351 buf << " " << i->second << "(); \n"; 00352 00353 buf << " if ( osgearth_LightingEnabled ) \n" 00354 << " osgearth_vert_setupLighting(); \n"; 00355 00356 if ( postLighting ) 00357 for( OrderedFunctionMap::const_iterator i = postLighting->begin(); i != postLighting->end(); ++i ) 00358 buf << " " << i->second << "(); \n"; 00359 00360 buf << "} \n"; 00361 00362 std::string str = buf.str(); 00363 //OE_INFO << str << std::endl; 00364 return new osg::Shader( osg::Shader::VERTEX, str ); 00365 } 00366 00367 00368 osg::Shader* 00369 ShaderFactory::createFragmentShaderMain( const FunctionLocationMap& functions ) const 00370 { 00371 FunctionLocationMap::const_iterator i = functions.find( LOCATION_FRAGMENT_PRE_TEXTURING ); 00372 const OrderedFunctionMap* preTexture = i != functions.end() ? &i->second : 0L; 00373 00374 FunctionLocationMap::const_iterator j = functions.find( LOCATION_FRAGMENT_PRE_LIGHTING ); 00375 const OrderedFunctionMap* preLighting = j != functions.end() ? &j->second : 0L; 00376 00377 FunctionLocationMap::const_iterator k = functions.find( LOCATION_FRAGMENT_POST_LIGHTING ); 00378 const OrderedFunctionMap* postLighting = k != functions.end() ? &k->second : 0L; 00379 00380 std::stringstream buf; 00381 buf << "void osgearth_frag_applyTexturing( inout vec4 color ); \n" 00382 << "void osgearth_frag_applyLighting( inout vec4 color ); \n"; 00383 00384 if ( preTexture ) 00385 for( OrderedFunctionMap::const_iterator i = preTexture->begin(); i != preTexture->end(); ++i ) 00386 buf << "void " << i->second << "( inout vec4 color ); \n"; 00387 00388 if ( preLighting ) 00389 for( OrderedFunctionMap::const_iterator i = preLighting->begin(); i != preLighting->end(); ++i ) 00390 buf << "void " << i->second << "( inout vec4 color ); \n"; 00391 00392 if ( postLighting ) 00393 for( OrderedFunctionMap::const_iterator i = postLighting->begin(); i != postLighting->end(); ++i ) 00394 buf << "void " << i->second << "( inout vec4 color ); \n"; 00395 00396 buf << "uniform bool osgearth_LightingEnabled; \n" 00397 << "void main(void) \n" 00398 << "{ \n" 00399 << " vec4 color = vec4(1,1,1,1); \n"; 00400 00401 if ( preTexture ) 00402 for( OrderedFunctionMap::const_iterator i = preTexture->begin(); i != preTexture->end(); ++i ) 00403 buf << " " << i->second << "( color ); \n"; 00404 00405 buf << " osgearth_frag_applyTexturing( color ); \n"; 00406 00407 if ( preLighting ) 00408 for( OrderedFunctionMap::const_iterator i = preLighting->begin(); i != preLighting->end(); ++i ) 00409 buf << " " << i->second << "( color ); \n"; 00410 00411 buf << " if (osgearth_LightingEnabled) \n" 00412 << " osgearth_frag_applyLighting( color ); \n"; 00413 00414 if ( postLighting ) 00415 for( OrderedFunctionMap::const_iterator i = postLighting->begin(); i != postLighting->end(); ++i ) 00416 buf << " " << i->second << "( color ); \n"; 00417 00418 buf << " gl_FragColor = color; \n" 00419 << "} \n"; 00420 00421 std::string str = buf.str(); 00422 //OE_INFO << str; 00423 return new osg::Shader( osg::Shader::FRAGMENT, str ); 00424 } 00425 00426 00427 osg::Shader* 00428 ShaderFactory::createDefaultTextureVertexShader( int numTexCoordSets ) const 00429 { 00430 std::stringstream buf; 00431 00432 buf << "void osgearth_vert_setupTexturing() \n" 00433 << "{ \n"; 00434 00435 //TODO: gl_TexCoord et.al. are depcrecated so we should replace them ... 00436 for(int i=0; i<numTexCoordSets; ++i ) 00437 { 00438 buf << " gl_TexCoord["<< i <<"] = gl_MultiTexCoord"<< i << "; \n"; 00439 } 00440 00441 buf << "} \n"; 00442 00443 std::string str = buf.str(); 00444 return new osg::Shader( osg::Shader::VERTEX, str ); 00445 } 00446 00447 00448 osg::Shader* 00449 ShaderFactory::createDefaultTextureFragmentShader( int numTexImageUnits ) const 00450 { 00451 std::stringstream buf; 00452 00453 buf << "#version 120 \n"; 00454 00455 if ( numTexImageUnits > 0 ) 00456 { 00457 buf << "uniform sampler2D "; 00458 for( int i=0; i<numTexImageUnits; ++i ) 00459 buf << "tex" << i << (i+1 < numTexImageUnits? "," : "; \n"); 00460 } 00461 00462 buf << "void osgearth_frag_applyTexturing( inout vec4 color ) \n" 00463 << "{ \n" 00464 << " vec3 color3 = color.rgb; \n" 00465 << " vec4 texel; \n"; 00466 00467 for(int i=0; i<numTexImageUnits; ++i ) 00468 { 00469 buf << " texel = texture2D(tex" << i << ", gl_TexCoord["<< i <<"].st); \n" 00470 << " color3 = mix( color3, texel.rgb, texel.a ); \n"; 00471 } 00472 00473 buf << " color = vec4(color3,color.a); \n" 00474 << "} \n"; 00475 00476 std::string str = buf.str(); 00477 return new osg::Shader( osg::Shader::FRAGMENT, str ); 00478 } 00479 00480 00481 osg::Shader* 00482 ShaderFactory::createDefaultLightingVertexShader() const 00483 { 00484 static char s_PerVertexLighting_VertexShaderSource[] = 00485 "void osgearth_vert_setupLighting() \n" 00486 "{ \n" 00487 " vec3 normal = normalize( gl_NormalMatrix * gl_Normal ); \n" 00488 " float NdotL = dot( normal, normalize(gl_LightSource[0].position.xyz) );\n" 00489 " NdotL = max( 0.0, NdotL ); \n" 00490 " float NdotHV = dot( normal, gl_LightSource[0].halfVector.xyz ); \n" 00491 " NdotHV = max( 0.0, NdotHV ); \n" 00492 " \n" 00493 " gl_FrontColor = gl_FrontLightModelProduct.sceneColor + \n" 00494 " gl_FrontLightProduct[0].ambient + \n" 00495 " gl_FrontLightProduct[0].diffuse * NdotL; \n" 00496 " \n" 00497 " gl_FrontSecondaryColor = vec4(0.0); \n" 00498 " \n" 00499 " if ( NdotL * NdotHV > 0.0 ) \n" 00500 " gl_FrontSecondaryColor = gl_FrontLightProduct[0].specular * \n" 00501 " pow( NdotHV, gl_FrontMaterial.shininess );\n" 00502 " \n" 00503 " gl_BackColor = gl_FrontColor; \n" 00504 " gl_BackSecondaryColor = gl_FrontSecondaryColor; \n" 00505 "} \n"; 00506 00507 return new osg::Shader( osg::Shader::VERTEX, s_PerVertexLighting_VertexShaderSource ); 00508 } 00509 00510 00511 osg::Shader* 00512 ShaderFactory::createDefaultLightingFragmentShader() const 00513 { 00514 static char s_PerVertexLighting_FragmentShaderSource[] = 00515 "void osgearth_frag_applyLighting( inout vec4 color ) \n" 00516 "{ \n" 00517 " float alpha = color.a; \n" 00518 " color = color * gl_Color + gl_SecondaryColor; \n" 00519 " color.a = alpha; \n" 00520 "} \n"; 00521 00522 return new osg::Shader( osg::Shader::FRAGMENT, s_PerVertexLighting_FragmentShaderSource ); 00523 } 00524 00525 //-------------------------------------------------------------------------- 00526 00527 #if 0 00528 // This is just a holding pen for various stuff 00529 00530 static char s_PerFragmentLighting_VertexShaderSource[] = 00531 "varying vec3 Normal; \n" 00532 "varying vec3 Position; \n" 00533 "void osgearth_vert_setupLighting() \n" 00534 "{ \n" 00535 " Normal = normal; \n" 00536 " Position = position; \n" 00537 "} \n"; 00538 00539 static char s_PerFragmentDirectionalLighting_FragmentShaderSource[] = 00540 "varying vec3 Normal; \n" 00541 "varying vec3 Position; \n" 00542 "void osgearth_frag_applyLighting( inout vec4 color ) \n" 00543 "{ \n" 00544 " vec3 n = normalize( Normal ); \n" 00545 " float NdotL = dot( n, normalize(gl_LightSource[0].position.xyz) ); \n" 00546 " NdotL = max( 0.0, NdotL ); \n" 00547 " float NdotHV = dot( n, gl_LightSource[0].halfVector.xyz ); \n" 00548 " NdotHV = max( 0.0, NdotHV ); \n" 00549 " color *= gl_FrontLightModelProduct.sceneColor + \n" 00550 " gl_FrontLightProduct[0].ambient + \n" 00551 " gl_FrontLightProduct[0].diffuse * NdotL; \n" 00552 " if ( NdotL * NdotHV > 0.0 ) \n" 00553 " color += gl_FrontLightProduct[0].specular * \n" 00554 " pow( NdotHV, gl_FrontMaterial.shininess ); \n" 00555 "} \n"; 00556 00557 #endif 00558 00559 //------------------------------------------------------------------------