diff --git a/examples/osgshadow/osgshadow.cpp b/examples/osgshadow/osgshadow.cpp index e217f6210..4549dfb39 100644 --- a/examples/osgshadow/osgshadow.cpp +++ b/examples/osgshadow/osgshadow.cpp @@ -665,7 +665,11 @@ int main(int argc, char** argv) { osg::ref_ptr sm = new osgShadow::ShadowMap; shadowedScene->setShadowTechnique(sm.get()); - } + + int mapres = 1024; + while (arguments.read("--mapres", mapres)) + sm->setTextureSize(osg::Vec2s(mapres,mapres)); + } osg::ref_ptr model = osgDB::readNodeFiles(arguments); if (model.valid()) @@ -715,6 +719,22 @@ int main(int argc, char** argv) osg::ref_ptr ls = new osg::LightSource; ls->getLight()->setPosition(lightpos); + + bool spotlight = false; + if (arguments.read("--spotLight")) + { + spotlight = true; + + osg::Vec3 center = bb.center(); + osg::Vec3 lightdir = center - osg::Vec3(lightpos.x(), lightpos.y(), lightpos.z()); + lightdir.normalize(); + ls->getLight()->setDirection(lightdir); + ls->getLight()->setSpotCutoff(30.0f); + + //set the LightSource, only for checking, there is only 1 light in the scene + dynamic_cast(shadowedScene->getShadowTechnique())->setLight(ls.get()); + } + if ( arguments.read("--coloured-light")) { ls->getLight()->setAmbient(osg::Vec4(1.0,0.0,0.0,1.0)); @@ -730,10 +750,29 @@ int main(int argc, char** argv) shadowedScene->addChild(ls.get()); viewer.setSceneData(shadowedScene.get()); - + // create the windows and run the threads. viewer.realize(); + // it is done after viewer.realize() so that the windows are already initialized + if ( arguments.read("--debugHUD")) + { + osgViewer::Viewer::Windows windows; + viewer.getWindows(windows); + + if (windows.empty()) return 1; + + osgShadow::ShadowMap* sm = dynamic_cast(shadowedScene->getShadowTechnique()); + osg::ref_ptr hudCamera = sm->makeDebugHUD(); + + // set up cameras to rendering on the first window available. + hudCamera->setGraphicsContext(windows[0]); + hudCamera->setViewport(0,0,windows[0]->getTraits()->width, windows[0]->getTraits()->height); + + viewer.addSlave(hudCamera.get(), false); + } + + // osgDB::writeNodeFile(*group,"test.osg"); while (!viewer.done()) @@ -743,7 +782,7 @@ int main(int argc, char** argv) float t = viewer.getFrameStamp()->getSimulationTime(); if (postionalLight) { - lightpos.set(bb.center().x()+sinf(t)*bb.radius(), bb.center().y() + cosf(t)*bb.radius(), bb.zMax() + bb.radius() ,1.0f); + lightpos.set(bb.center().x()+sinf(t)*bb.radius(), bb.center().y() + cosf(t)*bb.radius(), bb.zMax() + bb.radius()*2.0f ,1.0f); } else { @@ -752,6 +791,9 @@ int main(int argc, char** argv) ls->getLight()->setPosition(lightpos); osg::Vec3f lightDir(-lightpos.x(),-lightpos.y(),-lightpos.z()); + if(spotlight) + lightDir = osg::Vec3(bb.center().x()+sinf(t)*bb.radius()/2.0, bb.center().y() + cosf(t)*bb.radius()/2.0, bb.center().z()) + - osg::Vec3(lightpos.x(), lightpos.y(), lightpos.z()) ; lightDir.normalize(); ls->getLight()->setDirection(lightDir); } diff --git a/include/osgShadow/ShadowMap b/include/osgShadow/ShadowMap index 36a6b21f1..db58c3f68 100644 --- a/include/osgShadow/ShadowMap +++ b/include/osgShadow/ShadowMap @@ -16,6 +16,8 @@ #include #include +#include +#include #include @@ -35,14 +37,34 @@ class OSGSHADOW_EXPORT ShadowMap : public ShadowTechnique void setTextureUnit(unsigned int unit); /** Get the texture unit that the shadow texture will be applied on.*/ - unsigned int getTextureUnit() const { return _textureUnit; } + unsigned int getTextureUnit() const { return _shadowTextureUnit; } /** Set the values for the ambient bias the shader will use.*/ void setAmbientBias(const osg::Vec2& ambientBias ); /** Get the values that are used for the ambient bias in the shader.*/ const osg::Vec2& getAmbientBias() const { return _ambientBias; } - + + /** set the size in pixels x / y for the shadow texture.*/ + void setTextureSize(const osg::Vec2s& textureSize); + + /** Get the values that are used for the ambient bias in the shader.*/ + const osg::Vec2s& getTextureSize() const { return _textureSize; } + + /** Set the Light that will cast shadows */ + void setLight(osg::Light* light); + void setLight(osg::LightSource* ls); + + typedef std::vector< osg::ref_ptr > UniformList; + + typedef std::vector< osg::ref_ptr > ShaderList; + + /** Add a shader to internal list, will be used instead of the default ones */ + inline void addShader(osg::Shader* shader) { _shaderList.push_back(shader); } + + /** Reset internal shader list */ + inline void clearShaderList() { _shaderList.clear(); } + /** initialize the ShadowedScene and local cached data structures.*/ virtual void init(); @@ -55,19 +77,35 @@ class OSGSHADOW_EXPORT ShadowMap : public ShadowTechnique /** Clean scene graph from any shadow technique specific nodes, state and drawables.*/ virtual void cleanSceneGraph(); + // debug methods - protected : + osg::ref_ptr makeDebugHUD(); - virtual ~ShadowMap() {} + protected: + virtual ~ShadowMap(void) {}; + + /** Create the managed Uniforms */ + void createUniforms(); + + void createShaders(); osg::ref_ptr _camera; osg::ref_ptr _texgen; osg::ref_ptr _texture; osg::ref_ptr _stateset; - unsigned int _textureUnit; + osg::ref_ptr _program; + osg::ref_ptr _light; + + osg::ref_ptr _ls; + + UniformList _uniformList; + ShaderList _shaderList; + unsigned int _baseTextureUnit; + unsigned int _shadowTextureUnit; osg::Vec2 _ambientBias; - -}; + osg::Vec2s _textureSize; + + }; } diff --git a/src/osgShadow/ShadowMap.cpp b/src/osgShadow/ShadowMap.cpp index f5e9f0846..80a4abe22 100644 --- a/src/osgShadow/ShadowMap.cpp +++ b/src/osgShadow/ShadowMap.cpp @@ -21,300 +21,455 @@ using namespace osgShadow; +#include +//for debug +#include +#include +#include +#include +#include -////////////////////////////////////////////////////////////////// -// fragment shader -// -static const char fragmentShaderSource_noBaseTexture[] = - "uniform sampler2DShadow shadowTexture; \n" - "uniform vec2 ambientBias; \n" - "\n" - "void main(void) \n" - "{ \n" - " gl_FragColor = gl_Color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[0] ) * 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 baseTexture; \n" - "uniform sampler2DShadow shadowTexture; \n" - "uniform vec2 ambientBias; \n" - "\n" - "void main(void) \n" - "{ \n" - " vec4 color = gl_Color * texture2D( baseTexture, gl_TexCoord[0].xy ); \n" - " gl_FragColor = color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[1] ) * 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"; -ShadowMap::ShadowMap(): - _textureUnit(1), - _ambientBias(0.3f,1.2f) -{ -} + ShadowMap::ShadowMap(): + _baseTextureUnit(0), + _shadowTextureUnit(1), + _ambientBias(0.3f,1.2f), + _textureSize(1024,1024) + { + } -ShadowMap::ShadowMap(const ShadowMap& copy, const osg::CopyOp& copyop): + ShadowMap::ShadowMap(const ShadowMap& copy, const osg::CopyOp& copyop): ShadowTechnique(copy,copyop), - _textureUnit(copy._textureUnit), - _ambientBias(copy._ambientBias) -{ -} - -void ShadowMap::setTextureUnit(unsigned int unit) -{ - _textureUnit = unit; -} - -void ShadowMap::setAmbientBias(const osg::Vec2& ambientBias) -{ - _ambientBias = ambientBias; -} - -void ShadowMap::init() -{ - if (!_shadowedScene) return; - - unsigned int tex_width = 1024; - unsigned int tex_height = 1024; - - _texture = new osg::Texture2D; - _texture->setTextureSize(tex_width, tex_height); - _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); - _texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_EDGE); - _texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_EDGE); - - // set up the render to texture camera. + _baseTextureUnit(copy._baseTextureUnit), + _shadowTextureUnit(copy._shadowTextureUnit), + _ambientBias(copy._ambientBias), + _textureSize(copy._textureSize) { - // create the camera - _camera = new osg::Camera; - - _camera->setCullCallback(new CameraCullCallback(this)); - - _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 viewport - _camera->setViewport(0,0,tex_width,tex_height); - - // 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(); - - float factor = 0.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 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); - } - + + void ShadowMap::setTextureUnit(unsigned int unit) { - _stateset = new osg::StateSet; - _stateset->setTextureAttributeAndModes(_textureUnit,_texture.get(),osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); - _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); - _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); - _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); - - _texgen = new osg::TexGen; + _shadowTextureUnit = unit; + } -#if 1 - osg::Program* program = new osg::Program; - _stateset->setAttribute(program); + void ShadowMap::setAmbientBias(const osg::Vec2& ambientBias) + { + _ambientBias = ambientBias; + } - if (_textureUnit==0) + 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); + + osg::Uniform* ambientBias = new osg::Uniform("osgShadow_ambientBias",_ambientBias); + _uniformList.push_back(ambientBias); + + } + + void ShadowMap::createShaders() + { + // if we are not given shaders, use the default + if( _shaderList.empty() ) { - osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture); - program->addShader(fragment_shader); + 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::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)_textureUnit); - _stateset->addUniform(shadowTextureSampler); + } } - else + } + + 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); + _texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_EDGE); + _texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_EDGE); + + // set up the render to texture camera. { - osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture); - program->addShader(fragment_shader); + // create the camera + _camera = new osg::Camera; - osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0); - _stateset->addUniform(baseTextureSampler); + _camera->setCullCallback(new CameraCullCallback(this)); + + _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 viewport + _camera->setViewport(0,0,_textureSize.x(),_textureSize.y()); + + // 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(); + + float factor = 0.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 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::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)_textureUnit); - _stateset->addUniform(shadowTextureSampler); } - - osg::Uniform* ambientBias = new osg::Uniform("ambientBias",_ambientBias); - _stateset->addUniform(ambientBias); + { + _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()); + } + + } + + _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 recieving 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) + { + lightpos = light->getPosition() * (*matrix); + lightDir = light->getDirection() * (*matrix); + } + else + { + lightpos = light->getPosition(); + lightDir = light->getDirection(); + } + + } + } + + 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) + { + + //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 - } - - _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 recieving 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; - - 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) - { - osg::RefMatrix* matrix = itr->second.get(); - if (matrix) lightpos = light->getPosition() * (*matrix); - else lightpos = light->getPosition(); - - selectLight = light; - } - } - - osg::Matrix eyeToWorld; - eyeToWorld.invert(*cv.getModelViewMatrix()); - - lightpos = lightpos * eyeToWorld; - - if (selectLight) - { - - // get the bounds of the model. - osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); - cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask()); + 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; - _shadowedScene->osg::Group::traverse(cbbv); - - osg::BoundingBox bb = cbbv.getBoundingBox(); - - if (lightpos[3]!=0.0) - { - osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z()); + geode->addDrawable( osg::createTexturedQuadGeometry( centerBase-widthVec*0.5f-depthVec*0.5f, + widthVec, depthVec) ); - float centerDistance = (position-bb.center()).length(); + osg::StateSet* stateset = geode->getOrCreateStateSet(); - float znear = centerDistance-bb.radius(); - float zfar = centerDistance+bb.radius(); - float zNearRatio = 0.001f; - if (znearsetMode(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); - float top = (bb.radius()/centerDistance)*znear; - float right = top; + //stateset->setTextureAttributeAndModes(_baseTextureUnit, new osg::Texture2D(osgDB::readImageFile("Images/lz.rgb"))); + stateset->setTextureAttributeAndModes(_baseTextureUnit,_texture.get(),osg::StateAttribute::ON); - _camera->setReferenceFrame(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)); - + //TODO might need to have a shader for correct display - // 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); - } - else - { - // make an orthographic projection - osg::Vec3 lightDir(lightpos.x(), lightpos.y(), lightpos.z()); - lightDir.normalize(); + camera->addChild(geode); - // 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(_textureUnit, cv.getModelViewMatrix(), _texgen.get()); + return camera; } + //////////////////////// End Debug Section - // reapply the original traversal mask - cv.setTraversalMask( traversalMask ); -} - -void ShadowMap::cleanSceneGraph() -{ -}