Hu Mihai,

To get the position of the light source you do what the
osgShadow::ShadowVolume technique does and let the traversal happen
for the scene then get the PositionalStateContainer from the
RenderStage that the cull traversal has populated, then build the view
and projection matrix according to this position.

Robert.

On 2/13/07, Mihai Radu <[EMAIL PROTECTED]> wrote:
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/

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

Reply via email to