FadeLOD::FadeLOD() : _minPixelExtent( 0.0f ), _maxPixelExtent( FLT_MAX ), _minFadeExtent ( 0.0f ), _maxFadeExtent ( 0.0f ) { if ( Registry::capabilities().supportsGLSL() ) { VirtualProgram* vp = new VirtualProgram(); vp->setFunction( "oe_fragFadeLOD", FadeLODFragmentShader, ShaderComp::LOCATION_FRAGMENT_COLORING ); osg::StateSet* ss = getOrCreateStateSet(); ss->setAttributeAndModes( vp, osg::StateAttribute::ON ); } }
osg::Group* run(osg::Node* node) { float radius = osgEarth::SpatialReference::get("wgs84")->getEllipsoid()->getRadiusEquator(); VirtualProgram* vp = VirtualProgram::getOrCreate(node->getOrCreateStateSet()); // Install the shader function: vp->setFunction("make_it_red", fragShader, ShaderComp::LOCATION_FRAGMENT_LIGHTING); // Set a maximum LOD range for the above function: vp->setFunctionMinRange( "make_it_red", 500000 ); vp->setFunctionMaxRange( "make_it_red", 1000000 ); osg::Group* g = new osg::Group(); // Install a callback that will convey the LOD range to the shader LOD. g->addCullCallback( new RangeUniformCullCallback() ); g->addChild( node ); return g; }
void FeaturesToNodeFilter::applyLineSymbology(osg::StateSet* stateset, const LineSymbol* line) { if ( line && line->stroke().isSet() ) { if ( line->stroke()->width().isSet() ) { float width = std::max( 1.0f, *line->stroke()->width() ); if ( width != 1.0f ) { stateset->setAttributeAndModes(new osg::LineWidth(width), 1); } } if ( line->stroke()->stipplePattern().isSet() ) { #if 1 stateset->setAttributeAndModes( new osg::LineStipple( line->stroke()->stippleFactor().value(), line->stroke()->stipplePattern().value()), osg::StateAttribute::ON ); #else // goofing around... const char* frag = "#version 110\n" "void oe_stipple_frag(inout vec4 color) {\n" " float x = mod(gl_FragCoord.x, 5.0);\n" " float y = mod(gl_FragCoord.y, 5.0);\n" " if (x < y)\n" " color.a = 0.0;\n" "}\n"; VirtualProgram* vp = VirtualProgram::getOrCreate(stateset); vp->setFunction("oe_stipple_frag", frag, ShaderComp::LOCATION_FRAGMENT_COLORING); #endif } } }
void DiscardAlphaFragments::install(osg::StateSet* ss, float minAlpha) const { if ( ss && minAlpha < 1.0f && Registry::capabilities().supportsGLSL() ) { VirtualProgram* vp = VirtualProgram::getOrCreate(ss); if ( vp ) { std::string code = Stringify() << "#version " GLSL_VERSION_STR "\n" << "void oe_discardalpha_frag(inout vec4 color) { \n" << " if ( color.a < " << std::setprecision(1) << minAlpha << ") discard;\n" << "} \n"; vp->setFunction( "oe_discardalpha_frag", code, ShaderComp::LOCATION_FRAGMENT_COLORING, 0L, 0.95f); } } }
void ShaderGenerator::apply(osg::ClipNode& node) { static const char* s_clip_source = "#version " GLSL_VERSION_STR "\n" "void oe_sg_set_clipvertex(inout vec4 vertexVIEW)\n" "{\n" " gl_ClipVertex = vertexVIEW; \n" "}\n"; if ( !_active ) return; if ( ignore(&node) ) return; VirtualProgram* vp = VirtualProgram::getOrCreate(node.getOrCreateStateSet()); if ( vp->referenceCount() == 1 ) vp->setName( _name ); vp->setFunction( "oe_sg_set_clipvertex", s_clip_source, ShaderComp::LOCATION_VERTEX_VIEW ); apply( static_cast<osg::Group&>(node) ); }
void traverse(osg::NodeVisitor& nv) { if (nv.getVisitorType() == nv.UPDATE_VISITOR) { if ( (nv.getFrameStamp()->getFrameNumber() % 2) == 0 ) { _toggle = !_toggle; VirtualProgram* vp = VirtualProgram::getOrCreate(this->getOrCreateStateSet()); if ( _toggle ) { vp->setFunction( "make_it_red", fragShader, osgEarth::ShaderComp::LOCATION_FRAGMENT_COLORING, new Acceptor() ); } else { vp->removeShader("make_it_red"); } } } osg::Group::traverse(nv); }
bool HighlightDecoration::apply(AnnotationNode& node, bool enable) { if ( _supported ) { osg::StateSet* ss = node.getOrCreateStateSet(); if ( enable ) { VirtualProgram* vp = VirtualProgram::getOrCreate( ss ); if ( vp->getShader(FRAG_FUNCTION) == 0L ) { vp->setFunction(FRAG_FUNCTION, fragSource, ShaderComp::LOCATION_FRAGMENT_COLORING); ss->addUniform( _colorUniform.get() ); } _colorUniform->set(_color); } else { // sets alpha=0 to disable highlighting _colorUniform->set(osg::Vec4f(1,1,1,0)); } } return _supported; }
void DrawInstanced::install(osg::StateSet* stateset) { if ( !stateset ) return; // simple vertex program to position a vertex based on its instance // matrix, which is stored in a texture. std::string src_vert = Stringify() << "#version 120 \n" << "#extension GL_EXT_gpu_shader4 : enable \n" << "#extension GL_ARB_draw_instanced: enable \n" << "uniform sampler2D oe_di_postex; \n" << "uniform vec2 oe_di_postex_size; \n" << "void oe_di_setInstancePosition(inout vec4 VertexMODEL) \n" << "{ \n" << " float index = float(4 * gl_InstanceID) / oe_di_postex_size.x; \n" << " float s = fract(index); \n" << " float t = floor(index)/oe_di_postex_size.y; \n" << " float step = 1.0 / oe_di_postex_size.x; \n" // step from one vec4 to the next << " vec4 m0 = texture2D(oe_di_postex, vec2(s, t)); \n" << " vec4 m1 = texture2D(oe_di_postex, vec2(s+step, t)); \n" << " vec4 m2 = texture2D(oe_di_postex, vec2(s+step+step, t)); \n" << " vec4 m3 = texture2D(oe_di_postex, vec2(s+step+step+step, t)); \n" << " VertexMODEL = VertexMODEL * mat4(m0, m1, m2, m3); \n" // why??? << "} \n"; VirtualProgram* vp = VirtualProgram::getOrCreate(stateset); vp->setFunction( "oe_di_setInstancePosition", src_vert, ShaderComp::LOCATION_VERTEX_MODEL ); stateset->getOrCreateUniform("oe_di_postex", osg::Uniform::SAMPLER_2D)->set(POSTEX_TEXTURE_UNIT); }
// Generates the main shader code for rendering the terrain. void MPTerrainEngineNode::updateState() { if ( _batchUpdateInProgress ) { _stateUpdateRequired = true; } else { osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); // required for multipass tile rendering to work terrainStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); // install shaders, if we're using them. if ( Registry::capabilities().supportsGLSL() ) { VirtualProgram* vp = new VirtualProgram(); vp->setName( "osgEarth.engine_mp.TerrainNode" ); terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // bind the vertex attributes generated by the tile compiler. vp->addBindAttribLocation( "oe_terrain_attr", osg::Drawable::ATTRIBUTE_6 ); vp->addBindAttribLocation( "oe_terrain_attr2", osg::Drawable::ATTRIBUTE_7 ); // Vertex shader: std::string vs = Stringify() << "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc;\n" "varying vec4 oe_layer_tilec;\n" "void oe_mp_setup_coloring(inout vec4 VertexModel) \n" "{ \n" " oe_layer_texc = gl_MultiTexCoord" << _primaryUnit << ";\n" " oe_layer_tilec = gl_MultiTexCoord" << _secondaryUnit << ";\n" "}\n"; bool useTerrainColor = _terrainOptions.color().isSet(); bool useBlending = _terrainOptions.enableBlending() == true; // Fragment Shader for normal blending: std::string fs = Stringify() << "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc; \n" "uniform sampler2D oe_layer_tex; \n" "uniform int oe_layer_uid; \n" "uniform int oe_layer_order; \n" "uniform float oe_layer_opacity; \n" << (useTerrainColor ? "uniform vec4 oe_terrain_color; \n" : "" ) << "void oe_mp_apply_coloring(inout vec4 color) \n" "{ \n" << (useTerrainColor ? " color = oe_terrain_color; \n" : "" ) << //" color = vec4(1,1,1,1); \n" " vec4 texel; \n" " if ( oe_layer_uid >= 0 ) { \n" " texel = texture2D(oe_layer_tex, oe_layer_texc.st); \n" " texel.a *= oe_layer_opacity; \n" " } \n" " else \n" " texel = color; \n" " " << (useBlending ? " if ( oe_layer_order == 0 ) \n" " color = texel*texel.a + color*(1.0-texel.a); \n" // simulate src_alpha, 1-src_alpha blens " else \n" : "" ) << " color = texel; \n" "} \n"; // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "__COLOR_FILTER_HEAD__" "void oe_mp_apply_filters(inout vec4 color) \n" "{ \n" "__COLOR_FILTER_BODY__" "} \n"; vp->setFunction( "oe_mp_setup_coloring", vs, ShaderComp::LOCATION_VERTEX_MODEL, 0.0 ); vp->setFunction( "oe_mp_apply_coloring", fs, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); // assemble color filter code snippets. bool haveColorFilters = false; { std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; int numImageLayers = _update_mapf->imageLayers().size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = _update_mapf->getImageLayerAt(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( terrainStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "__COLOR_FILTER_HEAD__", cf_head_str ); replaceIn( fs_colorfilters, "__COLOR_FILTER_BODY__", cf_body_str ); vp->setFunction( "oe_mp_apply_filters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); } } // binding for the terrain texture terrainStateSet->getOrCreateUniform( "oe_layer_tex", osg::Uniform::SAMPLER_2D )->set( _primaryUnit ); // binding for the secondary texture (for LOD blending) terrainStateSet->getOrCreateUniform( "oe_layer_tex_parent", osg::Uniform::SAMPLER_2D )->set( _secondaryUnit ); // binding for the default secondary texture matrix osg::Matrixf parent_mat; parent_mat(0,0) = 0.0f; terrainStateSet->getOrCreateUniform( "oe_layer_parent_matrix", osg::Uniform::FLOAT_MAT4 )->set( parent_mat ); // uniform that controls per-layer opacity terrainStateSet->getOrCreateUniform( "oe_layer_opacity", osg::Uniform::FLOAT )->set( 1.0f ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->getOrCreateUniform( "oe_layer_uid", osg::Uniform::INT )->set( -1 ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->getOrCreateUniform( "oe_layer_order", osg::Uniform::INT )->set( 0 ); // base terrain color. if ( useTerrainColor ) { terrainStateSet->getOrCreateUniform( "oe_terrain_color", osg::Uniform::FLOAT_VEC4 )->set( *_terrainOptions.color() ); } } _stateUpdateRequired = false; } }
void OverlayDecorator::initSubgraphShaders( osg::StateSet* set ) { VirtualProgram* vp = new VirtualProgram(); vp->setName( "OverlayDecorator subgraph shader" ); set->setAttributeAndModes( vp, osg::StateAttribute::ON ); // sampler for projected texture: set->getOrCreateUniform( "osgearth_overlay_ProjTex", osg::Uniform::SAMPLER_2D )->set( *_textureUnit ); // the texture projection matrix uniform. _texGenUniform = set->getOrCreateUniform( "osgearth_overlay_TexGenMatrix", osg::Uniform::FLOAT_MAT4 ); std::stringstream buf; // vertex shader - subgraph buf << "#version 110 \n" << "uniform mat4 osgearth_overlay_TexGenMatrix; \n" << "uniform mat4 osg_ViewMatrixInverse; \n" << "void osgearth_overlay_vertex(void) \n" << "{ \n" << " gl_TexCoord["<< *_textureUnit << "] = osgearth_overlay_TexGenMatrix * osg_ViewMatrixInverse * gl_ModelViewMatrix * gl_Vertex; \n" << "} \n"; std::string vertexSource = buf.str(); vp->setFunction( "osgearth_overlay_vertex", vertexSource, ShaderComp::LOCATION_VERTEX_POST_LIGHTING ); // fragment shader - subgraph buf.str(""); buf << "#version 110 \n" << "uniform sampler2D osgearth_overlay_ProjTex; \n"; if ( _useWarping ) { buf << "uniform float warp; \n" // because the built-in pow() is busted << "float mypow( in float x, in float y ) \n" << "{ \n" << " return x/(x+y-y*x); \n" << "} \n" << "vec2 warpTexCoord( in vec2 src ) \n" << "{ \n" // incoming tex coord is [0..1], so we scale to [-1..1] << " vec2 srcn = vec2( src.x*2.0 - 1.0, src.y*2.0 - 1.0 ); \n" // we want to work in the [0..1] space on each side of 0, so can the abs // and store the signs for later: << " vec2 srct = vec2( abs(srcn.x), abs(srcn.y) ); \n" << " vec2 sign = vec2( srcn.x > 0.0 ? 1.0 : -1.0, srcn.y > 0.0 ? 1.0 : -1.0 ); \n" // apply the deformation using a deceleration curve: << " vec2 srcp = vec2( 1.0-mypow(1.0-srct.x,warp), 1.0-mypow(1.0-srct.y,warp) ); \n" // reapply the sign, and scale back to [0..1]: << " vec2 srcr = vec2( sign.x*srcp.x, sign.y*srcp.y ); \n" << " return vec2( 0.5*(srcr.x + 1.0), 0.5*(srcr.y + 1.0) ); \n" << "} \n"; } buf << "void osgearth_overlay_fragment( inout vec4 color ) \n" << "{ \n" << " vec2 texCoord = gl_TexCoord["<< *_textureUnit << "].xy / gl_TexCoord["<< *_textureUnit << "].q; \n"; if ( _useWarping && !_visualizeWarp ) buf << " texCoord = warpTexCoord( texCoord ); \n"; buf << " vec4 texel = texture2D(osgearth_overlay_ProjTex, texCoord); \n" << " color = vec4( mix( color.rgb, texel.rgb, texel.a ), color.a); \n" << "} \n"; std::string fragmentSource = buf.str(); vp->setFunction( "osgearth_overlay_fragment", fragmentSource, ShaderComp::LOCATION_FRAGMENT_PRE_LIGHTING ); }
bool ShadowUtils::setUpShadows(osgShadow::ShadowedScene* sscene, osg::Group* root) { osg::StateSet* ssStateSet = sscene->getOrCreateStateSet(); MapNode* mapNode = MapNode::findMapNode(root); TerrainEngineNode* engine = mapNode->getTerrainEngine(); if (!engine) return false; TextureCompositor* compositor = engine->getTextureCompositor(); int su = -1; if (!compositor->reserveTextureImageUnit(su)) return false; OE_INFO << LC << "Reserved texture unit " << su << " for shadowing" << std::endl; osgShadow::ViewDependentShadowMap* vdsm = dynamic_cast< osgShadow::ViewDependentShadowMap*>(sscene->getShadowTechnique()); int su1 = -1; if (vdsm && sscene->getShadowSettings()->getNumShadowMapsPerLight() == 2) { if (!compositor->reserveTextureImageUnit(su1) || su1 != su + 1) { OE_FATAL << LC << "couldn't get contiguous shadows for split vdsm\n"; sscene->getShadowSettings()->setNumShadowMapsPerLight(1); if (su1 != -1) compositor->releaseTextureImageUnit(su1); su1 = -1; } else { OE_INFO << LC << "Reserved texture unit " << su1 << " for shadowing" << std::endl; } } // create a virtual program to attach to the shadowed scene. VirtualProgram* vp = new VirtualProgram(); vp->setName( "shadow:terrain" ); //vp->installDefaultColoringAndLightingShaders(); ssStateSet->setAttributeAndModes( vp, 1 ); std::stringstream buf; buf << "#version " << GLSL_VERSION_STR << "\n"; #ifdef OSG_GLES2_AVAILABLE buf << "precision mediump float;\n"; #endif buf << "varying vec4 oe_shadow_ambient;\n"; buf << "varying vec4 oe_shadow_TexCoord0;\n"; if ( su1 >= 0 ) buf << "varying vec4 oe_shadow_TexCoord1;\n"; buf << "void oe_shadow_setupShadowCoords(inout vec4 VertexVIEW)\n"; buf << "{\n"; buf << " vec4 position4 = VertexVIEW;\n"; buf << " oe_shadow_TexCoord0.s = dot( position4, gl_EyePlaneS[" << su <<"]);\n"; buf << " oe_shadow_TexCoord0.t = dot( position4, gl_EyePlaneT[" << su <<"]);\n"; buf << " oe_shadow_TexCoord0.p = dot( position4, gl_EyePlaneR[" << su <<"]);\n"; buf << " oe_shadow_TexCoord0.q = dot( position4, gl_EyePlaneQ[" << su <<"]);\n"; if (su1 >= 0) { buf << " oe_shadow_TexCoord1.s = dot( position4, gl_EyePlaneS[" << su1 <<"]);\n"; buf << " oe_shadow_TexCoord1.t = dot( position4, gl_EyePlaneT[" << su1 <<"]);\n"; buf << " oe_shadow_TexCoord1.p = dot( position4, gl_EyePlaneR[" << su1 <<"]);\n"; buf << " oe_shadow_TexCoord1.q = dot( position4, gl_EyePlaneQ[" << su1 <<"]);\n"; } // the ambient lighting will control the intensity of the shadow. buf << " oe_shadow_ambient = gl_FrontLightProduct[0].ambient; \n" << "}\n"; std::string setupShadowCoords; setupShadowCoords = buf.str(); vp->setFunction( "oe_shadow_setupShadowCoords", setupShadowCoords, ShaderComp::LOCATION_VERTEX_VIEW, -1.0 ); std::stringstream buf2; buf2 << "#version " << GLSL_VERSION_STR << "\n" #ifdef OSG_GLES2_AVAILABLE "precision mediump float;\n" #endif "uniform sampler2DShadow shadowTexture;\n" "varying vec4 oe_shadow_TexCoord0;\n"; if (su1 >= 0) { // bound by vdsm buf2 << "uniform sampler2DShadow shadowTexture1;\n"; buf2 << "varying vec4 oe_shadow_TexCoord1;\n"; } buf2 << "varying vec4 oe_shadow_ambient;\n" "void oe_shadow_applyLighting( inout vec4 color )\n" "{\n" " float alpha = color.a;\n" " float shadowFac = shadow2DProj( shadowTexture, oe_shadow_TexCoord0).r;\n"; if (su1 > 0) { buf2 << " shadowFac *= shadow2DProj( shadowTexture1, oe_shadow_TexCoord1).r;\n"; } // calculate the shadowed color and mix if with the lit color based on the // ambient lighting. The 0.5 is a multiplier that darkens the shadow in // proportion to ambient light. It should probably be a uniform. buf2 << " vec4 colorInFullShadow = color * oe_shadow_ambient; \n" " color = mix(colorInFullShadow, color, shadowFac); \n" " color.a = alpha;\n" "}\n"; std::string fragApplyLighting; fragApplyLighting = buf2.str(); vp->setFunction( "oe_shadow_applyLighting", fragApplyLighting, osgEarth::ShaderComp::LOCATION_FRAGMENT_LIGHTING ); setShadowUnit(sscene, su); // VDSM uses a different sampler name, shadowTexture0. ssStateSet ->getOrCreateUniform("shadowTexture", osg::Uniform::SAMPLER_2D_SHADOW) ->set(su); return true; }
void ClampingBinTechnique::setUpCamera(OverlayDecorator::TechRTTParams& params) { // To store technique-specific per-view info: LocalPerViewData* local = new LocalPerViewData(); params._techniqueData = local; // set up a callback to extract the overlay projection matrix. local->_cpm = new CPM(); // create the projected texture: local->_rttTexture = new osg::Texture2D(); local->_rttTexture->setTextureSize( *_textureSize, *_textureSize ); local->_rttTexture->setInternalFormat( GL_DEPTH_COMPONENT ); local->_rttTexture->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR ); local->_rttTexture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); // this is important. geometry that is outside the depth texture will clamp to the // closest edge value in the texture -- this is good when you are rendering a // primitive that has one or more of its verts off-screen. local->_rttTexture->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE ); local->_rttTexture->setWrap( osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE ); //local->_rttTexture->setBorderColor( osg::Vec4(0,0,0,1) ); // set up the RTT camera: params._rttCamera = new osg::Camera(); params._rttCamera->setReferenceFrame( osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ); params._rttCamera->setClearColor( osg::Vec4f(0,0,0,0) ); params._rttCamera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); params._rttCamera->setComputeNearFarMode( osg::CullSettings::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES ); params._rttCamera->setViewport( 0, 0, *_textureSize, *_textureSize ); params._rttCamera->setRenderOrder( osg::Camera::PRE_RENDER ); params._rttCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT ); params._rttCamera->attach( osg::Camera::DEPTH_BUFFER, local->_rttTexture.get() ); params._rttCamera->setClampProjectionMatrixCallback( local->_cpm.get() ); // set up a StateSet for the RTT camera. osg::StateSet* rttStateSet = params._rttCamera->getOrCreateStateSet(); // lighting is off. We don't want draped items to be lit. //rttStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED ); rttStateSet->setMode( GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); // prevents wireframe mode in the depth camera. rttStateSet->setAttributeAndModes( new osg::PolygonMode( osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL ), osg::StateAttribute::ON | osg::StateAttribute::PROTECTED ); #if 0 //OOPS this kills things like a vertical scale shader!! // installs a dirt-simple program for rendering the depth texture that // skips all the normal terrain rendering stuff osg::Program* depthProg = new osg::Program(); depthProg->addShader(new osg::Shader( osg::Shader::VERTEX, "void main() { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; }\n")); depthProg->addShader(new osg::Shader( osg::Shader::FRAGMENT, "void main() { gl_FragColor = vec4(1,1,1,1); }\n")); rttStateSet->setAttributeAndModes( depthProg, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED ); #endif // attach the terrain to the camera. // todo: should probably protect this with a mutex..... params._rttCamera->addChild( _engine ); //params._terrainParent->getChild(0) ); // the terrain itself. // assemble the overlay graph stateset. local->_groupStateSet = new osg::StateSet(); local->_groupStateSet->setTextureAttributeAndModes( _textureUnit, local->_rttTexture.get(), osg::StateAttribute::ON ); // set up depth test/write parameters for the overlay geometry: local->_groupStateSet->setAttributeAndModes( new osg::Depth( osg::Depth::LEQUAL, 0.0, 1.0, false ), osg::StateAttribute::ON ); local->_groupStateSet->setRenderingHint( osg::StateSet::TRANSPARENT_BIN ); // sampler for depth map texture: local->_groupStateSet->getOrCreateUniform( "oe_clamp_depthtex", osg::Uniform::SAMPLER_2D )->set( _textureUnit ); // matrix that transforms a vert from EYE coords to the depth camera's CLIP coord. local->_camViewToDepthClipUniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_eye2depthclipmat", osg::Uniform::FLOAT_MAT4 ); // matrix that transforms a vert from depth-cam CLIP coords to EYE coords. local->_depthClipToCamViewUniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_depthclip2eyemat", osg::Uniform::FLOAT_MAT4 ); // make the shader that will do clamping and depth offsetting. VirtualProgram* vp = new VirtualProgram(); vp->setName( "ClampingBinTechnique program" ); local->_groupStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // vertex shader - subgraph std::string vertexSource = Stringify() << "#version " << GLSL_VERSION_STR << "\n" #ifdef OSG_GLES2_AVAILABLE << "precision mediump float;\n" #endif // uniforms from this ClampingBinTechnique: << "uniform sampler2D oe_clamp_depthtex; \n" << "uniform mat4 oe_clamp_eye2depthclipmat; \n" << "uniform mat4 oe_clamp_depthclip2eyemat; \n" // uniforms from ClampableNode: << "uniform vec2 oe_clamp_bias; \n" << "uniform vec2 oe_clamp_range; \n" << "varying vec4 oe_clamp_simvert; \n" << "varying float oe_clamp_simvertrange; \n" << "void oe_clamp_vertex(void) \n" << "{ \n" // transform the vertex into the depth texture's clip coordinates. << " vec4 v_eye_orig = gl_ModelViewMatrix * gl_Vertex; \n" << " vec4 tc = oe_clamp_eye2depthclipmat * v_eye_orig; \n" // sample the depth map. << " float d = texture2DProj( oe_clamp_depthtex, tc ).r; \n" // make a fake point in depth clip space and transform it back into eye coords. << " vec4 p = vec4(tc.x, tc.y, d, 1.0); \n" << " vec4 v_eye_clamped = oe_clamp_depthclip2eyemat * p; \n" // if the clamping distance is too big, bag it. << " vec3 v_eye_orig3 = v_eye_orig.xyz/v_eye_orig.w;\n" << " vec3 v_eye_clamped3 = v_eye_clamped.xyz/v_eye_clamped.w; \n" << " float clamp_distance = length(v_eye_orig3 - v_eye_clamped3); \n" << " const float maxClampDistance = 10000.0; \n" << " if ( clamp_distance > maxClampDistance ) \n" << " { \n" << " gl_Position = gl_ProjectionMatrix * v_eye_orig; \n" // still have to populate these to nullify the depth offset code. << " oe_clamp_simvert = gl_Position; \n" << " oe_clamp_simvertrange = 1.0; \n" << " } \n" << " else \n" << " { \n" // now simulate a "closer" vertex for depth offsetting. // remap depth offset based on camera distance to vertex. The farther you are away, // the more of an offset you need. << " float range = length(v_eye_clamped3); \n" << " float ratio = (clamp(range, oe_clamp_range[0], oe_clamp_range[1])-oe_clamp_range[0])/(oe_clamp_range[1]-oe_clamp_range[0]);\n" << " float bias = oe_clamp_bias[0] + ratio * (oe_clamp_bias[1]-oe_clamp_bias[0]);\n" << " vec3 adj_vec = normalize(v_eye_clamped3); \n" << " vec3 v_eye_offset3 = v_eye_clamped3 - (adj_vec * bias); \n" << " vec4 v_sim_eye = vec4( v_eye_offset3 * v_eye_clamped.w, v_eye_clamped.w ); \n" << " oe_clamp_simvert = gl_ProjectionMatrix * v_sim_eye;\n" << " oe_clamp_simvertrange = range - bias; \n" << " gl_Position = gl_ProjectionMatrix * v_eye_clamped; \n" << " } \n" << "} \n"; vp->setFunction( "oe_clamp_vertex", vertexSource, ShaderComp::LOCATION_VERTEX_POST_LIGHTING ); // fragment shader - depth offset apply std::string frag = "varying vec4 oe_clamp_simvert; \n" "varying float oe_clamp_simvertrange; \n" "void oe_clamp_fragment(inout vec4 color)\n" "{ \n" " float sim_depth = 0.5 * (1.0+(oe_clamp_simvert.z/oe_clamp_simvert.w));\n" // if the offset pushed the Z behind the eye, the projection mapping will // result in a z>1. We need to bring these values back down to the // near clip plan (z=0). We need to check simRange too before doing this // so we don't draw fragments that are legitimently beyond the far clip plane. " if ( sim_depth > 1.0 && oe_clamp_simvertrange < 0.0 ) { sim_depth = 0.0; } \n" " gl_FragDepth = max(0.0, sim_depth); \n" "}\n"; vp->setFunction( "oe_clamp_fragment", frag, ShaderComp::LOCATION_FRAGMENT_PRE_LIGHTING ); }
int main(int argc, char** argv) { osg::ArgumentParser arguments(&argc,argv); // help? if ( arguments.read("--help") ) return usage(argv[0]); // create a viewer: osgViewer::Viewer viewer(arguments); // Tell the database pager to not modify the unref settings viewer.getDatabasePager()->setUnrefImageDataAfterApplyPolicy( false, false ); // install our default manipulator (do this before calling load) viewer.setCameraManipulator( new EarthManipulator(arguments) ); // disable the small-feature culling viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f); // set a near/far ratio that is smaller than the default. This allows us to get // closer to the ground without near clipping. If you need more, use --logdepth viewer.getCamera()->setNearFarRatio(0.0001); // load an earth file, and support all or our example command-line options // and earth file <external> tags osg::Node* node = MapNodeHelper().load( arguments, &viewer ); if ( node ) { // Get the MapNode MapNode* mapNode = MapNode::findMapNode( node ); // Find the Splat Extension SplatExtension* splatExtension = mapNode->getExtension<SplatExtension>(); if (splatExtension) { OE_NOTICE << "Found Splat Extension" << std::endl; } LandCoverTerrainEffect* landCoverEffect = mapNode->getTerrainEngine()->getEffect<LandCoverTerrainEffect>(); if (landCoverEffect) { OE_NOTICE << "Found landcover terrain effect" << std::endl; for (Zones::const_iterator zoneItr = landCoverEffect->getZones().begin(); zoneItr != landCoverEffect->getZones().end(); ++zoneItr) { // Get the StateSet for each of the LandCoverLayers for (LandCoverLayers::iterator landCoverItr = zoneItr->get()->getLandCover()->getLayers().begin(); landCoverItr != zoneItr->get()->getLandCover()->getLayers().end(); ++landCoverItr) { // Get the stateset for the layer. osg::StateSet* stateset = landCoverItr->get()->getOrCreateStateSet(); // Get the VirtualProgram for this layer. VirtualProgram* vp = VirtualProgram::getOrCreate(stateset); // Make the "tree" layer all red. if (landCoverItr->get()->getName() == "trees") { vp->setFunction( "color_landcover", color_landcover, ShaderComp::LOCATION_FRAGMENT_LIGHTING); } } } } viewer.setSceneData( node ); while(!viewer.done()) { viewer.frame(); } } else { return usage(argv[0]); } }
void ShadowCaster::reinitialize() { if ( !_supported ) return; _shadowmap = 0L; _rttCameras.clear(); int numSlices = (int)_ranges.size() - 1; if ( numSlices < 1 ) { OE_WARN << LC << "Illegal. Must have at least one range slice." << std::endl; return ; } // create the projected texture: _shadowmap = new osg::Texture2DArray(); _shadowmap->setTextureSize( _size, _size, numSlices ); _shadowmap->setInternalFormat( GL_DEPTH_COMPONENT ); _shadowmap->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR ); _shadowmap->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); _shadowmap->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER ); _shadowmap->setWrap( osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER ); _shadowmap->setBorderColor(osg::Vec4(1,1,1,1)); // set up the RTT camera: for(int i=0; i<numSlices; ++i) { osg::Camera* rtt = new osg::Camera(); Shadowing::setIsShadowCamera(rtt); rtt->setReferenceFrame( osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ); rtt->setClearDepth( 1.0 ); rtt->setClearMask( GL_DEPTH_BUFFER_BIT ); rtt->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR ); rtt->setViewport( 0, 0, _size, _size ); rtt->setRenderOrder( osg::Camera::PRE_RENDER ); rtt->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT ); rtt->setImplicitBufferAttachmentMask(0, 0); rtt->attach( osg::Camera::DEPTH_BUFFER, _shadowmap.get(), 0, i ); rtt->addChild( _castingGroup.get() ); _rttCameras.push_back(rtt); } _rttStateSet = new osg::StateSet(); // only draw back faces to the shadow depth map _rttStateSet->setAttributeAndModes( new osg::CullFace(osg::CullFace::FRONT), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); _rttStateSet->addUniform(new osg::Uniform("oe_isShadowCamera", true), osg::StateAttribute::OVERRIDE); _renderStateSet = new osg::StateSet(); std::string vertex = Stringify() << "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform mat4 oe_shadow_matrix[" << numSlices << "]; \n" "varying vec4 oe_shadow_coord[" << numSlices << "]; \n" "void oe_shadow_vertex(inout vec4 VertexVIEW) \n" "{ \n" " for(int i=0; i<" << numSlices << "; ++i) \n" " oe_shadow_coord[i] = oe_shadow_matrix[i] * VertexVIEW;\n" "} \n"; std::string fragment = Stringify() << "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "#extension GL_EXT_texture_array : enable \n" "uniform sampler2DArray oe_shadow_map; \n" "uniform vec4 oe_shadow_color; \n" "uniform float oe_shadow_blur; \n" "varying vec3 vp_Normal; \n" "varying vec4 oe_shadow_coord[" << numSlices << "]; \n" //TODO-run a generator and rplace "#define OE_SHADOW_NUM_SAMPLES 16\n" "const vec2 oe_shadow_samples[OE_SHADOW_NUM_SAMPLES] = vec2[]( vec2( -0.942016, -0.399062 ), vec2( 0.945586, -0.768907 ), vec2( -0.094184, -0.929389 ), vec2( 0.344959, 0.293878 ), vec2( -0.915886, 0.457714 ), vec2( -0.815442, -0.879125 ), vec2( -0.382775, 0.276768 ), vec2( 0.974844, 0.756484 ), vec2( 0.443233, -0.975116 ), vec2( 0.53743, -0.473734 ), vec2( -0.264969, -0.41893 ), vec2( 0.791975, 0.190909 ), vec2( -0.241888, 0.997065 ), vec2( -0.8141, 0.914376 ), vec2( 0.199841, 0.786414 ), vec2( 0.143832, -0.141008 )); \n" "float oe_shadow_rand(vec2 co){\n" " return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\n" "}\n" "vec2 oe_shadow_rot(vec2 p, float a) { \n" " vec2 sincos = vec2(sin(a), cos(a)); \n" " return vec2(dot(p, vec2(sincos.y, -sincos.x)), dot(p, sincos.xy)); \n" "}\n" // slow PCF sampling. "float oe_shadow_multisample(in vec3 c, in float refvalue, in float blur) \n" "{ \n" " float shadowed = 0.0; \n" " float a = 6.283185 * oe_shadow_rand(c.xy); \n" " vec4 b = vec4(oe_shadow_rot(vec2(1,0),a), oe_shadow_rot(vec2(0,1),a)); \n" " for(int i=0; i<OE_SHADOW_NUM_SAMPLES; ++i) { \n" " vec2 off = oe_shadow_samples[i];\n" " off = vec2(dot(off,b.xz), dot(off,b.yw)); \n" " vec3 pc = vec3(c.xy + off*blur, c.z); \n" " float depth = texture2DArray(oe_shadow_map, pc).r; \n" " if ( depth < 1.0 && depth < refvalue ) { \n" " shadowed += 1.0; \n" " } \n" " } \n" " return 1.0-(shadowed/OE_SHADOW_NUM_SAMPLES); \n" "} \n" "void oe_shadow_fragment( inout vec4 color )\n" "{\n" " float alpha = color.a; \n" " float factor = 1.0; \n" // pre-pixel biasing to reduce moire/acne " const float b0 = 0.001; \n" " const float b1 = 0.01; \n" " vec3 L = normalize(gl_LightSource[0].position.xyz); \n" " vec3 N = normalize(vp_Normal); \n" " float costheta = clamp(dot(L,N), 0.0, 1.0); \n" " float bias = b0*tan(acos(costheta)); \n" // loop over the slices: " for(int i=0; i<" << numSlices << " && factor > 0.0; ++i) \n" " { \n" " vec4 c = oe_shadow_coord[i]; \n" " vec3 coord = vec3(c.x, c.y, float(i)); \n" " if ( oe_shadow_blur > 0.0 ) \n" " { \n" " factor = min(factor, oe_shadow_multisample(coord, c.z-bias, oe_shadow_blur)); \n" " } \n" " else \n" " { \n" " float depth = texture2DArray(oe_shadow_map, coord).r; \n" " if ( depth < 1.0 && depth < c.z-bias ) \n" " factor = 0.0; \n" " } \n" " } \n" " vec4 colorInFullShadow = color * oe_shadow_color; \n" " color = mix(colorInFullShadow, color, factor); \n" " color.a = alpha;\n" "}\n"; VirtualProgram* vp = VirtualProgram::getOrCreate(_renderStateSet.get()); vp->setFunction( "oe_shadow_vertex", vertex, ShaderComp::LOCATION_VERTEX_VIEW, 0.9f ); vp->setFunction( "oe_shadow_fragment", fragment, ShaderComp::LOCATION_FRAGMENT_LIGHTING, 0.9f ); // the texture coord generator matrix array (from the caster): _shadowMapTexGenUniform = _renderStateSet->getOrCreateUniform( "oe_shadow_matrix", osg::Uniform::FLOAT_MAT4, numSlices ); // bind the shadow map texture itself: _renderStateSet->setTextureAttribute( _texImageUnit, _shadowmap.get(), osg::StateAttribute::ON ); _renderStateSet->addUniform( new osg::Uniform("oe_shadow_map", _texImageUnit) ); // blur factor: _shadowBlurUniform = _renderStateSet->getOrCreateUniform( "oe_shadow_blur", osg::Uniform::FLOAT); _shadowBlurUniform->set(_blurFactor); // shadow color: _shadowColorUniform = _renderStateSet->getOrCreateUniform( "oe_shadow_color", osg::Uniform::FLOAT_VEC4); _shadowColorUniform->set(_color); }
osg::Node* run(osg::Node* earthfile) { // 32-bit vertex shader, for reference only. This shader will exceed // the single-precision capacity and cause "jumping verts" at the // camera make small movements. const char* vs32 = "#version 330 \n" "uniform mat4 osg_ViewMatrixInverse; \n" "flat out float isRed; \n" "void vertex(inout vec4 v32) \n" "{ \n" " vec4 world = osg_ViewMatrixInverse * v32; \n" " world /= world.w; \n" " float len = length(world); \n" " const float R = 6371234.5678; \n" " isRed = 0.0; \n" " if (len > R) \n" " isRed = 1.0;" "}\n"; // 64-bit vertex shader. This shader uses a double-precision inverse // view matrix and calculates the altitude all in double precision; // therefore the "jumping verts" problem in the 32-bit version is // resolved. (Mostly-- you will still see the jumping if you view the // earth from orbit, because the 32-bit vertex itself is very far from // the camera in view coordinates. If that is an issue, you need to pass // in 64-bit vertex attributes.) const char* vs64 = "#version 330 \n" "#extension GL_ARB_gpu_shader_fp64 : enable \n" "uniform dmat4 u_ViewMatrixInverse64; \n" // must use a 64-bit VMI. "flat out float isRed; \n" "flat out double vary64; \n" // just to test shadercomp framework "void vertex(inout vec4 v32) \n" "{ \n" " dvec4 v64 = dvec4(v32); \n" // upcast to 64-bit, no precision loss // unless camera is very far away " dvec4 world = u_ViewMatrixInverse64 * v64; \n" // xform into world coords " world /= world.w; \n" // divide by w " double len = length(world.xyz); \n" // get double-precision vector length. " const double R = 6371234.5678; \n" // arbitrary earth radius threshold " isRed = (len > R) ? 1.0 : 0.0; \n" "}\n"; // frag shader: color the terrain red if the incoming varying is non-zero. const char* fs = "#version 330 \n" "#extension GL_ARB_gpu_shader_fp64 : enable \n" "flat in float isRed; \n" "flat in double vary64; \n" "void fragment(inout vec4 color) \n" "{ \n" " if (isRed > 0.0f) { \n" " color.r = 1.0; \n" " color.gb *= 0.5; \n" " } \n" "} \n"; // installs a double-precision inverse view matrix for our shader to use. struct VMI64Callback : public osg::NodeCallback { void operator()(osg::Node* node, osg::NodeVisitor* nv) { osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv); osg::Uniform* u = new osg::Uniform(osg::Uniform::DOUBLE_MAT4, "u_ViewMatrixInverse64"); u->set(cv->getCurrentCamera()->getInverseViewMatrix()); osg::ref_ptr<osg::StateSet> ss = new osg::StateSet(); ss->addUniform(u); cv->pushStateSet(ss.get()); traverse(node, nv); cv->popStateSet(); } }; earthfile->setCullCallback(new VMI64Callback()); osg::StateSet* ss = earthfile->getOrCreateStateSet(); VirtualProgram* vp = VirtualProgram::getOrCreate(ss); vp->setFunction("vertex", vs64, ShaderComp::LOCATION_VERTEX_VIEW); vp->setFunction("fragment", fs, ShaderComp::LOCATION_FRAGMENT_COLORING); return earthfile; }
void DrapingTechnique::setUpCamera(OverlayDecorator::TechRTTParams& params) { // create the projected texture: osg::Texture2D* projTexture = new osg::Texture2D(); projTexture->setTextureSize( *_textureSize, *_textureSize ); projTexture->setInternalFormat( GL_RGBA ); projTexture->setSourceFormat( GL_RGBA ); projTexture->setSourceType( GL_UNSIGNED_BYTE ); projTexture->setFilter( osg::Texture::MIN_FILTER, _mipmapping? osg::Texture::LINEAR_MIPMAP_LINEAR: osg::Texture::LINEAR ); projTexture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); projTexture->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER ); projTexture->setWrap( osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER ); //projTexture->setWrap( osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE ); projTexture->setBorderColor( osg::Vec4(0,0,0,0) ); // set up the RTT camera: params._rttCamera = new osg::Camera(); params._rttCamera->setClearColor( osg::Vec4f(0,0,0,0) ); // this ref frame causes the RTT to inherit its viewpoint from above (in order to properly // process PagedLOD's etc. -- it doesn't affect the perspective of the RTT camera though) params._rttCamera->setReferenceFrame( osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ); params._rttCamera->setViewport( 0, 0, *_textureSize, *_textureSize ); params._rttCamera->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR ); params._rttCamera->setRenderOrder( osg::Camera::PRE_RENDER ); params._rttCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT ); params._rttCamera->attach( osg::Camera::COLOR_BUFFER, projTexture, 0, 0, _mipmapping ); if ( _attachStencil ) { // try a depth-packed buffer. failing that, try a normal one.. if the FBO doesn't support // that (which is doesn't on some GPUs like Intel), it will automatically fall back on // a PBUFFER_RTT impl if ( Registry::capabilities().supportsDepthPackedStencilBuffer() ) { #ifdef OSG_GLES2_AVAILABLE params._rttCamera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, GL_DEPTH24_STENCIL8_EXT ); #else params._rttCamera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, GL_DEPTH_STENCIL_EXT ); #endif } else { params._rttCamera->attach( osg::Camera::STENCIL_BUFFER, GL_STENCIL_INDEX ); } params._rttCamera->setClearStencil( 0 ); params._rttCamera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); } else { params._rttCamera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); } // set up a StateSet for the RTT camera. osg::StateSet* rttStateSet = params._rttCamera->getOrCreateStateSet(); // lighting is off. We don't want draped items to be lit. rttStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED ); // install a new default shader program that replaces anything from above. if ( _useShaders ) { VirtualProgram* vp = VirtualProgram::getOrCreate(rttStateSet); vp->setName( "DrapingTechnique RTT" ); vp->setInheritShaders( false ); //rttStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); } // active blending within the RTT camera's FBO if ( _rttBlending ) { //Setup a separate blend function for the alpha components and the RGB components. //Because the destination alpha is initialized to 0 instead of 1 osg::BlendFunc* blendFunc = 0; if (Registry::capabilities().supportsGLSL(1.4f)) { //Blend Func Separate is only available on OpenGL 1.4 and above blendFunc = new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { blendFunc = new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } rttStateSet->setAttributeAndModes(blendFunc, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } else { rttStateSet->setMode(GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); } // attach the overlay group to the camera. // TODO: we should probably lock this since other cull traversals might be accessing the group // while we are changing its children. params._rttCamera->addChild( params._group ); // overlay geometry is rendered with no depth testing, and in the order it's found in the // scene graph... until further notice. rttStateSet->setMode(GL_DEPTH_TEST, 0); rttStateSet->setBinName( "TraversalOrderBin" ); // add to the terrain stateset, i.e. the stateset that the OverlayDecorator will // apply to the terrain before cull-traversing it. This will activate the projective // texturing on the terrain. params._terrainStateSet->setTextureAttributeAndModes( *_textureUnit, projTexture, osg::StateAttribute::ON ); // fire up the local per-view data: LocalPerViewData* local = new LocalPerViewData(); params._techniqueData = local; if ( _useShaders ) { // GPU path VirtualProgram* vp = VirtualProgram::getOrCreate(params._terrainStateSet); vp->setName( "DrapingTechnique terrain shaders"); //params._terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // sampler for projected texture: params._terrainStateSet->getOrCreateUniform( "oe_overlay_tex", osg::Uniform::SAMPLER_2D )->set( *_textureUnit ); // the texture projection matrix uniform. local->_texGenUniform = params._terrainStateSet->getOrCreateUniform( "oe_overlay_texmatrix", osg::Uniform::FLOAT_MAT4 ); // vertex shader - subgraph std::string vs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform mat4 oe_overlay_texmatrix; \n" "varying vec4 oe_overlay_texcoord; \n" "void oe_overlay_vertex(inout vec4 VertexVIEW) \n" "{ \n" " oe_overlay_texcoord = oe_overlay_texmatrix * VertexVIEW; \n" "} \n"; vp->setFunction( "oe_overlay_vertex", vs, ShaderComp::LOCATION_VERTEX_VIEW ); // fragment shader - subgraph std::string fs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform sampler2D oe_overlay_tex; \n" "varying vec4 oe_overlay_texcoord; \n" "void oe_overlay_fragment( inout vec4 color ) \n" "{ \n" " vec4 texel = texture2DProj(oe_overlay_tex, oe_overlay_texcoord); \n" " color = vec4( mix( color.rgb, texel.rgb, texel.a ), color.a); \n" "} \n"; vp->setFunction( "oe_overlay_fragment", fs, ShaderComp::LOCATION_FRAGMENT_COLORING ); } else { // FFP path local->_texGen = new osg::TexGen(); local->_texGen->setMode( osg::TexGen::EYE_LINEAR ); params._terrainStateSet->setTextureAttributeAndModes( *_textureUnit, local->_texGen.get(), 1 ); osg::TexEnv* env = new osg::TexEnv(); env->setMode( osg::TexEnv::DECAL ); params._terrainStateSet->setTextureAttributeAndModes( *_textureUnit, env, 1 ); } }
int main(int argc, char** argv) { osg::ArgumentParser arguments(&argc,argv); // help? if ( arguments.read("--help") ) return usage(argv[0]); // set up a viewer: osgViewer::Viewer viewer(arguments); viewer.getDatabasePager()->setUnrefImageDataAfterApplyPolicy( false, false ); // install our default manipulator (do this before calling load) viewer.setCameraManipulator( new EarthManipulator() ); // load an earth file, and support all or our example command-line options // and earth file <external> tags osg::Node* node = MapNodeHelper().load( arguments, &viewer ); if ( node ) { // Make a root group: osg::Group* root = new osg::Group(); root->addChild( node ); viewer.setSceneData( root ); // Install a ClipNode. The ClipNode establishes positional state so it // doesn't need to parent anything. In this case it needs to be at the // top of the scene graph since out clip plane calculator assumes // you're in world space. osg::ClipNode* clipNode = new osg::ClipNode(); root->addChild( clipNode ); // By default, the clip node will activate any clip planes you add to it // for its subgraph. Our clip node doesn't parent anything, but we include // this to demonstrate how you would disable that: clipNode->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, 0); // Create a ClipPlane we will use to clip to the visible horizon: osg::ClipPlane* cp = new osg::ClipPlane(); clipNode->addClipPlane( cp ); // This cull callback will recalcuate the position of the clipping plane // each frame based on the camera. const osgEarth::SpatialReference* srs = osgEarth::MapNode::get(node)->getMapSRS(); clipNode->addCullCallback( new ClipToGeocentricHorizon(srs, cp) ); // We also need a shader that will activate clipping in GLSL. VirtualProgram* vp = VirtualProgram::getOrCreate(root->getOrCreateStateSet()); vp->setFunction("oe_clip_vert", clipvs, ShaderComp::LOCATION_VERTEX_VIEW); // Now everything is set up. The last thing to do is: anywhere in your // scene graph that you want to activate the clipping plane, set the // corresponding mode on, like so: // // node->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::ON); // // If you are using symbology, you can use RenderSymbol::clipPlane(). Or in // the earth file, for example: // // render-depth-test: false; // render-clip-plane: 0; return viewer.run(); } else { return usage(argv[0]); } }
void PolygonizeLinesOperator::installShaders(osg::Node* node) const { if ( !node ) return; float minPixels = _stroke.minPixels().getOrUse( 0.0f ); if ( minPixels <= 0.0f ) return; osg::StateSet* stateset = node->getOrCreateStateSet(); VirtualProgram* vp = VirtualProgram::getOrCreate(stateset); // bail if already installed. if ( vp->getName().compare( SHADER_NAME ) == 0 ) return; vp->setName( SHADER_NAME ); const char* vs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "in vec3 oe_polyline_center; \n" "uniform float oe_polyline_scale; \n" "uniform float oe_polyline_min_pixels; \n" "uniform vec4 oe_PixelSizeVector; \n" "void oe_polyline_scalelines(inout vec4 vertex_model4) \n" "{ \n" " const float epsilon = 0.0001; \n" " vec4 center = vec4(oe_polyline_center, 1.0); \n" " vec3 vector = vertex_model4.xyz - center.xyz; \n" " float r = length(vector); \n" " float activate = step(epsilon, r*oe_polyline_min_pixels);\n" " float pixelSize = max(epsilon, 2.0*abs(r/dot(center, oe_PixelSizeVector))); \n" " float min_scale = max(oe_polyline_min_pixels/pixelSize, 1.0); \n" " float scale = mix(1.0, max(oe_polyline_scale, min_scale), activate); \n" " vertex_model4.xyz = center.xyz + vector*scale; \n" "} \n"; vp->setFunction( "oe_polyline_scalelines", vs, ShaderComp::LOCATION_VERTEX_MODEL, 0.5f ); vp->addBindAttribLocation( "oe_polyline_center", ATTR_LOCATION ); // add the default scaling uniform. // good way to test: // osgearth_viewer earthfile --uniform oe_polyline_scale 1.0 10.0 osg::Uniform* scaleU = new osg::Uniform(osg::Uniform::FLOAT, "oe_polyline_scale"); scaleU->set( 1.0f ); stateset->addUniform( scaleU, 1 ); // the default "min pixels" uniform. osg::Uniform* minPixelsU = new osg::Uniform(osg::Uniform::FLOAT, "oe_polyline_min_pixels"); minPixelsU->set( minPixels ); stateset->addUniform( minPixelsU, 1 ); // this will install and update the oe_PixelSizeVector uniform. node->addCullCallback( new PixelSizeVectorCullCallback(stateset) ); }
// Generates the main shader code for rendering the terrain. void MPTerrainEngineNode::updateShaders() { if ( _batchUpdateInProgress ) { _shaderUpdateRequired = true; } else { osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); VirtualProgram* vp = new VirtualProgram(); vp->setName( "engine_mp:TerrainNode" ); terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // bind the vertex attributes generated by the tile compiler. vp->addBindAttribLocation( "oe_terrain_attr", osg::Drawable::ATTRIBUTE_6 ); vp->addBindAttribLocation( "oe_terrain_attr2", osg::Drawable::ATTRIBUTE_7 ); // Vertex shader template: std::string vs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc;\n" "varying vec4 oe_layer_tilec;\n" "void oe_mp_setup_coloring(inout vec4 VertexModel) \n" "{ \n" " oe_layer_texc = __GL_MULTITEXCOORD1__;\n" " oe_layer_tilec = __GL_MULTITEXCOORD2__;\n" "}\n"; // Fragment shader for normal blending: std::string fs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc; \n" "uniform sampler2D oe_layer_tex; \n" "uniform int oe_layer_uid; \n" "uniform int oe_layer_order; \n" "uniform float oe_layer_opacity; \n" "void oe_mp_apply_coloring( inout vec4 color ) \n" "{ \n" " vec4 texel; \n" " if ( oe_layer_uid >= 0 ) { \n" " texel = texture2D(oe_layer_tex, oe_layer_texc.st); \n" " texel.a *= oe_layer_opacity; \n" " } \n" " else \n" " texel = color; \n" " if (oe_layer_order == 0 ) \n" " color = texel*texel.a + color*(1.0-texel.a); \n" // simulate src_alpha, 1-src_alpha blens " else \n" " color = texel; \n" "} \n"; // Fragment shader with pre-multiplied alpha blending: std::string fs_pma = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc; \n" "uniform sampler2D oe_layer_tex; \n" "uniform int oe_layer_uid; \n" "uniform int oe_layer_order; \n" "uniform float oe_layer_opacity; \n" "void oe_mp_apply_coloring_pma( inout vec4 color ) \n" "{ \n" " vec4 texelpma; \n" // a UID < 0 means no texture. " if ( oe_layer_uid >= 0 ) \n" " texelpma = texture2D(oe_layer_tex, oe_layer_texc.st) * oe_layer_opacity; \n" " else \n" " texelpma = color * color.a * oe_layer_opacity; \n" // to PMA. // first layer must PMA-blend with the globe color. " if (oe_layer_order == 0) { \n" " color.rgb *= color.a; \n" " color = texelpma + color*(1.0-texelpma.a); \n" // simulate one, 1-src_alpha blend " } \n" " else { \n" " color = texelpma; \n" " } \n" "} \n"; // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "__COLOR_FILTER_HEAD__" "void oe_mp_apply_filters(inout vec4 color) \n" "{ \n" "__COLOR_FILTER_BODY__" "} \n"; // install the gl_MultiTexCoord* variable that uses the proper texture // image unit: replaceIn( vs, "__GL_MULTITEXCOORD1__", Stringify() << "gl_MultiTexCoord" << _primaryUnit ); replaceIn( vs, "__GL_MULTITEXCOORD2__", Stringify() << "gl_MultiTexCoord" << _secondaryUnit ); vp->setFunction( "oe_mp_setup_coloring", vs, ShaderComp::LOCATION_VERTEX_MODEL, 0.0 ); if ( _terrainOptions.premultipliedAlpha() == true ) vp->setFunction( "oe_mp_apply_coloring_pma", fs_pma, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); else vp->setFunction( "oe_mp_apply_coloring", fs, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); // assemble color filter code snippets. bool haveColorFilters = false; { std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; if ( _terrainOptions.premultipliedAlpha() == true ) { // un-PMA the color before passing it to the color filters. cf_body << I << "if (color.a > 0.0) color.rgb /= color.a; \n"; } // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; int numImageLayers = _update_mapf->imageLayers().size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = _update_mapf->getImageLayerAt(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( terrainStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( _terrainOptions.premultipliedAlpha() == true ) { // re-PMA the color after it passes through the color filters. cf_body << I << "color.rgb *= color.a; \n"; } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "__COLOR_FILTER_HEAD__", cf_head_str ); replaceIn( fs_colorfilters, "__COLOR_FILTER_BODY__", cf_body_str ); vp->setFunction( "oe_mp_apply_filters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); } } if ( _terrainOptions.premultipliedAlpha() == true ) { // activate PMA blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); } else { // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); } // required for multipass tile rendering to work terrainStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // binding for the terrain texture terrainStateSet->getOrCreateUniform( "oe_layer_tex", osg::Uniform::SAMPLER_2D )->set( _primaryUnit ); // binding for the secondary texture (for LOD blending) terrainStateSet->getOrCreateUniform( "oe_layer_tex_parent", osg::Uniform::SAMPLER_2D )->set( _secondaryUnit ); // uniform that controls per-layer opacity terrainStateSet->getOrCreateUniform( "oe_layer_opacity", osg::Uniform::FLOAT )->set( 1.0f ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->getOrCreateUniform( "oe_layer_uid", osg::Uniform::INT )->set( -1 ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->getOrCreateUniform( "oe_layer_order", osg::Uniform::INT )->set( 0 ); _shaderUpdateRequired = false; } }
void SimpleOceanNode::rebuild() { this->removeChildren( 0, this->getNumChildren() ); if ( _parentMapNode.valid() ) { const MapOptions& parentMapOptions = _parentMapNode->getMap()->getMapOptions(); const MapNodeOptions& parentMapNodeOptions = _parentMapNode->getMapNodeOptions(); // set up the map to "match" the parent map: MapOptions mo; mo.coordSysType() = parentMapOptions.coordSysType(); mo.profile() = _parentMapNode->getMap()->getProfile()->toProfileOptions(); // new data model for the ocean: Map* oceanMap = new Map( mo ); // ditto with the map node options: MapNodeOptions mno; if ( mno.enableLighting().isSet() ) mno.enableLighting() = *mno.enableLighting(); MPTerrainEngineOptions mpoptions; mpoptions.heightFieldSkirtRatio() = 0.0; // don't want to see skirts mpoptions.minLOD() = _options.maxLOD().get(); // weird, I know // so we can the surface from underwater: mpoptions.clusterCulling() = false; // want to see underwater mpoptions.enableBlending() = true; // gotsta blend with the main node mpoptions.color() = _options.baseColor().get(); mno.setTerrainOptions( mpoptions ); // make the ocean's map node: MapNode* oceanMapNode = new MapNode( oceanMap, mno ); // if the caller requested a mask layer, install that now. if ( _options.maskLayer().isSet() ) { if ( !_options.maskLayer()->maxLevel().isSet() ) { // set the max subdivision level if it's not already specified in the // mask layer options: _options.maskLayer()->maxLevel() = *_options.maxLOD(); } // make sure the mask is shared (so we can access it from our shader) // and invisible (so we can't see it) _options.maskLayer()->shared() = true; _options.maskLayer()->visible() = false; ImageLayer* maskLayer = new ImageLayer( "ocean-mask", *_options.maskLayer() ); oceanMap->addImageLayer( maskLayer ); } // otherwise, install a "proxy layer" that will use the elevation data in the map // to determine where the ocean is. This approach is limited in that it cannot // detect the difference between ocean and inland areas that are below sea level. else { // install an "elevation proxy" layer that reads elevation tiles from the // parent map and turns them into encoded images for our shader to use. ImageLayerOptions epo( "ocean-proxy" ); epo.cachePolicy() = CachePolicy::NO_CACHE; //epo.maxLevel() = *_options.maxLOD(); oceanMap->addImageLayer( new ElevationProxyImageLayer(_parentMapNode->getMap(), epo) ); } this->addChild( oceanMapNode ); // set up the shaders. osg::StateSet* ss = this->getOrCreateStateSet(); // install the shaders on the ocean map node. VirtualProgram* vp = VirtualProgram::getOrCreate( ss ); vp->setName( "osgEarth SimpleOcean" ); // use the appropriate shader for the active technique: std::string vertSource = _options.maskLayer().isSet() ? source_vertMask : source_vertProxy; std::string fragSource = _options.maskLayer().isSet() ? source_fragMask : source_fragProxy; vp->setFunction( "oe_ocean_vertex", vertSource, ShaderComp::LOCATION_VERTEX_VIEW ); vp->setFunction( "oe_ocean_fragment", fragSource, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.6f ); // install the slot attribute(s) ss->getOrCreateUniform( "ocean_data", osg::Uniform::SAMPLER_2D )->set( 0 ); // set up the options uniforms. _seaLevel = new osg::Uniform(osg::Uniform::FLOAT, "ocean_seaLevel"); ss->addUniform( _seaLevel.get() ); _lowFeather = new osg::Uniform(osg::Uniform::FLOAT, "ocean_lowFeather"); ss->addUniform( _lowFeather.get() ); _highFeather = new osg::Uniform(osg::Uniform::FLOAT, "ocean_highFeather"); ss->addUniform( _highFeather.get() ); _baseColor = new osg::Uniform(osg::Uniform::FLOAT_VEC4, "ocean_baseColor"); ss->addUniform( _baseColor.get() ); _maxRange = new osg::Uniform(osg::Uniform::FLOAT, "ocean_max_range"); ss->addUniform( _maxRange.get() ); _fadeRange = new osg::Uniform(osg::Uniform::FLOAT, "ocean_fade_range"); ss->addUniform( _fadeRange.get() ); // trick to mitigate z-fighting.. ss->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0.0, 1.0, false) ); ss->setRenderingHint( osg::StateSet::TRANSPARENT_BIN ); // load up a surface texture osg::ref_ptr<osg::Image> surfaceImage; ss->getOrCreateUniform( "ocean_has_surface_tex", osg::Uniform::BOOL )->set( false ); if ( _options.textureURI().isSet() ) { //TODO: enable cache support here? surfaceImage = _options.textureURI()->getImage(); } if ( !surfaceImage.valid() ) { surfaceImage = createSurfaceImage(); } if ( surfaceImage.valid() ) { osg::Texture2D* tex = new osg::Texture2D( surfaceImage.get() ); tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR ); tex->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); tex->setWrap ( osg::Texture::WRAP_S, osg::Texture::REPEAT ); tex->setWrap ( osg::Texture::WRAP_T, osg::Texture::REPEAT ); ss->setTextureAttributeAndModes( 2, tex, 1 ); ss->getOrCreateUniform( "ocean_surface_tex", osg::Uniform::SAMPLER_2D )->set( 2 ); ss->getOrCreateUniform( "ocean_has_surface_tex", osg::Uniform::BOOL )->set( true ); } // remove backface culling so we can see underwater // (use OVERRIDE since the terrain engine sets back face culling.) ss->setAttributeAndModes( new osg::CullFace(), osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE ); // Material. osg::Material* m = new osg::Material(); m->setAmbient(m->FRONT_AND_BACK, osg::Vec4(0,0,0,1)); m->setDiffuse(m->FRONT_AND_BACK, osg::Vec4(1,1,1,1)); m->setSpecular(m->FRONT_AND_BACK, osg::Vec4(0.1,0.1,0.1,1)); m->setEmission(m->FRONT_AND_BACK, osg::Vec4(0,0,0,1)); m->setShininess(m->FRONT_AND_BACK, 32.0); ss->setAttributeAndModes(m, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); // force apply options: applyOptions(); } }
void TextureCompositorMultiTexture::updateMasterStateSet(osg::StateSet* stateSet, const TextureLayout& layout ) const { int numSlots = layout.getMaxUsedSlot() + 1; int maxUnits = numSlots; if ( _useGPU ) { // Validate against the max number of GPU texture units: if ( maxUnits > Registry::instance()->getCapabilities().getMaxGPUTextureUnits() ) { maxUnits = Registry::instance()->getCapabilities().getMaxGPUTextureUnits(); OE_WARN << LC << "Warning! You have exceeded the number of texture units available on your GPU (" << maxUnits << "). Consider using another compositing mode." << std::endl; } VirtualProgram* vp = static_cast<VirtualProgram*>( stateSet->getAttribute(VirtualProgram::SA_TYPE) ); // see if we have any blended layers: bool hasBlending = layout.containsSecondarySlots( maxUnits ); // Why are these marked as PROTECTED? See the comments in MapNode.cpp for the answer. // (Where it sets up the top-level VirtualProgram) vp->setFunction( "oe_multicomp_vertex", s_createTextureVertexShader(layout, hasBlending), ShaderComp::LOCATION_VERTEX_MODEL, 0.0 ); vp->setFunction( "oe_multicomp_fragment", s_createTextureFragShaderFunction(layout, maxUnits, hasBlending, _lodTransitionTime), ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); //vp->setShader( // "osgearth_vert_setupColoring", // s_createTextureVertexShader(layout, hasBlending), // osg::StateAttribute::ON | osg::StateAttribute::PROTECTED ); //vp->setShader( // "osgearth_frag_applyColoring", // s_createTextureFragShaderFunction(layout, maxUnits, hasBlending, _lodTransitionTime), // osg::StateAttribute::ON | osg::StateAttribute::PROTECTED ); } else { // Forcably disable shaders stateSet->setAttributeAndModes( new osg::Program(), osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED ); // Validate against the maximum number of textures available in FFP mode. if ( maxUnits > Registry::instance()->getCapabilities().getMaxFFPTextureUnits() ) { maxUnits = Registry::instance()->getCapabilities().getMaxFFPTextureUnits(); OE_WARN << LC << "Warning! You have exceeded the number of texture units available in fixed-function pipeline " "mode on your graphics hardware (" << maxUnits << "). Consider using another " "compositing mode." << std::endl; } // FFP multitexturing requires that we set up a series of TexCombine attributes: if (maxUnits == 1) { osg::TexEnv* texenv = new osg::TexEnv(osg::TexEnv::MODULATE); stateSet->setTextureAttributeAndModes(0, texenv, osg::StateAttribute::ON); } else if (maxUnits >= 2) { //Blend together the colors and accumulate the alpha values of textures 0 and 1 on unit 0 { osg::TexEnvCombine* texenv = new osg::TexEnvCombine; texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); texenv->setCombine_Alpha(osg::TexEnvCombine::ADD); texenv->setSource0_RGB(osg::TexEnvCombine::TEXTURE0+1); texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource0_Alpha(osg::TexEnvCombine::TEXTURE0+1); texenv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); texenv->setSource1_RGB(osg::TexEnvCombine::TEXTURE0+0); texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource1_Alpha(osg::TexEnvCombine::TEXTURE0+0); texenv->setOperand1_Alpha(osg::TexEnvCombine::SRC_ALPHA); texenv->setSource2_RGB(osg::TexEnvCombine::TEXTURE0+1); texenv->setOperand2_RGB(osg::TexEnvCombine::SRC_ALPHA); stateSet->setTextureAttributeAndModes(0, texenv, osg::StateAttribute::ON); } //For textures 2 and beyond, blend them together with the previous //Add the alpha values of this unit and the previous unit for (int unit = 1; unit < maxUnits-1; ++unit) { osg::TexEnvCombine* texenv = new osg::TexEnvCombine; texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); texenv->setCombine_Alpha(osg::TexEnvCombine::ADD); texenv->setSource0_RGB(osg::TexEnvCombine::TEXTURE0+unit+1); texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource0_Alpha(osg::TexEnvCombine::TEXTURE0+unit+1); texenv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); texenv->setSource1_RGB(osg::TexEnvCombine::PREVIOUS); texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource1_Alpha(osg::TexEnvCombine::PREVIOUS); texenv->setOperand1_Alpha(osg::TexEnvCombine::SRC_ALPHA); texenv->setSource2_RGB(osg::TexEnvCombine::TEXTURE0+unit+1); texenv->setOperand2_RGB(osg::TexEnvCombine::SRC_ALPHA); stateSet->setTextureAttributeAndModes(unit, texenv, osg::StateAttribute::ON); } //Modulate the colors to get proper lighting on the last unit //Keep the alpha results from the previous stage { osg::TexEnvCombine* texenv = new osg::TexEnvCombine; texenv->setCombine_RGB(osg::TexEnvCombine::MODULATE); texenv->setCombine_Alpha(osg::TexEnvCombine::REPLACE); texenv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); texenv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); texenv->setSource1_RGB(osg::TexEnvCombine::PRIMARY_COLOR); texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); stateSet->setTextureAttributeAndModes(maxUnits-1, texenv, osg::StateAttribute::ON); } } } }
void DetailTexture::onInstall(TerrainEngineNode* engine) { if ( engine ) { if ( !_texture.valid() ) { _texture = new osg::Texture2DArray(); _texture->setTextureSize(1024, 1024, _textures.size()); _texture->setWrap( osg::Texture::WRAP_S, osg::Texture::REPEAT ); _texture->setWrap( osg::Texture::WRAP_T, osg::Texture::REPEAT ); _texture->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR ); _texture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); _texture->setResizeNonPowerOfTwoHint( false ); for(unsigned i=0; i<_textures.size(); ++i) { const TextureSource& ts = _textures[i]; osg::ref_ptr<osg::Image> image = URI(ts._url).getImage(_dbOptions.get()); if ( image->s() != 1024 || image->t() != 1024 ) { osg::ref_ptr<osg::Image> imageResized; ImageUtils::resizeImage( image.get(), 1024, 1024, imageResized ); _texture->setImage( i, imageResized.get() ); } else { _texture->setImage( i, image.get() ); } } } osg::StateSet* stateset = engine->getOrCreateStateSet(); if ( engine->getTextureCompositor()->reserveTextureImageUnit(_unit) ) { _samplerUniform = stateset->getOrCreateUniform( "oe_detail_tex", osg::Uniform::SAMPLER_2D_ARRAY ); _samplerUniform->set( _unit ); stateset->setTextureAttribute( _unit, _texture.get(), osg::StateAttribute::ON ); // don't use "..andModes" } if ( _maskLayer.valid() ) { int unit = *_maskLayer->shareImageUnit(); _maskUniform = stateset->getOrCreateUniform("oe_detail_mask", osg::Uniform::SAMPLER_2D); _maskUniform->set(unit); OE_NOTICE << LC << "Installed layer " << _maskLayer->getName() << " as texture mask on unit " << unit << std::endl; } else { exit(-1); } stateset->addUniform( _startLODUniform.get() ); stateset->addUniform( _intensityUniform.get() ); stateset->addUniform( _scaleUniform.get() ); stateset->addUniform( _attenuationDistanceUniform.get() ); std::string fs = generateFragmentShader( _textures.size(), _octaves.value() ); VirtualProgram* vp = VirtualProgram::getOrCreate(stateset); vp->setFunction( "oe_detail_vertex", vs, ShaderComp::LOCATION_VERTEX_VIEW ); vp->setFunction( "oe_detail_fragment", fs, ShaderComp::LOCATION_FRAGMENT_COLORING ); vp->setShader( "simplexNoise", new osg::Shader(osg::Shader::FRAGMENT, snoise) ); } }
void ClampingTechnique::setUpCamera(OverlayDecorator::TechRTTParams& params) { // To store technique-specific per-view info: LocalPerViewData* local = new LocalPerViewData(); params._techniqueData = local; // create the projected texture: local->_rttTexture = new osg::Texture2D(); local->_rttTexture->setTextureSize( *_textureSize, *_textureSize ); local->_rttTexture->setInternalFormat( GL_DEPTH_COMPONENT ); local->_rttTexture->setFilter( osg::Texture::MIN_FILTER, osg::Texture::NEAREST ); local->_rttTexture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); // this is important. geometry that is outside the depth texture will clamp to the // closest edge value in the texture -- this is good when you are rendering a // primitive that has one or more of its verts off-screen. local->_rttTexture->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE ); local->_rttTexture->setWrap( osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE ); //local->_rttTexture->setBorderColor( osg::Vec4(0,0,0,1) ); // set up the RTT camera: params._rttCamera = new osg::Camera(); params._rttCamera->setReferenceFrame( osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ); params._rttCamera->setClearDepth( 1.0 ); params._rttCamera->setClearMask( GL_DEPTH_BUFFER_BIT ); params._rttCamera->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR ); params._rttCamera->setViewport( 0, 0, *_textureSize, *_textureSize ); params._rttCamera->setRenderOrder( osg::Camera::PRE_RENDER ); params._rttCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT ); params._rttCamera->setImplicitBufferAttachmentMask(0, 0); params._rttCamera->attach( osg::Camera::DEPTH_BUFFER, local->_rttTexture.get() ); #ifdef DUMP_RTT_IMAGE local->_rttDebugImage = new osg::Image(); local->_rttDebugImage->allocateImage(4096, 4096, 1, GL_RGB, GL_UNSIGNED_BYTE); memset( (void*)local->_rttDebugImage->getDataPointer(), 0xff, local->_rttDebugImage->getTotalSizeInBytes() ); params._rttCamera->attach( osg::Camera::COLOR_BUFFER, local->_rttDebugImage.get() ); params._rttCamera->setFinalDrawCallback( new DumpTex(local->_rttDebugImage.get()) ); #endif #ifdef TIME_RTT_CAMERA params._rttCamera->setInitialDrawCallback( new RttIn() ); params._rttCamera->setFinalDrawCallback( new RttOut() ); #endif // set up a StateSet for the RTT camera. osg::StateSet* rttStateSet = params._rttCamera->getOrCreateStateSet(); rttStateSet->setMode( GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); // prevents wireframe mode in the depth camera. rttStateSet->setAttributeAndModes( new osg::PolygonMode( osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL ), osg::StateAttribute::ON | osg::StateAttribute::PROTECTED ); // attach the terrain to the camera. // todo: should probably protect this with a mutex..... params._rttCamera->addChild( _engine ); // the terrain itself. // assemble the overlay graph stateset. local->_groupStateSet = new osg::StateSet(); // Required for now, otherwise GPU-clamped geometry will jitter sometimes. // TODO: figure out why and fix it. This is a workaround for now. local->_groupStateSet->setDataVariance( osg::Object::DYNAMIC ); local->_groupStateSet->setTextureAttributeAndModes( _textureUnit, local->_rttTexture.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); // set up depth test/write parameters for the overlay geometry: local->_groupStateSet->setAttributeAndModes( new osg::Depth( osg::Depth::LEQUAL, 0.0, 1.0, true ), osg::StateAttribute::ON ); local->_groupStateSet->setRenderingHint( osg::StateSet::TRANSPARENT_BIN ); // uniform for the horizon distance (== max clamping distance) local->_horizonDistanceUniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_horizonDistance", osg::Uniform::FLOAT ); // sampler for depth map texture: local->_groupStateSet->getOrCreateUniform( "oe_clamp_depthTex", osg::Uniform::SAMPLER_2D )->set( _textureUnit ); // matrix that transforms a vert from EYE coords to the depth camera's CLIP coord. local->_camViewToDepthClipUniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_cameraView2depthClip", osg::Uniform::FLOAT_MAT4 ); #ifdef SUPPORT_Z // matrix that transforms a vert from depth clip coords to depth view coords. local->_depthClipToDepthViewUniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_depthClip2depthView", osg::Uniform::FLOAT_MAT4 ); // matrix that transforms a vert from depth view coords to camera view coords. local->_depthViewToCamViewUniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_depthView2cameraView", osg::Uniform::FLOAT_MAT4 ); #else // matrix that transforms a vert from depth-cam CLIP coords to EYE coords. local->_depthClipToCamViewUniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_depthClip2cameraView", osg::Uniform::FLOAT_MAT4 ); #endif // make the shader that will do clamping and depth offsetting. VirtualProgram* vp = VirtualProgram::getOrCreate(local->_groupStateSet.get()); vp->setName( "ClampingTechnique" ); vp->setFunction( "oe_clamp_vertex", clampingVertexShader, ShaderComp::LOCATION_VERTEX_VIEW ); vp->setFunction( "oe_clamp_fragment", clampingFragmentShader, ShaderComp::LOCATION_FRAGMENT_COLORING ); }
void makeVisibleVP(osg::StateSet* ss) { VirtualProgram* vp = VirtualProgram::getOrCreate(ss); vp->setFunction("oe_instancing_setPos", IG_VS, ShaderComp::LOCATION_VERTEX_MODEL, -FLT_MAX); vp->addBindAttribLocation( "xfb_position", XFB_SLOT ); }
// Generates the main shader code for rendering the terrain. void RexTerrainEngineNode::updateState() { if ( _batchUpdateInProgress ) { _stateUpdateRequired = true; } else { osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); // everything osg::StateSet* surfaceStateSet = getSurfaceStateSet(); // just the surface // required for multipass tile rendering to work surfaceStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); // install patch param if we are tessellation on the GPU. if ( _terrainOptions.gpuTessellation() == true ) { #ifdef HAVE_PATCH_PARAMETER terrainStateSet->setAttributeAndModes( new osg::PatchParameter(3) ); #endif } // install shaders, if we're using them. if ( Registry::capabilities().supportsGLSL() ) { Shaders package; VirtualProgram* terrainVP = VirtualProgram::getOrCreate(terrainStateSet); terrainVP->setName( "Rex Terrain" ); package.load(terrainVP, package.ENGINE_VERT_MODEL); //moved to CTOR so it's always available //package.load(terrainVP, package.SDK); bool useTerrainColor = _terrainOptions.color().isSet(); package.define("OE_REX_USE_TERRAIN_COLOR", useTerrainColor); if ( useTerrainColor ) { surfaceStateSet->addUniform(new osg::Uniform("oe_terrain_color", _terrainOptions.color().get())); } bool useBlending = _terrainOptions.enableBlending().get(); package.define("OE_REX_GL_BLENDING", useBlending); bool morphImagery = _terrainOptions.morphImagery().get(); package.define("OE_REX_MORPH_IMAGERY", morphImagery); // Funtions that affect only the terrain surface: VirtualProgram* surfaceVP = VirtualProgram::getOrCreate(surfaceStateSet); surfaceVP->setName("Rex Surface"); // Functions that affect the terrain surface only: package.load(surfaceVP, package.ENGINE_VERT_VIEW); package.load(surfaceVP, package.ENGINE_FRAG); // Normal mapping shaders: if ( this->normalTexturesRequired() ) { package.load(surfaceVP, package.NORMAL_MAP_VERT); package.load(surfaceVP, package.NORMAL_MAP_FRAG); } // Morphing? if (_terrainOptions.morphTerrain() == true || _terrainOptions.morphImagery() == true) { package.define("OE_REX_VERTEX_MORPHING", (_terrainOptions.morphTerrain() == true)); package.load(surfaceVP, package.MORPHING_VERT); } for(LandCoverZones::iterator zone = _landCoverData._zones.begin(); zone != _landCoverData._zones.end(); ++zone) { for(LandCoverBins::iterator bin = zone->_bins.begin(); bin != zone->_bins.end(); ++bin) { osg::StateSet* landCoverStateSet = bin->_binProto->getStateSet(); // enable alpha-to-coverage multisampling for vegetation. landCoverStateSet->setMode(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, 1); // uniform that communicates the availability of multisampling. landCoverStateSet->addUniform( new osg::Uniform( "oe_terrain_hasMultiSamples", osg::DisplaySettings::instance()->getMultiSamples()) ); landCoverStateSet->setAttributeAndModes( new osg::BlendFunc(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO), osg::StateAttribute::OVERRIDE ); #ifdef HAVE_OSG_PATCH_PARAMETER landCoverStateSet->setAttributeAndModes( new osg::PatchParameter(3) ); #endif } } // assemble color filter code snippets. bool haveColorFilters = false; { // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "$COLOR_FILTER_HEAD" "void oe_rexEngine_applyFilters(inout vec4 color) \n" "{ \n" "$COLOR_FILTER_BODY" "} \n"; std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; int numImageLayers = _update_mapf->imageLayers().size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = _update_mapf->getImageLayerAt(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( surfaceStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "$COLOR_FILTER_HEAD", cf_head_str ); replaceIn( fs_colorfilters, "$COLOR_FILTER_BODY", cf_body_str ); surfaceVP->setFunction( "oe_rexEngine_applyFilters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); } } // Apply uniforms for sampler bindings: OE_DEBUG << LC << "Render Bindings:\n"; for(RenderBindings::const_iterator b = _renderBindings.begin(); b != _renderBindings.end(); ++b) { if ( b->isActive() ) { terrainStateSet->addUniform( new osg::Uniform(b->samplerName().c_str(), b->unit()) ); OE_DEBUG << LC << " > Bound \"" << b->samplerName() << "\" to unit " << b->unit() << "\n"; } } // uniform that controls per-layer opacity terrainStateSet->addUniform( new osg::Uniform("oe_layer_opacity", 1.0f) ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->addUniform( new osg::Uniform("oe_layer_uid", (int)-1 ) ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->addUniform( new osg::Uniform("oe_layer_order", (int)0) ); // default min/max range uniforms. (max < min means ranges are disabled) terrainStateSet->addUniform( new osg::Uniform("oe_layer_minRange", 0.0f) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_maxRange", -1.0f) ); terrainStateSet->getOrCreateUniform( "oe_min_tile_range_factor", osg::Uniform::FLOAT)->set( *_terrainOptions.minTileRangeFactor() ); terrainStateSet->addUniform(new osg::Uniform("oe_tile_size", (float)_terrainOptions.tileSize().get())); // special object ID that denotes the terrain surface. surfaceStateSet->addUniform( new osg::Uniform( Registry::objectIndex()->getObjectIDUniformName().c_str(), OSGEARTH_OBJECTID_TERRAIN) ); } _stateUpdateRequired = false; } }
osg::Node* PolygonizeLinesFilter::push(FeatureList& input, FilterContext& cx) { // compute the coordinate localization matrices. computeLocalizers( cx ); // establish some things bool makeECEF = false; const SpatialReference* featureSRS = 0L; const SpatialReference* mapSRS = 0L; if ( cx.isGeoreferenced() ) { makeECEF = cx.getSession()->getMapInfo().isGeocentric(); featureSRS = cx.extent()->getSRS(); mapSRS = cx.getSession()->getMapInfo().getProfile()->getSRS(); } // The operator we'll use to make lines into polygons. const LineSymbol* line = _style.get<LineSymbol>(); PolygonizeLinesOperator polygonize( line ? (*line->stroke()) : Stroke() ); // Geode to hold all the geometries. osg::Geode* geode = new osg::Geode(); // iterate over all features. for( FeatureList::iterator i = input.begin(); i != input.end(); ++i ) { Feature* f = i->get(); // iterate over all the feature's geometry parts. We will treat // them as lines strings. GeometryIterator parts( f->getGeometry(), false ); while( parts.hasMore() ) { Geometry* part = parts.next(); // skip empty geometry if ( part->size() == 0 ) continue; // transform the geometry into the target SRS and localize it about // a local reference point. osg::Vec3Array* verts = new osg::Vec3Array(); osg::Vec3Array* normals = new osg::Vec3Array(); transformAndLocalize( part->asVector(), featureSRS, verts, normals, mapSRS, _world2local, makeECEF ); // turn the lines into polygons. osg::Geometry* geom = polygonize( verts, normals ); geode->addDrawable( geom ); // record the geometry's primitive set(s) in the index: if ( cx.featureIndex() ) cx.featureIndex()->tagPrimitiveSets( geom, f ); } } // attempt to combine geometries for better performance MeshConsolidator::run( *geode ); // GPU performance optimization: VertexCacheOptimizer vco; geode->accept( vco ); // If we're auto-scaling, we need a shader float minPixels = line ? line->stroke()->minPixels().getOrUse( 0.0f ) : 0.0f; if ( minPixels > 0.0f ) { osg::StateSet* stateSet = geode->getOrCreateStateSet(); VirtualProgram* vp = VirtualProgram::getOrCreate(stateSet); vp->setName( "osgEarth::PolygonizeLines" ); const char* vs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "attribute vec3 oe_polyline_center; \n" "uniform float oe_polyline_scale; \n" "uniform float oe_polyline_min_pixels; \n" "uniform mat3 oe_WindowScaleMatrix; \n" "void oe_polyline_scalelines(inout vec4 VertexMODEL) \n" "{ \n" " if ( oe_polyline_scale != 1.0 || oe_polyline_min_pixels > 0.0 ) \n" " { \n" " vec4 center_model = vec4(oe_polyline_center*VertexMODEL.w, VertexMODEL.w); \n" " vec4 vector_model = VertexMODEL - center_model; \n" " if ( length(vector_model.xyz) > 0.0 ) \n" " { \n" " float scale = oe_polyline_scale; \n" " vec4 vertex_clip = gl_ModelViewProjectionMatrix * VertexMODEL; \n" " vec4 center_clip = gl_ModelViewProjectionMatrix * center_model; \n" " vec4 vector_clip = vertex_clip - center_clip; \n" " if ( oe_polyline_min_pixels > 0.0 ) \n" " { \n" " vec3 vector_win = oe_WindowScaleMatrix * (vertex_clip.xyz/vertex_clip.w - center_clip.xyz/center_clip.w); \n" " float min_scale = max( (0.5*oe_polyline_min_pixels)/length(vector_win.xy), 1.0 ); \n" " scale = max( scale, min_scale ); \n" " } \n" " VertexMODEL = center_model + vector_model*scale; \n" " } \n" " } \n" "} \n"; vp->setFunction( "oe_polyline_scalelines", vs, ShaderComp::LOCATION_VERTEX_MODEL ); vp->addBindAttribLocation( "oe_polyline_center", osg::Drawable::ATTRIBUTE_6 ); // add the default scaling uniform. // good way to test: // osgearth_viewer earthfile --uniform oe_polyline_scale 1.0 10.0 osg::Uniform* scaleU = new osg::Uniform(osg::Uniform::FLOAT, "oe_polyline_scale"); scaleU->set( 1.0f ); stateSet->addUniform( scaleU, 1 ); // the default "min pixels" uniform. osg::Uniform* minPixelsU = new osg::Uniform(osg::Uniform::FLOAT, "oe_polyline_min_pixels"); minPixelsU->set( minPixels ); stateSet->addUniform( minPixelsU, 1 ); } return delocalize( geode ); }
// Generates the main shader code for rendering the terrain. void RexTerrainEngineNode::updateState() { if ( _batchUpdateInProgress ) { _stateUpdateRequired = true; } else { osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); // everything osg::StateSet* surfaceStateSet = getSurfaceStateSet(); // just the surface //terrainStateSet->setRenderBinDetails(0, "SORT_FRONT_TO_BACK"); // required for multipass tile rendering to work surfaceStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); surfaceStateSet->setAttributeAndModes( new osg::CullFace(), osg::StateAttribute::ON); // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); // install patch param if we are tessellation on the GPU. if ( _terrainOptions.gpuTessellation() == true ) { #ifdef HAVE_PATCH_PARAMETER terrainStateSet->setAttributeAndModes( new osg::PatchParameter(3) ); #endif } // install shaders, if we're using them. if ( Registry::capabilities().supportsGLSL() ) { Shaders package; VirtualProgram* terrainVP = VirtualProgram::getOrCreate(terrainStateSet); terrainVP->setName( "Rex Terrain" ); package.load(terrainVP, package.ENGINE_VERT_MODEL); surfaceStateSet->addUniform(new osg::Uniform("oe_terrain_color", _terrainOptions.color().get())); if (_terrainOptions.enableBlending() == true) { surfaceStateSet->setDefine("OE_TERRAIN_BLEND_IMAGERY"); } // Funtions that affect only the terrain surface: VirtualProgram* surfaceVP = VirtualProgram::getOrCreate(surfaceStateSet); surfaceVP->setName("Rex Surface"); // Functions that affect the terrain surface only: package.load(surfaceVP, package.ENGINE_VERT_VIEW); package.load(surfaceVP, package.ENGINE_FRAG); // Elevation? if (this->elevationTexturesRequired()) { surfaceStateSet->setDefine("OE_TERRAIN_RENDER_ELEVATION"); } // Normal mapping shaders: if ( this->normalTexturesRequired() ) { package.load(surfaceVP, package.NORMAL_MAP_VERT); package.load(surfaceVP, package.NORMAL_MAP_FRAG); surfaceStateSet->setDefine("OE_TERRAIN_RENDER_NORMAL_MAP"); } // Morphing? if (_terrainOptions.morphTerrain() == true || _terrainOptions.morphImagery() == true) { package.load(surfaceVP, package.MORPHING_VERT); if (_terrainOptions.morphImagery() == true) { surfaceStateSet->setDefine("OE_TERRAIN_MORPH_IMAGERY"); } if (_terrainOptions.morphTerrain() == true) { surfaceStateSet->setDefine("OE_TERRAIN_MORPH_GEOMETRY"); } } // assemble color filter code snippets. bool haveColorFilters = false; { // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "$COLOR_FILTER_HEAD" "void oe_rexEngine_applyFilters(inout vec4 color) \n" "{ \n" "$COLOR_FILTER_BODY" "} \n"; std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; ImageLayerVector imageLayers; _update_mapf->getLayers(imageLayers); for( int i=0; i<imageLayers.size(); ++i ) { ImageLayer* layer = imageLayers.at(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( surfaceStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "$COLOR_FILTER_HEAD", cf_head_str ); replaceIn( fs_colorfilters, "$COLOR_FILTER_BODY", cf_body_str ); surfaceVP->setFunction( "oe_rexEngine_applyFilters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.6 ); } } // Apply uniforms for sampler bindings: OE_DEBUG << LC << "Render Bindings:\n"; osg::ref_ptr<osg::Texture> tex = new osg::Texture2D(ImageUtils::createEmptyImage(1,1)); for (unsigned i = 0; i < _renderBindings.size(); ++i) { SamplerBinding& b = _renderBindings[i]; if (b.isActive()) { osg::Uniform* u = new osg::Uniform(b.samplerName().c_str(), b.unit()); terrainStateSet->addUniform( u ); OE_DEBUG << LC << " > Bound \"" << b.samplerName() << "\" to unit " << b.unit() << "\n"; terrainStateSet->setTextureAttribute(b.unit(), tex.get()); } } // uniform that controls per-layer opacity terrainStateSet->addUniform( new osg::Uniform("oe_layer_opacity", 1.0f) ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->addUniform( new osg::Uniform("oe_layer_uid", (int)-1 ) ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->addUniform( new osg::Uniform("oe_layer_order", (int)0) ); // default min/max range uniforms. (max < min means ranges are disabled) terrainStateSet->addUniform( new osg::Uniform("oe_layer_minRange", 0.0f) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_maxRange", -1.0f) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_attenuationRange", _terrainOptions.attentuationDistance().get()) ); terrainStateSet->getOrCreateUniform( "oe_min_tile_range_factor", osg::Uniform::FLOAT)->set( *_terrainOptions.minTileRangeFactor() ); terrainStateSet->addUniform(new osg::Uniform("oe_tile_size", (float)_terrainOptions.tileSize().get())); // special object ID that denotes the terrain surface. surfaceStateSet->addUniform( new osg::Uniform( Registry::objectIndex()->getObjectIDUniformName().c_str(), OSGEARTH_OBJECTID_TERRAIN) ); } _stateUpdateRequired = false; } }
bool ShaderGenerator::processGeometry( osg::StateSet* ss, osg::ref_ptr<osg::StateSet>& replacement ) { // do nothing if there's no GLSL support if ( !Registry::capabilities().supportsGLSL() ) return false; // State object with extra accessors: StateEx* state = static_cast<StateEx*>(_state.get()); // check for a real osg::Program in the whole state stack. If it exists, bail out // so that OSG can use the program already in the graph. We never override a // full Program. osg::StateAttribute* program = state->getAttribute(osg::StateAttribute::PROGRAM); if ( dynamic_cast<osg::Program*>(program) != 0L ) return false; // see if the current state set contains a VirtualProgram already. If so, // we will add to it if necessary. VirtualProgram* vp = dynamic_cast<VirtualProgram*>( ss->getAttribute(VirtualProgram::SA_TYPE) ); // Check whether the lighting state has changed and install a mode uniform. if ( ss->getMode(GL_LIGHTING) != osg::StateAttribute::INHERIT ) { if ( !replacement.valid() ) replacement = osg::clone(ss, osg::CopyOp::DEEP_COPY_ALL); ShaderFactory* sf = Registry::instance()->getShaderFactory(); osg::StateAttribute::GLModeValue value = state->getMode(GL_LIGHTING); // from the state, not the ss. replacement->addUniform( sf->createUniformForGLMode(GL_LIGHTING, value) ); } // if the stateset changes any texture attributes, we need a new virtual program: if (ss->getTextureAttributeList().size() > 0) { if ( !replacement.valid() ) replacement = osg::clone(ss, osg::CopyOp::DEEP_COPY_ALL); // work off the state's accumulated texture attribute set: int texCount = state->getNumTextureAttributes(); if ( !vp ) { vp = osg::clone( _defaultVP.get() ); replacement->setAttributeAndModes( vp, osg::StateAttribute::ON ); } // start generating the shader source. std::stringstream vertHead, vertBody, fragHead, fragBody; // compatibility strings make it work in GL or GLES. vertHead << "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION; fragHead << "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION; // function declarations: vertBody << "void " VERTEX_FUNCTION "()\n{\n"; fragBody << "void " FRAGMENT_FUNCTION "(inout vec4 color)\n{\n"; for( int t = 0; t < texCount; ++t ) { if (t == 0) { fragBody << INDENT << MEDIUMP "vec4 texel; \n"; } osg::StateAttribute* tex = state->getTextureAttribute( t, osg::StateAttribute::TEXTURE ); if ( tex ) { // see if we have a texenv; if so get its blending mode. osg::TexEnv::Mode blendingMode = osg::TexEnv::MODULATE; osg::TexEnv* env = dynamic_cast<osg::TexEnv*>(state->getTextureAttribute(t, osg::StateAttribute::TEXENV) ); if ( env ) { blendingMode = env->getMode(); if ( blendingMode == osg::TexEnv::BLEND ) { replacement->getOrCreateUniform( Stringify() << TEXENV_COLOR << t, osg::Uniform::FLOAT_VEC4 )->set( env->getColor() ); } } vertHead << "varying " MEDIUMP "vec4 " TEX_COORD << t << ";\n"; vertBody << INDENT << TEX_COORD << t << " = gl_MultiTexCoord" << t << ";\n"; fragHead << "varying " MEDIUMP "vec4 " TEX_COORD << t << ";\n"; if ( dynamic_cast<osg::Texture1D*>(tex) ) { fragHead << "uniform sampler1D " SAMPLER << t << ";\n"; fragBody << INDENT "texel = texture1D(" SAMPLER << t << ", " TEX_COORD << t << ".x);\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_1D )->set( t ); } else if ( dynamic_cast<osg::Texture2D*>(tex) ) { fragHead << "uniform sampler2D " SAMPLER << t << ";\n"; fragBody << INDENT "texel = texture2D(" SAMPLER << t << ", " TEX_COORD << t << ".xy);\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_2D )->set( t ); } else if ( dynamic_cast<osg::Texture3D*>(tex) ) { fragHead << "uniform sampler3D " SAMPLER << t << ";\n"; fragBody << INDENT "texel = texture3D(" SAMPLER << t << ", " TEX_COORD << t << ".xyz);\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_3D )->set( t ); } // See http://www.opengl.org/sdk/docs/man/xhtml/glTexEnv.xml switch( blendingMode ) { case osg::TexEnv::REPLACE: fragBody << INDENT "color = texel; \n"; break; case osg::TexEnv::MODULATE: fragBody << INDENT "color = color * texel; \n"; break; case osg::TexEnv::DECAL: fragBody << INDENT "color.rgb = color.rgb * (1.0 - texel.a) + (texel.rgb * texel.a); \n"; break; case osg::TexEnv::BLEND: fragHead << "uniform " MEDIUMP "vec4 " TEXENV_COLOR << t << "\n;"; fragBody << INDENT "color.rgb = color.rgb * (1.0 - texel.rgb) + (" << TEXENV_COLOR << t << ".rgb * texel.rgb); \n" << INDENT "color.a = color.a * texel.a; \n"; break; case osg::TexEnv::ADD: default: fragBody << INDENT "color.rgb = color.rgb + texel.rgb; \n" << INDENT "color.a = color.a * texel.a; \n"; } } } // close out functions: vertBody << "}\n"; fragBody << "}\n"; // Extract the shader source strings (win compat method) std::string vertBodySrc, vertSrc, fragBodySrc, fragSrc; vertBodySrc = vertBody.str(); vertHead << vertBodySrc; vertSrc = vertHead.str(); fragBodySrc = fragBody.str(); fragHead << fragBodySrc; fragSrc = fragHead.str(); // inject the shaders: vp->setFunction( VERTEX_FUNCTION, vertSrc, ShaderComp::LOCATION_VERTEX_PRE_LIGHTING ); vp->setFunction( FRAGMENT_FUNCTION, fragSrc, ShaderComp::LOCATION_FRAGMENT_PRE_LIGHTING ); } return replacement.valid(); }
// Generates the main shader code for rendering the terrain. void MPTerrainEngineNode::updateState() { if ( _batchUpdateInProgress ) { _stateUpdateRequired = true; } else { if ( _elevationTextureUnit < 0 && elevationTexturesRequired() ) { getResources()->reserveTextureImageUnit( _elevationTextureUnit, "MP Engine Elevation" ); } osg::StateSet* terrainStateSet = getTerrainStateSet(); // required for multipass tile rendering to work terrainStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); // install shaders, if we're using them. if ( Registry::capabilities().supportsGLSL() ) { VirtualProgram* vp = new VirtualProgram(); vp->setName( "osgEarth.engine_mp.TerrainNode" ); terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // bind the vertex attributes generated by the tile compiler. vp->addBindAttribLocation( "oe_terrain_attr", osg::Drawable::ATTRIBUTE_6 ); vp->addBindAttribLocation( "oe_terrain_attr2", osg::Drawable::ATTRIBUTE_7 ); Shaders package; package.replace( "$MP_PRIMARY_UNIT", Stringify() << _primaryUnit ); package.replace( "$MP_SECONDARY_UNIT", Stringify() << (_secondaryUnit>=0?_secondaryUnit:0) ); package.define( "MP_USE_BLENDING", (_terrainOptions.enableBlending() == true) ); package.loadFunction( vp, package.VertexModel ); package.loadFunction( vp, package.VertexView ); package.loadFunction( vp, package.Fragment ); // terrain background color; negative means use the vertex color. Color terrainColor = _terrainOptions.color().getOrUse( Color(1,1,1,-1) ); terrainStateSet->addUniform(new osg::Uniform("oe_terrain_color", terrainColor)); // assemble color filter code snippets. bool haveColorFilters = false; { // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "$COLOR_FILTER_HEAD" "void oe_mp_apply_filters(inout vec4 color) \n" "{ \n" "$COLOR_FILTER_BODY" "} \n"; std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; int numImageLayers = _update_mapf->imageLayers().size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = _update_mapf->getImageLayerAt(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( terrainStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "$COLOR_FILTER_HEAD", cf_head_str ); replaceIn( fs_colorfilters, "$COLOR_FILTER_BODY", cf_body_str ); vp->setFunction( "oe_mp_apply_filters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.5f ); } } // binding for the terrain texture terrainStateSet->getOrCreateUniform( "oe_layer_tex", osg::Uniform::SAMPLER_2D )->set( _primaryUnit ); // binding for the secondary texture (for LOD blending) if ( parentTexturesRequired() ) { terrainStateSet->getOrCreateUniform( "oe_layer_tex_parent", osg::Uniform::SAMPLER_2D )->set( _secondaryUnit ); // binding for the default secondary texture matrix osg::Matrixf parent_mat; parent_mat(0,0) = 0.0f; terrainStateSet->getOrCreateUniform( "oe_layer_parent_matrix", osg::Uniform::FLOAT_MAT4 )->set( parent_mat ); } // uniform for accessing the elevation texture sampler. if ( elevationTexturesRequired() ) { terrainStateSet->getOrCreateUniform( "oe_terrain_tex", osg::Uniform::SAMPLER_2D)->set( _elevationTextureUnit ); } // uniform that controls per-layer opacity terrainStateSet->getOrCreateUniform( "oe_layer_opacity", osg::Uniform::FLOAT )->set( 1.0f ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->getOrCreateUniform( "oe_layer_uid", osg::Uniform::INT )->set( -1 ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->getOrCreateUniform( "oe_layer_order", osg::Uniform::INT )->set( 0 ); // default min/max range uniforms. (max < min means ranges are disabled) terrainStateSet->addUniform( new osg::Uniform("oe_layer_minRange", 0.0f) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_maxRange", -1.0f) ); terrainStateSet->getOrCreateUniform( "oe_min_tile_range_factor", osg::Uniform::FLOAT)->set( *_terrainOptions.minTileRangeFactor() ); // special object ID that denotes the terrain surface. terrainStateSet->addUniform( new osg::Uniform( Registry::objectIndex()->getObjectIDUniformName().c_str(), OSGEARTH_OBJECTID_TERRAIN) ); } _stateUpdateRequired = false; } }
osg::Node* createFramebufferPass(App& app) { osg::Node* quad = createFramebufferQuad(app); osg::StateSet* stateset = quad->getOrCreateStateSet(); static const char* vertSource = "varying vec4 texcoord;\n" "void effect_vert(inout vec4 vertexView)\n" "{\n" " texcoord = gl_MultiTexCoord0; \n" "}\n"; static const char* fragSource = "#version 120\n" "#extension GL_ARB_texture_rectangle : enable\n" "uniform sampler2DRect gcolor;\n" "uniform sampler2DRect gnormal;\n" "uniform sampler2DRect gdepth;\n" "varying vec4 texcoord;\n" "void effect_frag(inout vec4 color)\n" "{\n" " color = texture2DRect(gcolor, texcoord.st); \n" " float depth = texture2DRect(gdepth, texcoord.st).r; \n" " vec3 normal = texture2DRect(gnormal,texcoord.st).xyz *2.0-1.0; \n" // sample radius in pixels: " float e = 5.0; \n" // sample the normals around our pixel and find the approximate // deviation from our center normal: " vec3 avgNormal =\n" " texture2DRect(gnormal, texcoord.st+vec2( e, e)).xyz + \n" " texture2DRect(gnormal, texcoord.st+vec2(-e, e)).xyz + \n" " texture2DRect(gnormal, texcoord.st+vec2(-e,-e)).xyz + \n" " texture2DRect(gnormal, texcoord.st+vec2( e,-e)).xyz + \n" " texture2DRect(gnormal, texcoord.st+vec2( 0, e)).xyz + \n" " texture2DRect(gnormal, texcoord.st+vec2( e, 0)).xyz + \n" " texture2DRect(gnormal, texcoord.st+vec2( 0,-e)).xyz + \n" " texture2DRect(gnormal, texcoord.st+vec2(-e, 0)).xyz; \n" " avgNormal = normalize((avgNormal/8.0)*2.0-1.0); \n" " float deviation = clamp(dot(normal, avgNormal),0.0,1.0); \n" // set a blur factor based on the normal deviation, so that we // blur more around edges. " e = 2.5 * (1.0-deviation); \n" " vec4 blurColor = \n" " color + \n" " texture2DRect(gcolor, texcoord.st+vec2( e, e)) + \n" " texture2DRect(gcolor, texcoord.st+vec2(-e, e)) + \n" " texture2DRect(gcolor, texcoord.st+vec2(-e,-e)) + \n" " texture2DRect(gcolor, texcoord.st+vec2( e,-e)) + \n" " texture2DRect(gcolor, texcoord.st+vec2( 0, e)) + \n" " texture2DRect(gcolor, texcoord.st+vec2( e, 0)) + \n" " texture2DRect(gcolor, texcoord.st+vec2( 0,-e)) + \n" " texture2DRect(gcolor, texcoord.st+vec2(-e, 0)); \n" " blurColor /= 9.0; \n" // blur the color and darken the edges at the same time " color.rgb = blurColor.rgb * deviation; \n" "}\n"; VirtualProgram* vp = VirtualProgram::getOrCreate(stateset); vp->setFunction("effect_vert", vertSource, ShaderComp::LOCATION_VERTEX_VIEW); vp->setFunction("effect_frag", fragSource, ShaderComp::LOCATION_FRAGMENT_COLORING); stateset->setTextureAttributeAndModes(0, app.gcolor, 1); stateset->addUniform(new osg::Uniform("gcolor", 0)); stateset->setTextureAttributeAndModes(1, app.gnormal, 1); stateset->addUniform(new osg::Uniform("gnormal", 1)); stateset->setTextureAttributeAndModes(2, app.gdepth, 1); stateset->addUniform(new osg::Uniform("gdepth", 2)); stateset->setMode( GL_LIGHTING, 0 ); float w = app.gcolor->getTextureWidth(); float h = app.gcolor->getTextureHeight(); osg::Camera* camera = new osg::Camera(); camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF ); camera->setViewMatrix( osg::Matrix::identity() ); camera->setProjectionMatrixAsOrtho2D( -w/2, (-w/2)+w, -h/2, (-h/2)+h ); camera->addChild( quad ); return camera; }