Show
Ignore:
Timestamp:
02/19/07 15:20:18 (8 years ago)
Author:
robert
Message:

Implemented basic ShadowMap? technique

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • OpenSceneGraph/trunk/src/osgShadow/ShadowMap.cpp

    r5641 r6233  
    1313 
    1414#include <osgShadow/ShadowMap> 
     15#include <osgShadow/ShadowedScene> 
    1516#include <osg/Notify> 
     17#include <osg/ComputeBoundsVisitor> 
     18#include <osg/PolygonOffset> 
     19#include <osg/CullFace> 
     20#include <osg/io_utils> 
    1621 
    1722using namespace osgShadow; 
    1823 
    19 ShadowMap::ShadowMap()     
    20 { 
    21     osg::notify(osg::NOTICE)<<"Warning: osgShadow::ShadowMap technique not implemented yet."<<std::endl; 
     24 
     25////////////////////////////////////////////////////////////////// 
     26// fragment shader 
     27// 
     28char fragmentShaderSource_noBaseTexture[] =  
     29    "uniform sampler2DShadow shadowTexture; \n" 
     30    "uniform vec2 ambientBias; \n" 
     31    "\n" 
     32    "void main(void) \n" 
     33    "{ \n" 
     34    "    gl_FragColor = gl_Color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[0] ) * ambientBias.y); \n" 
     35    "}\n"; 
     36 
     37////////////////////////////////////////////////////////////////// 
     38// fragment shader 
     39// 
     40char fragmentShaderSource_withBaseTexture[] =  
     41    "uniform sampler2D baseTexture; \n" 
     42    "uniform sampler2DShadow shadowTexture; \n" 
     43    "uniform vec2 ambientBias; \n" 
     44    "\n" 
     45    "void main(void) \n" 
     46    "{ \n" 
     47    "    vec4 color = gl_Color * texture2D( baseTexture, gl_TexCoord[0].xy ); \n" 
     48    "    gl_FragColor = color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[1] ) * ambientBias.y); \n" 
     49    "}\n"; 
     50 
     51ShadowMap::ShadowMap(): 
     52    _textureUnit(1) 
     53{ 
     54    osg::notify(osg::NOTICE)<<"Warning: osgShadow::ShadowMap technique is in development."<<std::endl; 
    2255} 
    2356 
    2457ShadowMap::ShadowMap(const ShadowMap& copy, const osg::CopyOp& copyop): 
    25     ShadowTechnique(copy,copyop) 
    26 { 
    27 } 
     58    ShadowTechnique(copy,copyop), 
     59    _textureUnit(copy._textureUnit) 
     60{ 
     61} 
     62 
     63void ShadowMap::setTextureUnit(unsigned int unit) 
     64{ 
     65    _textureUnit = unit; 
     66} 
     67 
     68void ShadowMap::init() 
     69{ 
     70    if (!_shadowedScene) return; 
     71 
     72    unsigned int tex_width = 1024; 
     73    unsigned int tex_height = 1024; 
     74     
     75    _texture = new osg::Texture2D; 
     76    _texture->setTextureSize(tex_width, tex_height); 
     77    _texture->setInternalFormat(GL_DEPTH_COMPONENT); 
     78    _texture->setShadowComparison(true); 
     79    _texture->setShadowTextureMode(osg::Texture2D::LUMINANCE); 
     80    _texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); 
     81    _texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); 
     82 
     83    // set up the render to texture camera. 
     84    { 
     85        // create the camera 
     86        _camera = new osg::Camera; 
     87 
     88        _camera->setCullCallback(new CameraCullCallback(this)); 
     89 
     90        _camera->setClearMask(GL_DEPTH_BUFFER_BIT); 
     91        //_camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 
     92        _camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); 
     93        _camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); 
     94 
     95        // set viewport 
     96        _camera->setViewport(0,0,tex_width,tex_height); 
     97 
     98        // set the camera to render before the main camera. 
     99        _camera->setRenderOrder(osg::Camera::PRE_RENDER); 
     100 
     101        // tell the camera to use OpenGL frame buffer object where supported. 
     102        _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); 
     103        //_camera->setRenderTargetImplementation(osg::Camera::SEPERATE_WINDOW); 
     104 
     105        // attach the texture and use it as the color buffer. 
     106        _camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get()); 
     107 
     108        osg::StateSet* stateset = _camera->getOrCreateStateSet(); 
     109 
     110        float factor = 0.0f; 
     111        float units = 1.0f; 
     112 
     113        osg::ref_ptr<osg::PolygonOffset> polygon_offset = new osg::PolygonOffset; 
     114        polygon_offset->setFactor(factor); 
     115        polygon_offset->setUnits(units); 
     116        stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); 
     117        stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); 
     118 
     119        osg::ref_ptr<osg::CullFace> cull_face = new osg::CullFace; 
     120        cull_face->setMode(osg::CullFace::FRONT); 
     121        stateset->setAttribute(cull_face.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); 
     122        stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); 
     123         
     124    } 
     125     
     126    { 
     127        _stateset = new osg::StateSet;         
     128        _stateset->setTextureAttributeAndModes(_textureUnit,_texture.get(),osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); 
     129        _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); 
     130        _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); 
     131        _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); 
     132        _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); 
     133         
     134        _texgen = new osg::TexGen; 
     135 
     136#if 1 
     137        osg::Program* program = new osg::Program; 
     138        _stateset->setAttribute(program); 
     139 
     140        if (_textureUnit==0) 
     141        { 
     142            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture); 
     143            program->addShader(fragment_shader); 
     144 
     145            osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)_textureUnit); 
     146            _stateset->addUniform(shadowTextureSampler); 
     147        } 
     148        else 
     149        { 
     150            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture); 
     151            program->addShader(fragment_shader); 
     152 
     153            osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0); 
     154            _stateset->addUniform(baseTextureSampler); 
     155 
     156            osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)_textureUnit); 
     157            _stateset->addUniform(shadowTextureSampler); 
     158        } 
     159         
     160        osg::Uniform* ambientBias = new osg::Uniform("ambientBias",osg::Vec2(0.3f,1.2f)); 
     161        _stateset->addUniform(ambientBias); 
     162 
     163#endif 
     164    } 
     165     
     166    _dirty = false; 
     167} 
     168 
     169 
     170void ShadowMap::update(osg::NodeVisitor& nv) 
     171{ 
     172    _shadowedScene->osg::Group::traverse(nv); 
     173} 
     174 
     175void ShadowMap::cull(osgUtil::CullVisitor& cv) 
     176{ 
     177    // record the traversal mask on entry so we can reapply it later. 
     178    unsigned int traversalMask = cv.getTraversalMask(); 
     179 
     180    osgUtil::RenderStage* orig_rs = cv.getRenderStage(); 
     181 
     182    // do traversal of shadow recieving scene which does need to be decorated by the shadow map 
     183    { 
     184        cv.pushStateSet(_stateset.get()); 
     185     
     186        _shadowedScene->osg::Group::traverse(cv); 
     187         
     188        cv.popStateSet(); 
     189 
     190    } 
     191     
     192    // need to compute view frustum for RTT camera. 
     193    // 1) get the light position 
     194    // 2) get the center and extents of the view frustum 
     195 
     196    const osg::Light* selectLight = 0; 
     197    osg::Vec4 lightpos; 
     198 
     199    osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList(); 
     200    for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin(); 
     201        itr != aml.end(); 
     202        ++itr) 
     203    { 
     204        const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get()); 
     205        if (light) 
     206        { 
     207            osg::RefMatrix* matrix = itr->second.get(); 
     208            if (matrix) lightpos = light->getPosition() * (*matrix); 
     209            else lightpos = light->getPosition(); 
     210 
     211            selectLight = light; 
     212        } 
     213    } 
     214     
     215    osg::Matrix eyeToWorld; 
     216    eyeToWorld.invert(cv.getModelViewMatrix()); 
     217     
     218    lightpos = lightpos * eyeToWorld; 
     219 
     220    if (selectLight) 
     221    { 
     222 
     223        // get the bounds of the model.     
     224        osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); 
     225        cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask()); 
     226         
     227        _shadowedScene->osg::Group::traverse(cbbv); 
     228         
     229        osg::BoundingBox bb = cbbv.getBoundingBox(); 
     230         
     231        if (lightpos[3]!=0.0) 
     232        { 
     233            osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z()); 
     234 
     235            float centerDistance = (position-bb.center()).length(); 
     236 
     237            float znear = centerDistance-bb.radius(); 
     238            float zfar  = centerDistance+bb.radius(); 
     239            float zNearRatio = 0.001f; 
     240            if (znear<zfar*zNearRatio) znear = zfar*zNearRatio; 
     241 
     242            float top   = (bb.radius()/centerDistance)*znear; 
     243            float right = top; 
     244 
     245            _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); 
     246            _camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar); 
     247            _camera->setViewMatrixAsLookAt(position,bb.center(),osg::Vec3(0.0f,1.0f,0.0f)); 
     248             
     249 
     250            // compute the matrix which takes a vertex from local coords into tex coords 
     251            // will use this later to specify osg::TexGen.. 
     252            osg::Matrix MVPT = _camera->getViewMatrix() *  
     253                               _camera->getProjectionMatrix() * 
     254                               osg::Matrix::translate(1.0,1.0,1.0) * 
     255                               osg::Matrix::scale(0.5f,0.5f,0.5f); 
     256                                
     257            _texgen->setMode(osg::TexGen::EYE_LINEAR); 
     258            _texgen->setPlanesFromMatrix(MVPT); 
     259        } 
     260 
     261 
     262        cv.setTraversalMask( traversalMask &  
     263                             getShadowedScene()->getCastsShadowTraversalMask() ); 
     264 
     265        // do RTT camera traversal 
     266        _camera->accept(cv); 
     267 
     268        orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(_textureUnit, &cv.getModelViewMatrix(), _texgen.get()); 
     269    } 
     270 
     271 
     272    // reapply the original traversal mask 
     273    cv.setTraversalMask( traversalMask ); 
     274} 
     275 
     276void ShadowMap::cleanSceneGraph() 
     277{ 
     278}