bool ShaderGenerator::processText(const osg::StateSet* ss, osg::ref_ptr<osg::StateSet>& replacement) { // do nothing if there's no GLSL support if ( !_active ) return false; // State object with extra accessors: StateEx* state = static_cast<StateEx*>(_state.get()); // check for a real osg::Program. If it exists, bail out so that OSG // can use the program already in the graph osg::StateAttribute* program = state->getAttribute(osg::StateAttribute::PROGRAM); if ( dynamic_cast<osg::Program*>(program) != 0L ) return false; // new state set: replacement = ss ? osg::clone(ss, osg::CopyOp::SHALLOW_COPY) : new osg::StateSet(); // new VP: VirtualProgram* vp = 0L; if ( VirtualProgram::get(replacement.get()) ) vp = osg::clone(VirtualProgram::get(replacement.get()), osg::CopyOp::DEEP_COPY_ALL); else vp = VirtualProgram::getOrCreate(replacement.get()); if ( vp->referenceCount() == 1 ) vp->setName( _name ); std::string vertSrc = "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION "\n" "varying " MEDIUMP "vec4 " TEX_COORD_TEXT ";\n" "void " VERTEX_FUNCTION "(inout vec4 vertexVIEW)\n" "{ \n" INDENT TEX_COORD_TEXT " = gl_MultiTexCoord0;\n" "} \n"; std::string fragSrc = "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION "\n" "uniform sampler2D " SAMPLER_TEXT ";\n" "varying " MEDIUMP "vec4 " TEX_COORD_TEXT ";\n" "void " FRAGMENT_FUNCTION "(inout vec4 color)\n" "{ \n" INDENT MEDIUMP "vec4 texel = texture2D(" SAMPLER_TEXT ", " TEX_COORD_TEXT ".xy);\n" INDENT "color.a *= texel.a; \n" "}\n"; vp->setFunction( VERTEX_FUNCTION, vertSrc, ShaderComp::LOCATION_VERTEX_VIEW ); vp->setFunction( FRAGMENT_FUNCTION, fragSrc, ShaderComp::LOCATION_FRAGMENT_COLORING ); replacement->getOrCreateUniform( SAMPLER_TEXT, osg::Uniform::SAMPLER_2D )->set( 0 ); return replacement.valid(); }
void ShaderGenVisitor::update(osg::Drawable *drawable) { // update only geometry due to compatibility issues with user defined drawables osg::Geometry *geometry = drawable->asGeometry(); #if 0 if (!geometry) return; #endif StateEx *state = static_cast<StateEx *>(_state.get()); // skip nodes without state sets if (state->getStateSetStackSize() == (_rootStateSet.valid() ? 1u : 0u)) return; // skip state sets with already attached programs if (state->getAttribute(osg::StateAttribute::PROGRAM)) return; int stateMask = 0; //if (state->getMode(GL_BLEND) & osg::StateAttribute::ON) // stateMask |= ShaderGen::BLEND; if (state->getMode(GL_LIGHTING) & osg::StateAttribute::ON) stateMask |= ShaderGenCache::LIGHTING; if (state->getMode(GL_FOG) & osg::StateAttribute::ON) stateMask |= ShaderGenCache::FOG; if (state->getTextureAttribute(0, osg::StateAttribute::TEXTURE)) stateMask |= ShaderGenCache::DIFFUSE_MAP; if (state->getTextureAttribute(1, osg::StateAttribute::TEXTURE) && geometry!=0 && geometry->getVertexAttribArray(6)) //tangent stateMask |= ShaderGenCache::NORMAL_MAP; // Get program and uniforms for accumulated state. osg::StateSet *progss = _stateCache->getOrCreateStateSet(stateMask); // Set program and uniforms to the last state set. osg::StateSet *ss = const_cast<osg::StateSet *>(state->getStateSetStack().back()); ss->setAttribute(progss->getAttribute(osg::StateAttribute::PROGRAM)); ss->setUniformList(progss->getUniformList()); // remove any modes that won't be appropriate when using shaders if ((stateMask&ShaderGenCache::LIGHTING)!=0) { ss->removeMode(GL_LIGHTING); ss->removeMode(GL_LIGHT0); } if ((stateMask&ShaderGenCache::FOG)!=0) { ss->removeMode(GL_FOG); } if ((stateMask&ShaderGenCache::DIFFUSE_MAP)!=0) ss->removeTextureMode(0, GL_TEXTURE_2D); if ((stateMask&ShaderGenCache::NORMAL_MAP)!=0) ss->removeTextureMode(1, GL_TEXTURE_2D); }
bool ShaderGenerator::processText( 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. If it exists, bail out so that OSG // can use the program already in the graph 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) ); replacement = osg::clone(ss, osg::CopyOp::SHALLOW_COPY); //replacement = osg::clone(ss, osg::CopyOp::DEEP_COPY_ALL); std::string vertSrc = "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION "\n" "varying " MEDIUMP "vec4 " TEX_COORD_TEXT ";\n" "void " VERTEX_FUNCTION "(inout vec4 vertex_view)\n" "{ \n" INDENT TEX_COORD_TEXT " = gl_MultiTexCoord0;\n" "} \n"; std::string fragSrc = "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION "\n" "uniform sampler2D " SAMPLER_TEXT ";\n" "varying " MEDIUMP "vec4 " TEX_COORD_TEXT ";\n" "void " FRAGMENT_FUNCTION "(inout vec4 color)\n" "{ \n" INDENT MEDIUMP "vec4 texel = texture2D(" SAMPLER_TEXT ", " TEX_COORD_TEXT ".xy);\n" INDENT "color.a *= texel.a; \n" "}\n"; if ( !vp ) vp = osg::clone( _defaultVP.get() ); replacement->setAttributeAndModes( vp, osg::StateAttribute::ON ); vp->setFunction( VERTEX_FUNCTION, vertSrc, ShaderComp::LOCATION_VERTEX_VIEW ); vp->setFunction( FRAGMENT_FUNCTION, fragSrc, ShaderComp::LOCATION_FRAGMENT_COLORING ); replacement->getOrCreateUniform( SAMPLER_TEXT, osg::Uniform::SAMPLER_2D )->set( 0 ); return replacement.valid(); }
void GLES2ShaderGenVisitor::update(osg::Drawable *drawable) { // update only geometry due to compatibility issues with user defined drawables osg::Geometry *geometry = drawable->asGeometry(); #if 1 if (!geometry) return; #endif OSG_INFO << "Updating GEOMETRY 1" <<std::endl; StateEx *state = static_cast<StateEx *>(_state.get()); // skip nodes without state sets if (state->getStateSetStackSize() == (_rootStateSet.valid() ? 1u : 0u)) return; OSG_INFO << "Updating GEOMETRY 2" <<std::endl; // skip state sets with already attached programs if (state->getAttribute(osg::StateAttribute::PROGRAM)) return; OSG_INFO << "Updating GEOMETRY 3" <<std::endl; int stateMask = 0; //if (state->getMode(GL_BLEND) & osg::StateAttribute::ON) // stateMask |= ShaderGen::BLEND; if (state->getMode(GL_LIGHTING) & osg::StateAttribute::ON) stateMask |= GLES2ShaderGenCache::LIGHTING; if (state->getMode(GL_FOG) & osg::StateAttribute::ON) stateMask |= GLES2ShaderGenCache::FOG; if (state->getTextureAttribute(0, osg::StateAttribute::TEXTURE)) stateMask |= GLES2ShaderGenCache::DIFFUSE_MAP; if (state->getTextureAttribute(1, osg::StateAttribute::TEXTURE) && geometry!=0 && geometry->getVertexAttribArray(6)) //tangent stateMask |= GLES2ShaderGenCache::NORMAL_MAP; // Get program and uniforms for accumulated state. osg::StateSet *progss = _stateCache->getOrCreateStateSet(stateMask); // Set program and uniforms to the last state set. osg::StateSet *ss = const_cast<osg::StateSet *>(state->getStateSetStack().back()); ss->setAttribute(progss->getAttribute(osg::StateAttribute::PROGRAM)); ss->setUniformList(progss->getUniformList()); //Edit, for now we will pinch the Material colors and bind as uniforms for non fixed function to replace gl_Front Material #ifndef OSG_GL_FIXED_FUNCTION_AVAILABLE OSG_INFO << "Updating GEOMETRY material" <<std::endl; osg::Material* mat = dynamic_cast<osg::Material*>(ss->getAttribute(osg::StateAttribute::MATERIAL)); if(mat){ ss->addUniform(new osg::Uniform("osg_Material.ambient", mat->getAmbient(osg::Material::FRONT_AND_BACK))); ss->addUniform(new osg::Uniform("osg_Material.diffuse", mat->getDiffuse(osg::Material::FRONT_AND_BACK))); ss->addUniform(new osg::Uniform("osg_Material.specular", mat->getSpecular(osg::Material::FRONT_AND_BACK))); ss->addUniform(new osg::Uniform("osg_Material.shine", mat->getShininess(osg::Material::FRONT_AND_BACK))); ss->removeAttribute(osg::StateAttribute::MATERIAL); osg::notify(osg::NOTICE) << "----------- Generated material" << std::endl; }else{ //if no material then setup some reasonable defaults ss->addUniform(new osg::Uniform("osg_Material.ambient", osg::Vec4(0.2f,0.2f,0.2f,1.0f))); ss->addUniform(new osg::Uniform("osg_Material.diffuse", osg::Vec4(0.8f,0.8f,0.8f,1.0f))); ss->addUniform(new osg::Uniform("osg_Material.specular", osg::Vec4(1.0f,1.0f,1.0f,1.0f))); ss->addUniform(new osg::Uniform("osg_Material.shine", 16.0f)); } #endif // remove any modes that won't be appropriate when using shaders if ((stateMask & GLES2ShaderGenCache::LIGHTING)!=0) { ss->removeMode(GL_LIGHTING); ss->removeMode(GL_LIGHT0); } if ((stateMask & GLES2ShaderGenCache::FOG)!=0) { ss->removeMode(GL_FOG); } if ((stateMask & GLES2ShaderGenCache::DIFFUSE_MAP)!=0) ss->removeTextureMode(0, GL_TEXTURE_2D); if ((stateMask & GLES2ShaderGenCache::NORMAL_MAP)!=0) ss->removeTextureMode(1, GL_TEXTURE_2D); }
bool ShaderGenerator::processGeometry(const osg::StateSet* original, osg::ref_ptr<osg::StateSet>& replacement) { // do nothing if there's no GLSL support if ( !_active ) 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; // copy or create a new stateset (that we may or may not use depending on // what we find) osg::ref_ptr<osg::StateSet> new_stateset = original ? osg::clone(original, osg::CopyOp::SHALLOW_COPY) : new osg::StateSet(); // likewise, create a VP that we might populate. osg::ref_ptr<VirtualProgram> vp = VirtualProgram::cloneOrCreate(original, new_stateset); // we'll set this to true if the new stateset goes into effect and // needs to be returned. bool need_new_stateset = false; // give the VP a name if it needs one. if ( vp->getName().empty() ) vp->setName( _name ); // Check whether the lighting state has changed and install a mode uniform. // TODO: fix this if ( original && original->getMode(GL_LIGHTING) != osg::StateAttribute::INHERIT ) { need_new_stateset = true; osg::StateAttribute::GLModeValue value = state->getMode(GL_LIGHTING); // from the state, not the ss. new_stateset->addUniform( Registry::shaderFactory()->createUniformForGLMode(GL_LIGHTING, value) ); } // if the stateset changes any texture attributes, we need a new virtual program: if (state->getNumTextureAttributes() > 0) { // start generating the shader source. GenBuffers buf; buf.stateSet = new_stateset; // compatibility strings make it work in GL or GLES. buf.vertHead << "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION; buf.fragHead << "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION; // function declarations: buf.vertBody << "void " VERTEX_FUNCTION "(inout vec4 vertex_view)\n{\n"; buf.fragBody << "void " FRAGMENT_FUNCTION "(inout vec4 color)\n{\n"; bool wroteTexelDecl = false; // Loop over all possible texture image units. int maxUnit = Registry::capabilities().getMaxGPUTextureUnits(); for( int unit = 0; unit < maxUnit; ++unit ) { if ( !wroteTexelDecl ) { buf.fragBody << INDENT << MEDIUMP "vec4 texel; \n"; wroteTexelDecl = true; } osg::Texture* tex = dynamic_cast<osg::Texture*>( state->getTextureAttribute(unit, osg::StateAttribute::TEXTURE)); if (accept(tex) && !ImageUtils::isFloatingPointInternalFormat(tex->getInternalFormat())) { // record this unit as being in use _texImageUnits.insert( unit ); osg::TexGen* texgen = dynamic_cast<osg::TexGen*>(state->getTextureAttribute(unit, osg::StateAttribute::TEXGEN)); osg::TexEnv* texenv = dynamic_cast<osg::TexEnv*>(state->getTextureAttribute(unit, osg::StateAttribute::TEXENV)); if ( apply(tex, texgen, texenv, unit, buf) == true ) { need_new_stateset = true; } } } if ( need_new_stateset ) { // close out functions: buf.vertBody << "}\n"; buf.fragBody << "}\n"; // Extract the shader source strings (win compat method) std::string vertBodySrc, vertSrc, fragBodySrc, fragSrc; vertBodySrc = buf.vertBody.str(); buf.vertHead << vertBodySrc; vertSrc = buf.vertHead.str(); fragBodySrc = buf.fragBody.str(); buf.fragHead << fragBodySrc; fragSrc = buf.fragHead.str(); // inject the shaders: vp->setFunction( VERTEX_FUNCTION, vertSrc, ShaderComp::LOCATION_VERTEX_VIEW ); vp->setFunction( FRAGMENT_FUNCTION, fragSrc, ShaderComp::LOCATION_FRAGMENT_COLORING ); } } if ( need_new_stateset ) { replacement = new_stateset.get(); } return replacement.valid(); }
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. osg::ref_ptr<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::SHALLOW_COPY); //if ( !replacement.valid() ) // replacement = osg::clone(ss, osg::CopyOp::DEEP_COPY_ALL); osg::StateAttribute::GLModeValue value = state->getMode(GL_LIGHTING); // from the state, not the ss. replacement->addUniform( Registry::shaderFactory()->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::SHALLOW_COPY); //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 "(inout vec4 vertex_view)\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() ); } } osg::TexGen::Mode texGenMode = osg::TexGen::OBJECT_LINEAR; osg::TexGen* texGen = dynamic_cast<osg::TexGen*>(state->getTextureAttribute(t, osg::StateAttribute::TEXGEN)); if ( texGen ) { texGenMode = texGen->getMode(); } vertHead << "varying " MEDIUMP "vec4 " TEX_COORD << t << ";\n"; fragHead << "varying " MEDIUMP "vec4 " TEX_COORD << t << ";\n"; // handle different TexGen modes. switch(texGenMode) { case osg::TexGen::SPHERE_MAP: vertBody //todo: consolidate. << INDENT "{\n" // scope it in case there are > 1 << INDENT "vec3 v = normalize(vec3(vertex_view));\n" << INDENT "vec3 n = normalize(gl_NormalMatrix * gl_Normal);\n" << INDENT "vec3 r = reflect(v, n);\n" << INDENT "float m = 2.0 * sqrt(r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0));\n" << INDENT TEX_COORD << t << ".s = r.x/m + 0.5;\n" << INDENT TEX_COORD << t << ".t = r.y/m + 0.5;\n" << INDENT "}\n"; break; default: vertBody << INDENT << TEX_COORD << t << " = gl_MultiTexCoord" << t << ";\n"; break; } 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 ); } #if 1 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 // embosser else if ( dynamic_cast<osg::Texture2D*>(tex) ) { fragHead << "uniform sampler2D " SAMPLER << t << ";\n"; fragBody << INDENT "{\n" << INDENT "float bs = 1.0/256.0;\n" << INDENT "vec4 bm = vec4(0.0);\n" << INDENT "float u = " TEX_COORD << t << ".x;\n" << INDENT "float v = " TEX_COORD << t << ".y;\n" << INDENT "texel = texture2D(" SAMPLER << t << ", vec2(u, v)); \n" << INDENT "bm = texture2D(" SAMPLER << t << ", vec2(u-bs, v-bs)) + \n" << INDENT " texture2D(" SAMPLER << t << ", vec2(u-bs, v-bs)) - \n" << INDENT " texel - \n" << INDENT " texture2D(" SAMPLER << t << ", vec2(u+bs, v+bs)); \n" << INDENT "texel *= vec4( 2.0*(bm.rgb+vec3(0.5,0.5,0.5)),1.0 );\n" << INDENT "}\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_2D )->set( t ); } #endif #if 0 // works, but requires a higher version of GL? else if ( dynamic_cast<osg::TextureRectangle*>(tex) ) { fragHead << "uniform sampler2Drect " SAMPLER << t << ";\n"; fragBody << INDENT "texel = texture2Drect(" SAMPLER << t << ", " TEX_COORD << t << ".xy);\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_2D_RECT )->set( t ); } #endif // doesn't work. why? else if ( dynamic_cast<osg::TextureRectangle*>(tex) ) { osg::Image* image = static_cast<osg::TextureRectangle*>(tex)->getImage(); vertBody << INDENT << TEX_COORD << t << ".x /= " << (image->s()-1) << ".0;\n" << INDENT << TEX_COORD << t << ".y /= " << (image->t()-1) << ".0;\n"; 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_VIEW ); vp->setFunction( FRAGMENT_FUNCTION, fragSrc, ShaderComp::LOCATION_FRAGMENT_COLORING ); } return replacement.valid(); }
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(); }