Hello Robert,

I've been trying to implement osgShadow::ShadowMap, using the old osgdepthshadow as a starting point.

I am attaching ShadowMap[.cpp] and testShadow.cpp[ based on osgshadow example ].

I hit a bit of a wall, and here are some of the points I'm not very clear on:

1. there is a Camera[PRE_RENDER] to RTT the depthMap, it's viewFrustum needs to be updated according to the light, but where is the appropriate call-back for it in the Update or in the Cull traversals ??
2. same for TexGenNode for applying the said depthMap
3. how do I add the Camera to the rendering ? (if I add it to ShadowedScene, there is a loop, since the sceneData of the Camera is ShadowedScene) 4. where is appropriate to add the TexGenNode (ShadowedScene seems like the candidate) ?

Right now I've turned off the depth comparing on the depthMap to see what is happening, and all I get is a black rectangle.

I've looked through the code for ShadowVolume, and I see you do some magic with the renderBins in Cull traversal, but I can't quite figure if I need to do something similar (I guess because I don't quite get what is happening there :)

I would really like to have this going, then I could use the nodeKit with the application we are working on ( I'll have to back-port it to osg 1.2, but that's not a big deal if I exclude ShadowVolume technique).

Regards
Mihai Radu
------------
cm-labs.com
#include <osg/ArgumentParser>

#include <osg/LightModel>
#include <osg/Depth>
#include <osg/BlendFunc>
#include <osg/Camera>
#include <osg/Stencil>
#include <osg/StencilTwoSided>
#include <osg/CullFace>
#include <osg/Geometry>
#include <osg/Switch>

#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/TerrainManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/StateSetManipulator>

#include <osgViewer/Viewer>
#include <osgViewer/StatsHandler>

#include <osgShadow/OccluderGeometry>
#include <osgShadow/ShadowedScene>
#include <osgShadow/ShadowVolume>
#include <osgShadow/ShadowMap>

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

#include <osg/Geode>
#include <osg/BlendFunc>

#include <iostream>

class ComputeBoundingBoxVisitor : public osg::NodeVisitor
{
public:
    ComputeBoundingBoxVisitor():
        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
    {
    }
    
    virtual void reset()
    {
        _matrixStack.clear();
        _bb.init();
    }
    
    osg::BoundingBox& getBoundingBox() { return _bb; }

    void getPolytope(osg::Polytope& polytope, float margin=0.1) const
    {
        float delta = _bb.radius()*margin;
        polytope.add( osg::Plane(0.0, 0.0, 1.0, -(_bb.zMin()-delta)) );
        polytope.add( osg::Plane(0.0, 0.0, -1.0, (_bb.zMax()+delta)) );

        polytope.add( osg::Plane(1.0, 0.0, 0.0, -(_bb.xMin()-delta)) );
        polytope.add( osg::Plane(-1.0, 0.0, 0.0, (_bb.xMax()+delta)) );

        polytope.add( osg::Plane(0.0, 1.0, 0.0, -(_bb.yMin()-delta)) );
        polytope.add( osg::Plane(0.0, -1.0, 0.0, (_bb.yMax()+delta)) );
    }
        
    void getBase(osg::Polytope& polytope, float margin=0.1) const
    {
        float delta = _bb.radius()*margin;
        polytope.add( osg::Plane(0.0, 0.0, 1.0, -(_bb.zMin()-delta)) );
    }
    
    void apply(osg::Node& node)
    {
        traverse(node);
    }
    
    void apply(osg::Transform& transform)
    {
        osg::Matrix matrix;
        if (!_matrixStack.empty()) matrix = _matrixStack.back();
        
        transform.computeLocalToWorldMatrix(matrix,this);
        
        pushMatrix(matrix);
        
        traverse(transform);
        
        popMatrix();
    }
    
    void apply(osg::Geode& geode)
    {
        for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
        {
            apply(geode.getDrawable(i));
        }
    }
    
    void pushMatrix(osg::Matrix& matrix)
    {
        _matrixStack.push_back(matrix);
    }
    
    void popMatrix()
    {
        _matrixStack.pop_back();
    }

    void apply(osg::Drawable* drawable)
    {
        if (_matrixStack.empty()) _bb.expandBy(drawable->getBound());
        else
        {
            osg::Matrix& matrix = _matrixStack.back();
            const osg::BoundingBox& dbb = drawable->getBound();
            if (dbb.valid())
            {
                _bb.expandBy(dbb.corner(0) * matrix);
                _bb.expandBy(dbb.corner(1) * matrix);
                _bb.expandBy(dbb.corner(2) * matrix);
                _bb.expandBy(dbb.corner(3) * matrix);
                _bb.expandBy(dbb.corner(4) * matrix);
                _bb.expandBy(dbb.corner(5) * matrix);
                _bb.expandBy(dbb.corner(6) * matrix);
                _bb.expandBy(dbb.corner(7) * matrix);
            }
        }
    }
    
protected:
    
    typedef std::vector<osg::Matrix> MatrixStack;

    MatrixStack         _matrixStack;
    osg::BoundingBox    _bb;
};



osg::Camera* makeHud(osg::Texture2D* tex)
{
 // set hud to render shadow texture, just for interest
#if 1   
        osg::Geode* geode = new osg::Geode;
        osg::Geometry* geom = 
osg::createTexturedQuadGeometry(osg::Vec3(0,0,0),osg::Vec3(100.0,0.0,0.0),osg::Vec3(0.0,100.0,0.0));
        
geom->getOrCreateStateSet()->setTextureAttributeAndModes(0,tex,osg::StateAttribute::ON);
        
geom->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
        geode->addDrawable(geom);
        
        osg::Camera* camera = new osg::Camera;

        // set the projection matrix
        camera->setProjectionMatrix(osg::Matrix::ortho2D(0,100,0,100));

        // set the view matrix    
        camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
        camera->setViewMatrix(osg::Matrix::identity());
        
        camera->setViewport(50,50,100,100);

        // only clear the depth buffer
        camera->setClearMask(GL_DEPTH_BUFFER_BIT);

        // draw subgraph after main camera view.
        camera->setRenderOrder(osg::Camera::POST_RENDER);

        camera->addChild(geode);
        
    
#else
    osg::Geode* geode = new osg::Geode();
    {
        osg::Geometry* geom = new osg::Geometry;

        osg::Vec3Array* vertices = new osg::Vec3Array;
        float depth = -0.1;
        vertices->push_back(osg::Vec3(0,512,depth));
        vertices->push_back(osg::Vec3(0,0,depth));
        vertices->push_back(osg::Vec3(512,0,depth));
        vertices->push_back(osg::Vec3(512,512,depth));
        geom->setVertexArray(vertices);

        osg::Vec3Array* normals = new osg::Vec3Array;
        normals->push_back(osg::Vec3(0.0f,0.0f,1.0f));
        geom->setNormalArray(normals);
        geom->setNormalBinding(osg::Geometry::BIND_OVERALL);

        osg::Vec4Array* colors = new osg::Vec4Array;
        colors->push_back(osg::Vec4(1.0f,1.0,0.8f,0.2f));
        geom->setColorArray(colors);
        geom->setColorBinding(osg::Geometry::BIND_OVERALL);

        geom->addPrimitiveSet(new osg::DrawArrays(GL_QUADS,0,4));
        
        osg::StateSet* stateset = geom->getOrCreateStateSet();
        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);

        geode->addDrawable(geom);
    }


    osg::StateSet* set =  geode->getOrCreateStateSet();
    set->setTextureAttributeAndModes(0, tex ,osg::StateAttribute::ON);
   

    osg::Camera* camera = new osg::Camera;

    // set the projection matrix
    camera->setProjectionMatrix(osg::Matrix::ortho2D(0,1280,0,1024));

    // 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);

    // draw subgraph after main camera view.
    camera->setRenderOrder(osg::Camera::POST_RENDER);

    camera->addChild(geode);
#endif
    return camera;

}


int main(int argc, char** argv)
{
    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc, argv);

    // set up the usage document, in case we need to print out how to use this 
program.
    
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() 
+ " is the example which demonstrates using of GL_ARB_shadow extension 
implemented in osg::Texture class");
    
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName());
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help", 
"Display this information");
    arguments.getApplicationUsage()->addCommandLineOption("--positionalLight", 
"Use a positional light.");
    arguments.getApplicationUsage()->addCommandLineOption("--directionalLight", 
"Use a direction light.");
    
arguments.getApplicationUsage()->addCommandLineOption("--addOccluderToScene", 
"Add the occluders geometry.");
    arguments.getApplicationUsage()->addCommandLineOption("--noUpdate", 
"Disable the updating the of light source.");
    arguments.getApplicationUsage()->addCommandLineOption("--base", "Add a base 
geometry to test shadows.");
    arguments.getApplicationUsage()->addCommandLineOption("--noShadow", 
"Disable the shadows.");
    arguments.getApplicationUsage()->addCommandLineOption("--two-sided", "Use 
two-sided stencil extension for shadow volumes.");
    arguments.getApplicationUsage()->addCommandLineOption("--two-pass", "Use 
two-pass stencil for shadow volumes.");

    // hint to tell viewer to request stencil buffer when setting up windows
    osg::DisplaySettings::instance()->setMinimumNumStencilBits(8);

    // construct the viewer.
    osgViewer::Viewer viewer;

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(std::cout);
        return 1;
    }

    // default to single threaded during dev work.
    viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
    
    while (arguments.read("--SingleThreaded")) 
viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
    while (arguments.read("--CullDrawThreadPerContext")) 
viewer.setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
    while (arguments.read("--DrawThreadPerContext")) 
viewer.setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
    while (arguments.read("--CullThreadPerCameraDrawThreadPerContext")) 
viewer.setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);


    bool postionalLight = false;
    while (arguments.read("--positionalLight")) postionalLight = true;
    while (arguments.read("--directionalLight")) postionalLight = false;

    bool updateLightPosition = true;
    while (arguments.read("--noUpdate")) updateLightPosition = false;

    bool createBase = false;
    while (arguments.read("--base")) createBase = true;


    int screenNum = -1;
    while (arguments.read("--screen", screenNum)) 
viewer.setUpViewOnSingleScreen(screenNum);

    bool ShadowMap = true;
    while (arguments.read("--ShadowMap")) ShadowMap = true;


    // set up the camera manipulators.
    {
        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = 
new osgGA::KeySwitchMatrixManipulator;

        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new 
osgGA::TrackballManipulator() );
        keyswitchManipulator->addMatrixManipulator( '2', "Flight", new 
osgGA::FlightManipulator() );
        keyswitchManipulator->addMatrixManipulator( '3', "Drive", new 
osgGA::DriveManipulator() );
        keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new 
osgGA::TerrainManipulator() );

        std::string pathfile;
        char keyForAnimationPath = '5';
        while (arguments.read("-p",pathfile))
        {
            osgGA::AnimationPathManipulator* apm = new 
osgGA::AnimationPathManipulator(pathfile);
            if (apm || !apm->valid()) 
            {
                unsigned int num = 
keyswitchManipulator->getNumMatrixManipulators();
                keyswitchManipulator->addMatrixManipulator( 
keyForAnimationPath, "Path", apm );
                keyswitchManipulator->selectMatrixManipulator(num);
                ++keyForAnimationPath;
            }
        }

        viewer.setCameraManipulator( keyswitchManipulator.get() );
    }


    // add the state manipulator
    viewer.addEventHandler( new 
osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );

    // add stats
    viewer.addEventHandler( new osgViewer::StatsHandler() );

    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
      arguments.writeErrorMessages(std::cout);
      return 1;
    }


    osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);
    if (!model)
    {
        return 1;
    }

    // get the bounds of the model.    
    ComputeBoundingBoxVisitor cbbv;
    model->accept(cbbv);
    osg::BoundingBox bb = cbbv.getBoundingBox();

    if (createBase)
    {
        osg::ref_ptr<osg::Group> newGroup = new osg::Group;
        newGroup->addChild(model.get());
        
        osg::Geode* geode = new osg::Geode;
        
        osg::Vec3 widthVec(bb.radius(), 0.0f, 0.0f);
        osg::Vec3 depthVec(0.0f, bb.radius(), 0.0f);
        osg::Vec3 centerBase( (bb.xMin()+bb.xMax())*0.5f, 
(bb.yMin()+bb.yMax())*0.5f, bb.zMin()-bb.radius()*0.1f );
        
        geode->addDrawable( osg::createTexturedQuadGeometry( 
centerBase-widthVec*1.5f-depthVec*1.5f, 
                                                             widthVec*3.0f, 
depthVec*3.0f) );
        newGroup->addChild(geode);
        
        model = newGroup.get();
    }

    osg::Vec4 lightpos;
    
    if (postionalLight)
    {
        lightpos.set(bb.center().x(), bb.center().y(), bb.zMax() + bb.radius()  
,1.0f);
    }
    else
    {
        lightpos.set(0.5f,0.25f,0.8f,0.0f);
    }


    osg::ref_ptr<osgShadow::ShadowedScene> shadowedScene = new 
osgShadow::ShadowedScene;
    osg::ref_ptr<osgShadow::ShadowMap> shadowMap = new osgShadow::ShadowMap;

    shadowedScene->setShadowTechnique(shadowMap.get());

    shadowedScene->addChild(model.get());

    osgShadow::ShadowMap* map = dynamic_cast<osgShadow::ShadowMap*>( 
shadowedScene->getShadowTechnique());

    osg::ref_ptr<osg::LightSource> ls = new osg::LightSource;

    ls->getLight()->setPosition(lightpos);

    map->setLight(ls.get());

    //osg::Camera* cam  = map->getCamera();
    //osg::Camera::BufferAttachmentMap bMap = cam->getBufferAttachmentMap();
    //osg::Camera::Attachment attach =  
(*bMap.find(osg::Camera::COLOR_BUFFER)).second;
    osg::ref_ptr<osg::Camera> _hud;

    osg::Texture2D* tex = map->getTexture();
    tex->setShadowComparison(false);

    if (! tex)
        exit(1);

    _hud = makeHud(tex);


    //shadowedScene->addChild(  map->getCamera() );

    shadowedScene->addChild(  map->getTexGen() );

    //shadowedScene->addChild( _hud.get() );



    shadowedScene->addChild(model.get());
    shadowedScene->addChild(ls.get());

    viewer.setSceneData(shadowedScene.get());
    
    // create the windows and run the threads.
    viewer.realize();

    // osgDB::writeNodeFile(*group,"test.osg");

    while (!viewer.done())
    {
        if (updateLightPosition)
        {
            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);
            }
            else
            {
                lightpos.set(sinf(t),cosf(t),1.0f,0.0f);
            }
            ls->getLight()->setPosition(lightpos);
        }

        viewer.frame();
    }
    
    return 0;
}
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield 
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * OpenSceneGraph Public License for more details.
*/

#include <osgShadow/ShadowMap>
#include <osgShadow/ShadowedScene>

#include <osg/Notify>
#include <osg/Texture2D>
#include <osg/TexGenNode>
#include <osg/PolygonOffset>
#include <osg/CullFace>
#include <osg/LightSource>
#include <osgSim/DOFTransform>
#include <osg/MatrixTransform>

#include <iomanip>

using namespace osgShadow;

ShadowMap::ShadowMap() :
_useLightPos(false)
{
    osg::notify(osg::NOTICE)<<"Warning: osgShadow::ShadowMap technique in 
development."<<std::endl;

    _textureHeight = 1024;
    _textureWidth = 1024;
    _textureUnit = 1;

    _position = osg::Vec3(5.0, 5.0, 0.0);
}

ShadowMap::ShadowMap(const ShadowMap& copy, const osg::CopyOp& copyop):
ShadowTechnique(copy,copyop)
{
}

void ShadowMap::init()
{
    if (!_shadowedScene) return;

    // create the depthMap texture
    _texture = new osg::Texture2D;

    _texture->setTextureSize(_textureHeight, _textureWidth);

    _texture->setInternalFormat(GL_DEPTH_COMPONENT);
    _texture->setShadowComparison(true);
    _texture->setShadowCompareFunc (osg::Texture::LEQUAL);
    _texture->setShadowTextureMode(osg::Texture::LUMINANCE);
    _texture->setShadowAmbient(0.2);
    _texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER );
    _texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER );

    _texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
    _texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);

    _texture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));

    /////////////////// create S_CameraNode
    _camera = new osg::Camera;

    _camera->setName("ShadowMap");

    _camera->setClearMask(GL_DEPTH_BUFFER_BIT);
    _camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
    // this turns off automatic computation of NEAR & FAR planes for the camera
    _camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);

    // set the CullMask to allow for non_occluder nodes
    _camera->setCullMask( _shadowedScene->getCastsShadowTraversalMask() );

    // set viewport
    _camera->setViewport(0,0,_textureHeight, _textureWidth);

    osg::StateSet*  _local_stateset = _camera->getOrCreateStateSet();

    _local_stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

    // PolygonOffset property to set the bias for shadow

    float factor = 1.85f;
    float units =  1.80f;

    osg::ref_ptr<osg::PolygonOffset> polygon_offset = new osg::PolygonOffset;
    polygon_offset->setFactor(factor);
    polygon_offset->setUnits(units);
    _local_stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON 
| osg::StateAttribute::OVERRIDE);
    _local_stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | 
osg::StateAttribute::OVERRIDE);

    osg::ref_ptr<osg::CullFace> cull_face = new osg::CullFace;
    cull_face->setMode(osg::CullFace::FRONT_AND_BACK);
    _local_stateset->setAttribute(cull_face.get(), osg::StateAttribute::ON | 
osg::StateAttribute::OVERRIDE);
    _local_stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | 
osg::StateAttribute::OVERRIDE);


    // set the shadowCamera to render before the main camera.
    _camera->setRenderOrder(osg::Camera::PRE_RENDER);
    //shadowCamera->setRenderOrder(osg::CameraNode::NESTED_RENDER);

    // tell the shadowCamera to use OpenGL frame buffer object where supported.
    _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);

    // attach the texture and use it as the depth buffer.
    _camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get());
    
    _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);

    _camera->addChild(_shadowedScene);

    // create TexGen node
    _texGen = new osg::TexGenNode;
    _texGen->setTextureUnit(_textureUnit);
    /*
    // find the entity the Light is attached-to
    VxEntity* ent;

    osg::Node* ln = NULL;
    ln = (osg::Node*)VxSceneGraphManager::find(m_Light->name);
    if (!ln)
    VxFatalError(0,"Ooops couldn't find Light %s\n", m_Light->name.c_str());
    else
    {
    osg::Light* light  = dynamic_cast<osg::LightSource*>(ln)->getLight();
    VxInfo(1,"VxShadowMap:: shadow caster GL lightID 
%d\n",light->getLightNum());
    // TODO set the lightID of the shadowCasting light here ???
    ent = getParentEntityfromNode(ln);
    }
    // found the part
    if ( ent )
    {
    const osg::Vec3 lightPosOffset(m_Light->attachementInfo.position[0], 
m_Light->attachementInfo.position[1], m_Light->attachementInfo.position[2]);

    // set an update callback to keep moving the camera and tex gen in the 
right direction.
    _Camera->setUpdateCallback( new 
UpdateCameraAndTexGenCallback(lightPosOffset, ent, _TexGen.get()) );
    }
    */

    // enable shadowTexture on the 3Dscene
    osg::StateSet* stateset = _shadowedScene->getOrCreateStateSet();
    stateset->setTextureAttributeAndModes(_textureUnit, _texture.get() 
,osg::StateAttribute::ON);
    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);
    //stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON| 
StateAttribute::OVERRIDE);

}


void ShadowMap::update(osg::NodeVisitor& nv)
{

    _shadowedScene->osg::Group::traverse(nv);

}

void ShadowMap::cull(osgUtil::CullVisitor& cv)
{
    //osg::notify(osg::NOTICE)<<className()<<"::cull(osgUtl::CullVisitor&) in 
development."<<std::endl;
    
    // now compute the camera's view and projection matrix to point at the 
shadower (the camera's children)

    //TODO cull the scene based on the main camera or LightNode MR
    osg::BoundingSphere bs;
    // Need to unfold the scene to take in account NodeMask(s)

    for(unsigned int i=0; i<_shadowedScene->getNumChildren(); ++i)
    {
        if ( _shadowedScene->getChild(i)->getNodeMask() & 
_shadowedScene->getCastsShadowTraversalMask() )
        {
#ifdef _DEBUG
            osg::notify(osg::NOTICE)<<className()<< " _camera bounding box exp 
with child " << i << std::endl;
#endif
            bs.expandBy(_shadowedScene->getChild(i)->getBound());
        }
    }

    if (!bs.valid())
    {
        osg::notify(osg::INFO) << "bb invalid"<<_camera.get()<<std::endl;
        return;
    }
#ifdef _DEBUG
    osg::notify(osg::NOTICE)<<className()<< std::setprecision(6) <<" _camera 
bounding box r-x,y,z" << std::setw(10) << bs.radius() << std::setw(10) << 
(float)bs.center().x() << std::setw(10) <<  (float)bs.center().y() << 
std::setw(10) << (float)bs.center().z() <<std::endl;

    //VxWarning(0, "ShadowMap: CameraNode bounding box r:%.2f x:%.2f y:%.2f 
z:%.2f.\n",bs.radius(), bs.center().x(), bs.center().y(),bs.center().z() );
#endif

    if(_useLightPos)
    {
        osg::Vec4 _positionU = _light->getLight()->getPosition();
        if( _positionU.w() != 0.0)
            _position.set(_positionU.x()/_positionU.w(), 
_positionU.y()/_positionU.w(), _positionU.z()/_positionU.w());
        else
            _position.set(_positionU.x(), _positionU.y(), _positionU.z());

    }
    float centerDistance = (_position-bs.center()).length();

    float znear = centerDistance-bs.radius();
    float zfar  = centerDistance+bs.radius();
    float zNearRatio = 0.001f;
    if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;

#if 0
    // hack to illustrate the precision problems of excessive gap between near 
far range.
    znear = 0.00001*zfar;
#endif
    float top   = (bs.radius()/centerDistance)*znear;
    float right = top;


    _camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar);
    
_camera->setViewMatrixAsLookAt(_position,bs.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->getTexGen()->setMode(osg::TexGen::EYE_LINEAR);
    _texGen->getTexGen()->setPlanesFromMatrix(MVPT);

    //_camera->traverse(cv);
    _shadowedScene->osg::Group::traverse(cv);
}
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield 
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * OpenSceneGraph Public License for more details.
*/

#ifndef OSGSHADOW_SHADOWEDTEXTURE
#define OSGSHADOW_SHADOWEDTEXTURE 1

#include <osg/Camera>

#include <osgShadow/ShadowTechnique>

namespace osgShadow {
    class osg::Texture2D;
    class osg::TexGenNode;

/** ShadowedTexture provides an implementation of shadow textures.*/
class OSGSHADOW_EXPORT ShadowMap : public ShadowTechnique
{
    public :
        ShadowMap();

        ShadowMap(const ShadowMap& es, const osg::CopyOp& 
copyop=osg::CopyOp::SHALLOW_COPY);
            
        META_Object(osgShadow, ShadowMap);
        
        /** initialize the ShadowedScene and local cached data structures.*/
        virtual void init();

        /** run the update traversal of the ShadowedScene and update any loca 
chached data structures.*/
        virtual void update(osg::NodeVisitor& nv);

        /** run the cull traversal of the ShadowedScene and set up the 
rendering for this ShadowTechnique.*/
        virtual void cull(osgUtil::CullVisitor& cv);


        inline osg::Camera* getCamera() { 
            if(_dirty)
                init();
            return _camera.get(); };
        inline osg::Texture2D* getTexture() { 
            if(_dirty)
                init();
            return _texture.get(); };
         inline osg::TexGenNode* getTexGen() { 
            if(_dirty)
                init();
            return _texGen.get(); };

            inline void setLight(osg::LightSource* light) { _light = light; 
_useLightPos=true;};


    protected :

        virtual ~ShadowMap() {}
    private :

        unsigned int    _textureHeight;
        unsigned int    _textureWidth;
        unsigned int    _textureUnit;
        osg::Vec3       _position;

        bool                _useLightPos;
        osg::LightSource*   _light;

        osg::ref_ptr<osg::Camera>       _camera;
        osg::ref_ptr<osg::Texture2D>    _texture;
        osg::ref_ptr<osg::TexGenNode>   _texGen;

        
};

}

#endif
_______________________________________________
osg-users mailing list
[email protected]
http://openscenegraph.net/mailman/listinfo/osg-users
http://www.openscenegraph.org/

Reply via email to