From 8b21b87d96cb777944ffc19fb12c41fc0862ab18 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 15 Dec 2007 15:22:00 +0000 Subject: [PATCH] Added setting of ambient bias uniform --- src/osgShadow/ShadowMap.cpp | 985 ++++++++++++++++++------------------ 1 file changed, 493 insertions(+), 492 deletions(-) diff --git a/src/osgShadow/ShadowMap.cpp b/src/osgShadow/ShadowMap.cpp index 657851bcb..b87cf907d 100644 --- a/src/osgShadow/ShadowMap.cpp +++ b/src/osgShadow/ShadowMap.cpp @@ -29,548 +29,549 @@ using namespace osgShadow; #include #include - ////////////////////////////////////////////////////////////////// - // fragment shader - // - static const char fragmentShaderSource_noBaseTexture[] = - "uniform sampler2DShadow osgShadow_shadowTexture; \n" - "uniform vec2 osgShadow_ambientBias; \n" - "\n" - "void main(void) \n" - "{ \n" - " gl_FragColor = gl_Color * (osgShadow_ambientBias.x + shadow2DProj( osgShadow_shadowTexture, gl_TexCoord[0] ) * osgShadow_ambientBias.y); \n" - "}\n"; +////////////////////////////////////////////////////////////////// +// fragment shader +// +static const char fragmentShaderSource_noBaseTexture[] = + "uniform sampler2DShadow osgShadow_shadowTexture; \n" + "uniform vec2 osgShadow_ambientBias; \n" + "\n" + "void main(void) \n" + "{ \n" + " gl_FragColor = gl_Color * (osgShadow_ambientBias.x + shadow2DProj( osgShadow_shadowTexture, gl_TexCoord[0] ) * osgShadow_ambientBias.y); \n" + "}\n"; - ////////////////////////////////////////////////////////////////// - // fragment shader - // - static const char fragmentShaderSource_withBaseTexture[] = - "uniform sampler2D osgShadow_baseTexture; \n" - "uniform sampler2DShadow osgShadow_shadowTexture; \n" - "uniform vec2 osgShadow_ambientBias; \n" - "\n" - "void main(void) \n" - "{ \n" - " vec4 color = gl_Color * texture2D( osgShadow_baseTexture, gl_TexCoord[0].xy ); \n" - " gl_FragColor = color * (osgShadow_ambientBias.x + shadow2DProj( osgShadow_shadowTexture, gl_TexCoord[1] ) * osgShadow_ambientBias.y); \n" - "}\n"; +////////////////////////////////////////////////////////////////// +// fragment shader +// +static const char fragmentShaderSource_withBaseTexture[] = + "uniform sampler2D osgShadow_baseTexture; \n" + "uniform sampler2DShadow osgShadow_shadowTexture; \n" + "uniform vec2 osgShadow_ambientBias; \n" + "\n" + "void main(void) \n" + "{ \n" + " vec4 color = gl_Color * texture2D( osgShadow_baseTexture, gl_TexCoord[0].xy ); \n" + " gl_FragColor = color * (osgShadow_ambientBias.x + shadow2DProj( osgShadow_shadowTexture, gl_TexCoord[1] ) * osgShadow_ambientBias.y); \n" + "}\n"; - ////////////////////////////////////////////////////////////////// - // fragment shader - // - static const char fragmentShaderSource_debugHUD_texcoord[] = - "uniform sampler2D osgShadow_shadowTexture; \n" - " \n" - "void main(void) \n" - "{ \n" - " vec4 texCoord = gl_TexCoord[1].xyzw; \n" - " float value = texCoord.z / texCoord.w; \n" - " gl_FragColor = vec4( value, value, value, 1.0 ); \n" - "} \n"; +////////////////////////////////////////////////////////////////// +// fragment shader +// +static const char fragmentShaderSource_debugHUD_texcoord[] = + "uniform sampler2D osgShadow_shadowTexture; \n" + " \n" + "void main(void) \n" + "{ \n" + " vec4 texCoord = gl_TexCoord[1].xyzw; \n" + " float value = texCoord.z / texCoord.w; \n" + " gl_FragColor = vec4( value, value, value, 1.0 ); \n" + "} \n"; - static const char fragmentShaderSource_debugHUD[] = - "uniform sampler2D osgShadow_shadowTexture; \n" - " \n" - "void main(void) \n" - "{ \n" - " vec4 texResult = texture2D(osgShadow_shadowTexture, gl_TexCoord[0].st ); \n" - " float value = texResult.r + 0.5; \n" - " gl_FragColor = vec4( value, value, value, 0.8 ); \n" - "} \n"; +static const char fragmentShaderSource_debugHUD[] = + "uniform sampler2D osgShadow_shadowTexture; \n" + " \n" + "void main(void) \n" + "{ \n" + " vec4 texResult = texture2D(osgShadow_shadowTexture, gl_TexCoord[0].st ); \n" + " float value = texResult.r + 0.5; \n" + " gl_FragColor = vec4( value, value, value, 0.8 ); \n" + "} \n"; - ShadowMap::ShadowMap(): - _baseTextureUnit(0), - _shadowTextureUnit(1), - _ambientBias(0.5f,0.5f), - _textureSize(1024,1024) +ShadowMap::ShadowMap(): +_baseTextureUnit(0), + _shadowTextureUnit(1), + _ambientBias(0.5f,0.5f), + _textureSize(1024,1024) +{ +} + +ShadowMap::ShadowMap(const ShadowMap& copy, const osg::CopyOp& copyop): +ShadowTechnique(copy,copyop), + _baseTextureUnit(copy._baseTextureUnit), + _shadowTextureUnit(copy._shadowTextureUnit), + _ambientBias(copy._ambientBias), + _textureSize(copy._textureSize) +{ +} + +void ShadowMap::setTextureUnit(unsigned int unit) +{ + _shadowTextureUnit = unit; +} + +void ShadowMap::setAmbientBias(const osg::Vec2& ambientBias) +{ + _ambientBias = ambientBias; + if (_ambientBiasUniform.valid()) _ambientBiasUniform->set(_ambientBias); +} + +void ShadowMap::setTextureSize(const osg::Vec2s& textureSize) +{ + _textureSize = textureSize; + dirty(); +} + +void ShadowMap::setLight(osg::Light* light) +{ + _light = light; +} + + +void ShadowMap::setLight(osg::LightSource* ls) +{ + _ls = ls; + _light = _ls->getLight(); +} + +void ShadowMap::createUniforms() +{ + _uniformList.clear(); + + osg::Uniform* baseTextureSampler = new osg::Uniform("osgShadow_baseTexture",(int)_baseTextureUnit); + _uniformList.push_back(baseTextureSampler); + + osg::Uniform* shadowTextureSampler = new osg::Uniform("osgShadow_shadowTexture",(int)_shadowTextureUnit); + _uniformList.push_back(shadowTextureSampler); + + _ambientBiasUniform = new osg::Uniform("osgShadow_ambientBias",_ambientBias); + _uniformList.push_back(_ambientBiasUniform.get()); + +} + +void ShadowMap::createShaders() +{ + // if we are not given shaders, use the default + if( _shaderList.empty() ) { - } - - ShadowMap::ShadowMap(const ShadowMap& copy, const osg::CopyOp& copyop): - ShadowTechnique(copy,copyop), - _baseTextureUnit(copy._baseTextureUnit), - _shadowTextureUnit(copy._shadowTextureUnit), - _ambientBias(copy._ambientBias), - _textureSize(copy._textureSize) - { - } - - void ShadowMap::setTextureUnit(unsigned int unit) - { - _shadowTextureUnit = unit; - } - - void ShadowMap::setAmbientBias(const osg::Vec2& ambientBias) - { - _ambientBias = ambientBias; - } - - void ShadowMap::setTextureSize(const osg::Vec2s& textureSize) - { - _textureSize = textureSize; - dirty(); - } - - void ShadowMap::setLight(osg::Light* light) - { - _light = light; - } - - - void ShadowMap::setLight(osg::LightSource* ls) - { - _ls = ls; - _light = _ls->getLight(); - } - - void ShadowMap::createUniforms() - { - _uniformList.clear(); - - osg::Uniform* baseTextureSampler = new osg::Uniform("osgShadow_baseTexture",(int)_baseTextureUnit); - _uniformList.push_back(baseTextureSampler); - - osg::Uniform* shadowTextureSampler = new osg::Uniform("osgShadow_shadowTexture",(int)_shadowTextureUnit); - _uniformList.push_back(shadowTextureSampler); - - _ambientBiasUniform = new osg::Uniform("osgShadow_ambientBias",_ambientBias); - _uniformList.push_back(_ambientBiasUniform.get()); - - } - - void ShadowMap::createShaders() - { - // if we are not given shaders, use the default - if( _shaderList.empty() ) + if (_shadowTextureUnit==0) { - if (_shadowTextureUnit==0) - { - osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture); - _shaderList.push_back(fragment_shader); - } - else - { - osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture); - _shaderList.push_back(fragment_shader); + osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture); + _shaderList.push_back(fragment_shader); + } + else + { + osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture); + _shaderList.push_back(fragment_shader); - } } } +} - void ShadowMap::init() +void ShadowMap::init() +{ + if (!_shadowedScene) return; + + _texture = new osg::Texture2D; + _texture->setTextureSize(_textureSize.x(), _textureSize.y()); + _texture->setInternalFormat(GL_DEPTH_COMPONENT); + _texture->setShadowComparison(true); + _texture->setShadowTextureMode(osg::Texture2D::LUMINANCE); + _texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); + _texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); + + // the shadow comparison should fail if object is outside the texture + _texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER); + _texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER); + _texture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); + + // set up the render to texture camera. { - if (!_shadowedScene) return; + // create the camera + _camera = new osg::Camera; - _texture = new osg::Texture2D; - _texture->setTextureSize(_textureSize.x(), _textureSize.y()); - _texture->setInternalFormat(GL_DEPTH_COMPONENT); - _texture->setShadowComparison(true); - _texture->setShadowTextureMode(osg::Texture2D::LUMINANCE); - _texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); - _texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); + _camera->setCullCallback(new CameraCullCallback(this)); - // the shadow comparison should fail if object is outside the texture - _texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER); - _texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER); - _texture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); + _camera->setClearMask(GL_DEPTH_BUFFER_BIT); + //_camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + _camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); + _camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); - // set up the render to texture camera. - { - // create the camera - _camera = new osg::Camera; + // set viewport + _camera->setViewport(0,0,_textureSize.x(),_textureSize.y()); - _camera->setCullCallback(new CameraCullCallback(this)); + // set the camera to render before the main camera. + _camera->setRenderOrder(osg::Camera::PRE_RENDER); - _camera->setClearMask(GL_DEPTH_BUFFER_BIT); - //_camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - _camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); - _camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); + // tell the camera to use OpenGL frame buffer object where supported. + _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + //_camera->setRenderTargetImplementation(osg::Camera::SEPERATE_WINDOW); - // set viewport - _camera->setViewport(0,0,_textureSize.x(),_textureSize.y()); + // attach the texture and use it as the color buffer. + _camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get()); - // set the camera to render before the main camera. - _camera->setRenderOrder(osg::Camera::PRE_RENDER); - - // tell the camera to use OpenGL frame buffer object where supported. - _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); - //_camera->setRenderTargetImplementation(osg::Camera::SEPERATE_WINDOW); - - // attach the texture and use it as the color buffer. - _camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get()); - - osg::StateSet* stateset = _camera->getOrCreateStateSet(); + osg::StateSet* stateset = _camera->getOrCreateStateSet(); #if 1 - // cull front faces so that only backfaces contribute to depth map + // cull front faces so that only backfaces contribute to depth map - osg::ref_ptr cull_face = new osg::CullFace; - cull_face->setMode(osg::CullFace::FRONT); - stateset->setAttribute(cull_face.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + osg::ref_ptr cull_face = new osg::CullFace; + cull_face->setMode(osg::CullFace::FRONT); + stateset->setAttribute(cull_face.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - // negative polygonoffset - move the backface nearer to the eye point so that backfaces - // shadow themselves - float factor = -1.0f; - float units = -1.0f; + // negative polygonoffset - move the backface nearer to the eye point so that backfaces + // shadow themselves + float factor = -1.0f; + float units = -1.0f; - osg::ref_ptr polygon_offset = new osg::PolygonOffset; - polygon_offset->setFactor(factor); - polygon_offset->setUnits(units); - stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + osg::ref_ptr polygon_offset = new osg::PolygonOffset; + polygon_offset->setFactor(factor); + polygon_offset->setUnits(units); + stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); #else - // disabling cull faces so that only front and backfaces contribute to depth map - stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); + // disabling cull faces so that only front and backfaces contribute to depth map + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); - // negative polygonoffset - move the backface nearer to the eye point - // so that front faces do not shadow themselves. - float factor = 1.0f; - float units = 1.0f; + // negative polygonoffset - move the backface nearer to the eye point + // so that front faces do not shadow themselves. + float factor = 1.0f; + float units = 1.0f; - osg::ref_ptr polygon_offset = new osg::PolygonOffset; - polygon_offset->setFactor(factor); - polygon_offset->setUnits(units); - stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + osg::ref_ptr polygon_offset = new osg::PolygonOffset; + polygon_offset->setFactor(factor); + polygon_offset->setUnits(units); + stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); #endif - } - - { - _stateset = new osg::StateSet; - _stateset->setTextureAttributeAndModes(_shadowTextureUnit,_texture.get(),osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - _stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); - _stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); - _stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); - _stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); - - _texgen = new osg::TexGen; - - // add Program, when empty of Shaders then we are using fixed functionality - _program = new osg::Program; - _stateset->setAttribute(_program.get()); - - // create default shaders if needed - createShaders(); - - // add the shader list to the program - for(ShaderList::const_iterator itr=_shaderList.begin(); - itr!=_shaderList.end(); - ++itr) - { - _program->addShader(itr->get()); - } - - // create own uniforms - createUniforms(); - - // add the uniform list to the stateset - for(UniformList::const_iterator itr=_uniformList.begin(); - itr!=_uniformList.end(); - ++itr) - { - _stateset->addUniform(itr->get()); - } - - { - // fake texture for baseTexture, add a fake texture - // we support by default at least one texture layer - // without this fake texture we can not support - // textured and not textured scene - - // TODO: at the moment the PSSM supports just one texture layer in the GLSL shader, multitexture are - // not yet supported ! - - osg::Image* image = new osg::Image; - // allocate the image data, noPixels x 1 x 1 with 4 rgba floats - equivilant to a Vec4! - int noPixels = 1; - image->allocateImage(noPixels,1,1,GL_RGBA,GL_FLOAT); - image->setInternalTextureFormat(GL_RGBA); - // fill in the image data. - osg::Vec4* dataPtr = (osg::Vec4*)image->data(); - osg::Vec4 color(1,1,1,1); - *dataPtr = color; - // make fake texture - osg::Texture2D* fakeTex = new osg::Texture2D; - fakeTex->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER); - fakeTex->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER); - fakeTex->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); - fakeTex->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); - fakeTex->setImage(image); - // add fake texture - _stateset->setTextureAttribute(_baseTextureUnit,fakeTex,osg::StateAttribute::ON); - _stateset->setTextureMode(_baseTextureUnit,GL_TEXTURE_1D,osg::StateAttribute::OFF); - _stateset->setTextureMode(_baseTextureUnit,GL_TEXTURE_2D,osg::StateAttribute::ON); - _stateset->setTextureMode(_baseTextureUnit,GL_TEXTURE_3D,osg::StateAttribute::OFF); - } - } - - _dirty = false; } - - void ShadowMap::update(osg::NodeVisitor& nv) { - _shadowedScene->osg::Group::traverse(nv); - } + _stateset = new osg::StateSet; + _stateset->setTextureAttributeAndModes(_shadowTextureUnit,_texture.get(),osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + _stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); + _stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); + _stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); + _stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); - void ShadowMap::cull(osgUtil::CullVisitor& cv) - { - // record the traversal mask on entry so we can reapply it later. - unsigned int traversalMask = cv.getTraversalMask(); + _texgen = new osg::TexGen; - osgUtil::RenderStage* orig_rs = cv.getRenderStage(); + // add Program, when empty of Shaders then we are using fixed functionality + _program = new osg::Program; + _stateset->setAttribute(_program.get()); - // do traversal of shadow receiving scene which does need to be decorated by the shadow map - { - cv.pushStateSet(_stateset.get()); + // create default shaders if needed + createShaders(); - _shadowedScene->osg::Group::traverse(cv); - - cv.popStateSet(); - - } - - // need to compute view frustum for RTT camera. - // 1) get the light position - // 2) get the center and extents of the view frustum - - const osg::Light* selectLight = 0; - osg::Vec4 lightpos; - osg::Vec3 lightDir; - - //MR testing giving a specific light - osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList(); - for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin(); - itr != aml.end(); + // add the shader list to the program + for(ShaderList::const_iterator itr=_shaderList.begin(); + itr!=_shaderList.end(); ++itr) { - const osg::Light* light = dynamic_cast(itr->first.get()); - if (light) - { - if( _light.valid()) { - if( _light.get() == light ) - selectLight = light; - else - continue; - } - else - selectLight = light; - - osg::RefMatrix* matrix = itr->second.get(); - if (matrix) - { - lightpos = light->getPosition() * (*matrix); - lightDir = light->getDirection() * (*matrix); - } - else - { - lightpos = light->getPosition(); - lightDir = light->getDirection(); - } - - } + _program->addShader(itr->get()); } - - osg::Matrix eyeToWorld; - eyeToWorld.invert(*cv.getModelViewMatrix()); - lightpos = lightpos * eyeToWorld; - //MR do we do this for the direction also ? preliminary Yes, but still no good result - lightDir = lightDir * eyeToWorld; - lightDir.normalize(); + // create own uniforms + createUniforms(); - if (selectLight) + // add the uniform list to the stateset + for(UniformList::const_iterator itr=_uniformList.begin(); + itr!=_uniformList.end(); + ++itr) { + _stateset->addUniform(itr->get()); + } - // set to ambient on light to black so that the ambient bias uniform can take it's affect - const_cast(selectLight)->setAmbient(osg::Vec4(0.0f,0.0f,0.0f,1.0f)); + { + // fake texture for baseTexture, add a fake texture + // we support by default at least one texture layer + // without this fake texture we can not support + // textured and not textured scene - //std::cout<<"----- VxOSG::ShadowMap selectLight spot cutoff "<getSpotCutoff()<getSpotCutoff() < 180.0f) // spotlight, then we don't need the bounding box - { - osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z()); - float spotAngle = selectLight->getSpotCutoff(); - _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); - _camera->setProjectionMatrixAsPerspective(spotAngle, 1.0, 0.1, 1000.0); - _camera->setViewMatrixAsLookAt(position,position+lightDir,osg::Vec3(0.0f,1.0f,0.0f)); + osg::Image* image = new osg::Image; + // allocate the image data, noPixels x 1 x 1 with 4 rgba floats - equivilant to a Vec4! + int noPixels = 1; + image->allocateImage(noPixels,1,1,GL_RGBA,GL_FLOAT); + image->setInternalTextureFormat(GL_RGBA); + // fill in the image data. + osg::Vec4* dataPtr = (osg::Vec4*)image->data(); + osg::Vec4 color(1,1,1,1); + *dataPtr = color; + // make fake texture + osg::Texture2D* fakeTex = new osg::Texture2D; + fakeTex->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER); + fakeTex->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER); + fakeTex->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); + fakeTex->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); + fakeTex->setImage(image); + // add fake texture + _stateset->setTextureAttribute(_baseTextureUnit,fakeTex,osg::StateAttribute::ON); + _stateset->setTextureMode(_baseTextureUnit,GL_TEXTURE_1D,osg::StateAttribute::OFF); + _stateset->setTextureMode(_baseTextureUnit,GL_TEXTURE_2D,osg::StateAttribute::ON); + _stateset->setTextureMode(_baseTextureUnit,GL_TEXTURE_3D,osg::StateAttribute::OFF); + } + } + + _dirty = false; +} + + +void ShadowMap::update(osg::NodeVisitor& nv) +{ + _shadowedScene->osg::Group::traverse(nv); +} + +void ShadowMap::cull(osgUtil::CullVisitor& cv) +{ + // record the traversal mask on entry so we can reapply it later. + unsigned int traversalMask = cv.getTraversalMask(); + + osgUtil::RenderStage* orig_rs = cv.getRenderStage(); + + // do traversal of shadow receiving scene which does need to be decorated by the shadow map + { + cv.pushStateSet(_stateset.get()); + + _shadowedScene->osg::Group::traverse(cv); + + cv.popStateSet(); + + } + + // need to compute view frustum for RTT camera. + // 1) get the light position + // 2) get the center and extents of the view frustum + + const osg::Light* selectLight = 0; + osg::Vec4 lightpos; + osg::Vec3 lightDir; + + //MR testing giving a specific light + osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList(); + for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin(); + itr != aml.end(); + ++itr) + { + const osg::Light* light = dynamic_cast(itr->first.get()); + if (light) + { + if( _light.valid()) { + if( _light.get() == light ) + selectLight = light; + else + continue; } else + selectLight = light; + + osg::RefMatrix* matrix = itr->second.get(); + if (matrix) { - // get the bounds of the model. - osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); - cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask()); - - _shadowedScene->osg::Group::traverse(cbbv); - - osg::BoundingBox bb = cbbv.getBoundingBox(); - - if (lightpos[3]!=0.0) // point light - { - osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z()); - - float centerDistance = (position-bb.center()).length(); - - float znear = centerDistance-bb.radius(); - float zfar = centerDistance+bb.radius(); - float zNearRatio = 0.001f; - if (znearsetReferenceFrame(osg::Camera::ABSOLUTE_RF); - _camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar); - _camera->setViewMatrixAsLookAt(position,bb.center(),osg::Vec3(0.0f,1.0f,0.0f)); - } - else // directional light - { - // make an orthographic projection - osg::Vec3 lightDir(lightpos.x(), lightpos.y(), lightpos.z()); - lightDir.normalize(); - - // set the position far away along the light direction - osg::Vec3 position = lightDir * bb.radius() * 20; - - float centerDistance = (position-bb.center()).length(); - - float znear = centerDistance-bb.radius(); - float zfar = centerDistance+bb.radius(); - float zNearRatio = 0.001f; - if (znearsetReferenceFrame(osg::Camera::ABSOLUTE_RF); - _camera->setProjectionMatrixAsOrtho(-right, right, -top, top, znear, zfar); - _camera->setViewMatrixAsLookAt(position,bb.center(),osg::Vec3(0.0f,1.0f,0.0f)); - } - - + lightpos = light->getPosition() * (*matrix); + lightDir = light->getDirection() * (*matrix); + } + else + { + lightpos = light->getPosition(); + lightDir = light->getDirection(); } - // compute the matrix which takes a vertex from local coords into tex coords - // will use this later to specify osg::TexGen.. - osg::Matrix MVPT = _camera->getViewMatrix() * - _camera->getProjectionMatrix() * - osg::Matrix::translate(1.0,1.0,1.0) * - osg::Matrix::scale(0.5f,0.5f,0.5f); - _texgen->setMode(osg::TexGen::EYE_LINEAR); - _texgen->setPlanesFromMatrix(MVPT); - - cv.setTraversalMask( traversalMask & - getShadowedScene()->getCastsShadowTraversalMask() ); - - // do RTT camera traversal - _camera->accept(cv); - - orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(_shadowTextureUnit, cv.getModelViewMatrix(), _texgen.get()); - } // if(selectLight) - - - // reapply the original traversal mask - cv.setTraversalMask( traversalMask ); - } - - void ShadowMap::cleanSceneGraph() - { - } - - ///////////////////// Debug Methods - - osg::ref_ptr ShadowMap::makeDebugHUD() - { - osg::ref_ptr camera = new osg::Camera; - - osg::Vec2 size(1280, 1024); - // set the projection matrix - camera->setProjectionMatrix(osg::Matrix::ortho2D(0,size.x(),0,size.y())); - - // set the view matrix - camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); - camera->setViewMatrix(osg::Matrix::identity()); - - // only clear the depth buffer - camera->setClearMask(GL_DEPTH_BUFFER_BIT); - camera->setClearColor(osg::Vec4(0.2f, 0.3f, 0.5f, 0.2f)); - //camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - - // draw subgraph after main camera view. - camera->setRenderOrder(osg::Camera::POST_RENDER); - - // we don't want the camera to grab event focus from the viewers main camera(s). - camera->setAllowEventFocus(false); - - osg::Geode* geode = new osg::Geode; - - osg::Vec3 position(10.0f,size.y()-100.0f,0.0f); - osg::Vec3 delta(0.0f,-120.0f,0.0f); - float lenght = 300.0f; - - // turn the text off to avoid linking with osgText -#if 0 - std::string timesFont("fonts/arial.ttf"); - - { - osgText::Text* text = new osgText::Text; - geode->addDrawable( text ); - - text->setFont(timesFont); - text->setPosition(position); - text->setText("Shadow Map HUD"); - - position += delta; } -#endif - - osg::Vec3 widthVec(lenght, 0.0f, 0.0f); - osg::Vec3 depthVec(0.0f,lenght, 0.0f); - osg::Vec3 centerBase( 10.0f + lenght/2, size.y()-lenght/2, 0.0f); - centerBase += delta; - - geode->addDrawable( osg::createTexturedQuadGeometry( centerBase-widthVec*0.5f-depthVec*0.5f, - widthVec, depthVec) ); - - osg::StateSet* stateset = geode->getOrCreateStateSet(); - - stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); - stateset->setMode(GL_BLEND,osg::StateAttribute::ON); - //stateset->setAttribute(new osg::PolygonOffset(1.0f,1.0f),osg::StateAttribute::ON); - stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - - // test with regular texture - //stateset->setTextureAttributeAndModes(_baseTextureUnit, new osg::Texture2D(osgDB::readImageFile("Images/lz.rgb"))); - - stateset->setTextureAttributeAndModes(_shadowTextureUnit,_texture.get(),osg::StateAttribute::ON); - - //test to check the texture coordinates generated during shadow pass -#if 0 - stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); - stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); - stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); - stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); - - // create TexGen node - osg::ref_ptr texGenNode = new osg::TexGenNode; - texGenNode->setTextureUnit(_shadowTextureUnit); - texGenNode->setTexGen(_texgen.get()); - camera->addChild(texGenNode.get()); -#endif - //shader for correct display - - osg::ref_ptr program = new osg::Program; - stateset->setAttribute(program.get()); - - osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_debugHUD); - program->addShader(fragment_shader); - - camera->addChild(geode); - - return camera; } - //////////////////////// End Debug Section + osg::Matrix eyeToWorld; + eyeToWorld.invert(*cv.getModelViewMatrix()); + + lightpos = lightpos * eyeToWorld; + //MR do we do this for the direction also ? preliminary Yes, but still no good result + lightDir = lightDir * eyeToWorld; + lightDir.normalize(); + + if (selectLight) + { + + // set to ambient on light to black so that the ambient bias uniform can take it's affect + const_cast(selectLight)->setAmbient(osg::Vec4(0.0f,0.0f,0.0f,1.0f)); + + //std::cout<<"----- VxOSG::ShadowMap selectLight spot cutoff "<getSpotCutoff()<getSpotCutoff() < 180.0f) // spotlight, then we don't need the bounding box + { + osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z()); + float spotAngle = selectLight->getSpotCutoff(); + _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + _camera->setProjectionMatrixAsPerspective(spotAngle, 1.0, 0.1, 1000.0); + _camera->setViewMatrixAsLookAt(position,position+lightDir,osg::Vec3(0.0f,1.0f,0.0f)); + } + else + { + // get the bounds of the model. + osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); + cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask()); + + _shadowedScene->osg::Group::traverse(cbbv); + + osg::BoundingBox bb = cbbv.getBoundingBox(); + + if (lightpos[3]!=0.0) // point light + { + osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z()); + + float centerDistance = (position-bb.center()).length(); + + float znear = centerDistance-bb.radius(); + float zfar = centerDistance+bb.radius(); + float zNearRatio = 0.001f; + if (znearsetReferenceFrame(osg::Camera::ABSOLUTE_RF); + _camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar); + _camera->setViewMatrixAsLookAt(position,bb.center(),osg::Vec3(0.0f,1.0f,0.0f)); + } + else // directional light + { + // make an orthographic projection + osg::Vec3 lightDir(lightpos.x(), lightpos.y(), lightpos.z()); + lightDir.normalize(); + + // set the position far away along the light direction + osg::Vec3 position = lightDir * bb.radius() * 20; + + float centerDistance = (position-bb.center()).length(); + + float znear = centerDistance-bb.radius(); + float zfar = centerDistance+bb.radius(); + float zNearRatio = 0.001f; + if (znearsetReferenceFrame(osg::Camera::ABSOLUTE_RF); + _camera->setProjectionMatrixAsOrtho(-right, right, -top, top, znear, zfar); + _camera->setViewMatrixAsLookAt(position,bb.center(),osg::Vec3(0.0f,1.0f,0.0f)); + } + + + } + // compute the matrix which takes a vertex from local coords into tex coords + // will use this later to specify osg::TexGen.. + osg::Matrix MVPT = _camera->getViewMatrix() * + _camera->getProjectionMatrix() * + osg::Matrix::translate(1.0,1.0,1.0) * + osg::Matrix::scale(0.5f,0.5f,0.5f); + + _texgen->setMode(osg::TexGen::EYE_LINEAR); + _texgen->setPlanesFromMatrix(MVPT); + + cv.setTraversalMask( traversalMask & + getShadowedScene()->getCastsShadowTraversalMask() ); + + // do RTT camera traversal + _camera->accept(cv); + + orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(_shadowTextureUnit, cv.getModelViewMatrix(), _texgen.get()); + } // if(selectLight) + + + // reapply the original traversal mask + cv.setTraversalMask( traversalMask ); +} + +void ShadowMap::cleanSceneGraph() +{ +} + +///////////////////// Debug Methods + +osg::ref_ptr ShadowMap::makeDebugHUD() +{ + osg::ref_ptr camera = new osg::Camera; + + osg::Vec2 size(1280, 1024); + // set the projection matrix + camera->setProjectionMatrix(osg::Matrix::ortho2D(0,size.x(),0,size.y())); + + // set the view matrix + camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); + camera->setViewMatrix(osg::Matrix::identity()); + + // only clear the depth buffer + camera->setClearMask(GL_DEPTH_BUFFER_BIT); + camera->setClearColor(osg::Vec4(0.2f, 0.3f, 0.5f, 0.2f)); + //camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + // draw subgraph after main camera view. + camera->setRenderOrder(osg::Camera::POST_RENDER); + + // we don't want the camera to grab event focus from the viewers main camera(s). + camera->setAllowEventFocus(false); + + osg::Geode* geode = new osg::Geode; + + osg::Vec3 position(10.0f,size.y()-100.0f,0.0f); + osg::Vec3 delta(0.0f,-120.0f,0.0f); + float lenght = 300.0f; + + // turn the text off to avoid linking with osgText +#if 0 + std::string timesFont("fonts/arial.ttf"); + + { + osgText::Text* text = new osgText::Text; + geode->addDrawable( text ); + + text->setFont(timesFont); + text->setPosition(position); + text->setText("Shadow Map HUD"); + + position += delta; + } +#endif + + osg::Vec3 widthVec(lenght, 0.0f, 0.0f); + osg::Vec3 depthVec(0.0f,lenght, 0.0f); + osg::Vec3 centerBase( 10.0f + lenght/2, size.y()-lenght/2, 0.0f); + centerBase += delta; + + geode->addDrawable( osg::createTexturedQuadGeometry( centerBase-widthVec*0.5f-depthVec*0.5f, + widthVec, depthVec) ); + + osg::StateSet* stateset = geode->getOrCreateStateSet(); + + stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); + stateset->setMode(GL_BLEND,osg::StateAttribute::ON); + //stateset->setAttribute(new osg::PolygonOffset(1.0f,1.0f),osg::StateAttribute::ON); + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + + // test with regular texture + //stateset->setTextureAttributeAndModes(_baseTextureUnit, new osg::Texture2D(osgDB::readImageFile("Images/lz.rgb"))); + + stateset->setTextureAttributeAndModes(_shadowTextureUnit,_texture.get(),osg::StateAttribute::ON); + + //test to check the texture coordinates generated during shadow pass +#if 0 + stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); + stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); + stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); + stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); + + // create TexGen node + osg::ref_ptr texGenNode = new osg::TexGenNode; + texGenNode->setTextureUnit(_shadowTextureUnit); + texGenNode->setTexGen(_texgen.get()); + camera->addChild(texGenNode.get()); +#endif + //shader for correct display + + osg::ref_ptr program = new osg::Program; + stateset->setAttribute(program.get()); + + osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_debugHUD); + program->addShader(fragment_shader); + + camera->addChild(geode); + + return camera; +} + +//////////////////////// End Debug Section