Sorry, first version was an odd version. this works, but not yet perfect.
Enjoy the weekend :-) May i will be able to work on this project monday.

/adegli

2007/8/4, Adrian Egli <[EMAIL PROTECTED]>:
>
> Hi all
>
> i am currently working on PSSM (parallel splited shadow map)
> Implementation for the OpenSceneGraph osgShadow library. Here is my first
> part of the current implementation, but
> i need help. May another guy can see whats wrong in this prototypic
> impelementation, unfrotunatelly it doesn't work as expected.
>
> Please support me, and i hope there is an other guy answering this topic
> than robert. robert is quit in hurry at this moment.
>
> /adegli
>
> --
> ********************************************
> Adrian Egli
>



-- 
********************************************
Adrian Egli
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield 
*
* This application is open source and may be redistributed and/or modified   
* freely and without restriction, both in commericial and non commericial 
applications,
* as long as this copyright notice is maintained.
* 
* This application 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.
*/

#include <osgDB/ReadFile>
#include <osgUtil/Optimizer>
#include <osg/CoordinateSystemNode>

#include <osg/Switch>
#include <osgText/Text>
#include <osg/MatrixTransform>
#include <osg/Projection>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>

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

#include <osg/ComputeBoundsVisitor>
#include <osg/ShapeDrawable>
#include <osg/Geometry>

#include <osgShadow/ShadowedScene>
#include "ShadowPSSM.h"


#include <iostream>

const int ReceivesShadowTraversalMask = 0x1;
const int CastsShadowTraversalMask = 0x2;
const int MAX_SPLIT_TEXTURES = 3;
const int size_display_debug_texture = 150;

osg::Node* createBase(const osg::Vec3& center,float radius)
{

        osg::Geode* geode = new osg::Geode;

        osg::HeightField* grid = new osg::HeightField;
        grid->allocate(2,2);
        grid->setOrigin(center+osg::Vec3(-radius*10.0,-radius*10.0,0.0));
        grid->setXInterval(radius*20.0);
        grid->setYInterval(radius*20.0);

        grid->setHeight(0,0,0);
        grid->setHeight(0,1,0);
        grid->setHeight(1,0,0);
        grid->setHeight(1,1,0);
        
        geode->addDrawable(new osg::ShapeDrawable(grid));

        osg::Group* group = new osg::Group;
        group->addChild(geode);

        return group;

}


int main(int argc, char** argv)
{

        putenv("OSG_WINDOW=500 250 512 512");

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

        
arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
        
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+"
 is the standard OpenSceneGraph example which loads and visualises 3d models.");
        
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+"
 [options] filename ...");
        arguments.getApplicationUsage()->addCommandLineOption("--image 
<filename>","Load an image and render it on a quad");
        arguments.getApplicationUsage()->addCommandLineOption("--dem 
<filename>","Load an image/DEM and render it on a HeightField");
        arguments.getApplicationUsage()->addCommandLineOption("-h or 
--help","Display command line parameters");
        
arguments.getApplicationUsage()->addCommandLineOption("--help-env","Display 
environmental variables available");
        
arguments.getApplicationUsage()->addCommandLineOption("--help-keys","Display 
keyboard & mouse bindings available");
        
arguments.getApplicationUsage()->addCommandLineOption("--help-all","Display all 
command line, env vars and keyboard & mouse bindings.");
        
arguments.getApplicationUsage()->addCommandLineOption("--SingleThreaded","Select
 SingleThreaded threading model for viewer.");
        
arguments.getApplicationUsage()->addCommandLineOption("--CullDrawThreadPerContext","Select
 CullDrawThreadPerContext threading model for viewer.");
        
arguments.getApplicationUsage()->addCommandLineOption("--DrawThreadPerContext","Select
 DrawThreadPerContext threading model for viewer.");
        
arguments.getApplicationUsage()->addCommandLineOption("--CullThreadPerCameraDrawThreadPerContext","Select
 CullThreadPerCameraDrawThreadPerContext threading model for viewer.");
        
arguments.getApplicationUsage()->addCommandLineOption("--NO-DEBUG","Switch off 
displaying the PSSM Textures");

        // if user request help write it out to cout.
        bool helpAll = arguments.read("--help-all");
        unsigned int helpType = ((helpAll || arguments.read("-h") || 
arguments.read("--help"))? osg::ApplicationUsage::COMMAND_LINE_OPTION : 0 ) |
                ((helpAll ||  arguments.read("--help-env"))? 
osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE : 0 ) |
                ((helpAll ||  arguments.read("--help-keys"))? 
osg::ApplicationUsage::KEYBOARD_MOUSE_BINDING : 0 );
        if (helpType)
        {
                arguments.getApplicationUsage()->write(std::cout, helpType);
                return 1;
        }

        osgViewer::Viewer viewer(arguments);

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

        if (arguments.argc()<=1)
        {
                
arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
                return 1;
        }
 
        bool createBackgroundContextForCompiling = false;
        while (arguments.read("--bc")) { createBackgroundContextForCompiling = 
true; }

        bool createBackgroundThreadsForCompiling = false;
        while (arguments.read("--bt")) { createBackgroundContextForCompiling = 
true; createBackgroundThreadsForCompiling = 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 the thread model handler
        viewer.addEventHandler(new osgViewer::ThreadingHandler);

        // add the window size toggle handler
        viewer.addEventHandler(new osgViewer::WindowSizeHandler);

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

        // add the help handler
        viewer.addEventHandler(new 
osgViewer::HelpHandler(arguments.getApplicationUsage()));

        // add the record camera path handler
        viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);

        // prepare shadow
        osg::Group* veryRootGroup   = new osg::Group;
        bool non_debug=false;
        osg::Geode* geoHolders[MAX_SPLIT_TEXTURES];
        while (arguments.read("--NO-DEBUG")) {non_debug=true; }
        if ( ! non_debug ){
                for ( int i = 0;i<MAX_SPLIT_TEXTURES;i++ ){
                        osg::Geode* geode = new osg::Geode;
                        osg::Geometry* geom = 
osg::createTexturedQuadGeometry(osg::Vec3(2,2,0),osg::Vec3(196.0,0.0,0.0),osg::Vec3(0.0,196.0,0.0));
                        
geom->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
                        geoHolders[i]=geode;
                        geode->addDrawable(geom);
                        // create a camera to set up the projection and model 
view matrices, and the subgraph to drawn in the HUD
                        osg::Camera* camera = new osg::Camera;
                        // set the projection matrix
                        
camera->setProjectionMatrix(osg::Matrix::ortho2D(0,200,0,200));
                        // set the view matrix    
                        camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
                        camera->setViewMatrix(osg::Matrix::identity());
                        // only clear the depth buffer
                        camera->setClearMask(GL_COLOR_BUFFER_BIT);
                        camera->setClearColor(osg::Vec4(0.0,1.0,1.0,1.0));
                        // 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);
                        
camera->setViewport(50,600-i*(size_display_debug_texture+2),size_display_debug_texture,size_display_debug_texture);
                        camera->addChild(geode);
                        veryRootGroup->addChild(camera);

                }
        }

        osg::ref_ptr<osgShadow::ShadowedScene> shadowedScene = new 
osgShadow::ShadowedScene;
        
shadowedScene->setReceivesShadowTraversalMask(ReceivesShadowTraversalMask);
        shadowedScene->setCastsShadowTraversalMask(CastsShadowTraversalMask);

        osg::ref_ptr<osgShadow::ShadowPSSM> pssm;
        if ( non_debug ) {
                pssm = new osgShadow::ShadowPSSM();
        } else {
                pssm= new osgShadow::ShadowPSSM(geoHolders,MAX_SPLIT_TEXTURES);
        }
        shadowedScene->setShadowTechnique(pssm.get());

        // load the data
        osg::ref_ptr<osg::Group> modelRoot   = new osg::Group;
        osg::ref_ptr<osg::Node>  loadedModel = osgDB::readNodeFiles(arguments);
        if (!loadedModel) 
        {
                std::cout << arguments.getApplicationName() <<": No data 
loaded" << std::endl;
                osg::Node* basePlane = createBase(osg::Vec3(0,0,0),100);
                modelRoot->addChild(basePlane);
                
basePlane->setNodeMask(shadowedScene->getReceivesShadowTraversalMask());

        } else {
                osg::Vec3 
center(0,0,0);//0.5*-loadedModel->getBound().radius()); 
                center = center+loadedModel->getBound().center();
                osg::Node* basePlane = 
createBase(center,loadedModel->getBound().radius());
                modelRoot->addChild(loadedModel.get());
                //modelRoot->addChild(basePlane);
        }

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

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


        // optimize the scene graph, remove redundant nodes and state etc.
        osgUtil::Optimizer optimizer;
        optimizer.optimize(modelRoot.get());


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

        osg::Vec4 lightpos;
        // get the bounds of the model.    
        osg::ComputeBoundsVisitor cbbv;
        modelRoot->accept(cbbv);
        osg::BoundingBox bb = cbbv.getBoundingBox();
        lightpos.set(bb.center().x() + bb.radius(), bb.center().y() + 
bb.radius(), bb.zMax() + 2*bb.radius()  ,1.0f);
    //lightpos.set(bb.center().x(), bb.center().y(), bb.zMax() + bb.radius()  
,1.0f);   

        ls->getLight()->setPosition(lightpos);
        if (arguments.read("--coloured-light"))
        {
                ls->getLight()->setAmbient(osg::Vec4(1.0,0.0,0.0,1.0));
                ls->getLight()->setDiffuse(osg::Vec4(0.0,1.0,0.0,1.0));
        }
        else
        {
                ls->getLight()->setAmbient(osg::Vec4(0.2,0.2,0.2,1.0));
                ls->getLight()->setDiffuse(osg::Vec4(0.8,0.8,0.8,1.0));
        }

        shadowedScene->addChild(modelRoot.get());
        shadowedScene->addChild(ls.get());
        veryRootGroup->addChild(shadowedScene.get());
        viewer.setSceneData( veryRootGroup );















        viewer.realize();

        if (createBackgroundContextForCompiling)
        {

                int numProcessors = OpenThreads::GetNumberOfProcessors();
                int processNum = 0;

                for(unsigned int i=0; i<= 
osg::GraphicsContext::getMaxContextID(); ++i)
                {
                        osg::GraphicsContext* gc = 
osg::GraphicsContext::getOrCreateCompileContext(i);

                        if (gc && createBackgroundThreadsForCompiling)
                        {
                                gc->createGraphicsThread();
                                
gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors);
                                gc->getGraphicsThread()->startThread();

                                ++processNum;
                        }
                }
        }


        while (!viewer.done())
        {
                if (true)
                {
                        float t = viewer.getFrameStamp()->getSimulationTime();
                        lightpos.set(bb.center().x()+sinf(t)*bb.radius(), 
bb.center().y() + cosf(t)*bb.radius(), bb.zMax() + 2*bb.radius()  ,1.0f);
                        ls->getLight()->setPosition(lightpos);
                }

                viewer.frame();
        } 


        //viewer.run();

}
 
#include "ShadowPSSM.h"

#include <osgShadow/ShadowedScene>
#include <osg/Notify>
#include <osg/ComputeBoundsVisitor>
#include <osg/PolygonOffset>
#include <osg/CullFace>
#include <osg/io_utils>
#include <iostream>
#include <sstream>
#include <osg/Geode>
#include <osg/Geometry>
#include <osgDB/ReadFile>

using namespace osgShadow;



//////////////////////////////////////////////////////////////////
// fragment shader
//
static const char fragmentShaderSource_noBaseTexture[] = 
"uniform sampler2DShadow shadowTexture0; \n"
"uniform sampler2DShadow shadowTexture1; \n"
"uniform sampler2DShadow shadowTexture2; \n"
"uniform vec2 ambientBias0; \n"
"uniform vec2 ambientBias1; \n"
"uniform vec2 ambientBias2; \n"
"\n"
"void main(void) \n"
"{ \n"
"    vec4 shadow =  vec4(0,0,(ambientBias0.x + shadow2DProj( shadowTexture0, 
gl_TexCoord[0]).x * ambientBias0.y),0); \n"
"    shadow      = shadow    + vec4(0, (ambientBias1.x + shadow2DProj( 
shadowTexture1, gl_TexCoord[1]).y * ambientBias1.y),0,0); \n"
"    shadow      = shadow    + vec4((ambientBias2.x + shadow2DProj( 
shadowTexture2, gl_TexCoord[2]).z * ambientBias2.y),0,0,0); \n"
"    float v     = (1.0*shadow.x+2.0*shadow.y+4.0*shadow.z)/7.0;\n"
"    gl_FragColor = gl_Color*(clamp(v,0.0,1.0)*0.5+0.5); \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";


// split scheme
unsigned int NUM_SPLITS            = 3;
static unsigned int TEXTURE_RESOLUTION = 1024;
static int SPLITSCHEME=1;


// clamp variables of any type
template<class Type> inline Type Clamp(Type A, Type Min, Type Max) {
        if(A<Min) return Min;
        if(A>Max) return Max;
        return A;
}

#define min(a,b)            (((a) < (b)) ? (a) : (b))
#define max(a,b)            (((a) > (b)) ? (a) : (b))


ShadowPSSM::ShadowPSSM(osg::Geode** gr, int icountplanes){
        _displayTexturesGroupingNode = gr;
        NUM_SPLITS = icountplanes;
}

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


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

    
        unsigned int iCamerasMax=NUM_SPLITS;
        for (unsigned int iCameras=0;iCameras<iCamerasMax;iCameras++)
        {
                PSSMShadowSplitTexture pssmShadowSplitTexture;

                pssmShadowSplitTexture._textureUnit = iCameras;
                pssmShadowSplitTexture._ambientBias = osg::Vec2(0.8,0.2);
                        
                // set up the texture to render into
                {
                        pssmShadowSplitTexture._texture = new osg::Texture2D;
                        
pssmShadowSplitTexture._texture->setTextureSize(TEXTURE_RESOLUTION, 
TEXTURE_RESOLUTION);
                        
pssmShadowSplitTexture._texture->setInternalFormat(GL_DEPTH_COMPONENT);
                        
pssmShadowSplitTexture._texture->setShadowComparison(true);
                        
pssmShadowSplitTexture._texture->setShadowTextureMode(osg::Texture2D::LUMINANCE);
                        
pssmShadowSplitTexture._texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
                        
pssmShadowSplitTexture._texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
                }
                // set up the render to texture camera.
                {
                        // create the camera
                        pssmShadowSplitTexture._camera = new osg::Camera;

                        pssmShadowSplitTexture._camera->setCullCallback(new 
CameraCullCallback(this));

                        
pssmShadowSplitTexture._camera->setClearMask(GL_DEPTH_BUFFER_BIT);
                        
pssmShadowSplitTexture._camera->setClearColor(osg::Vec4(1.0,1.0,1.0,1.0));
                
                        
pssmShadowSplitTexture._camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);

                        // set viewport
                        
pssmShadowSplitTexture._camera->setViewport(0,0,TEXTURE_RESOLUTION,TEXTURE_RESOLUTION);

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

                        // tell the camera to use OpenGL frame buffer object 
where supported.
                        
pssmShadowSplitTexture._camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
 
                        // attach the texture and use it as the color buffer.
                        
pssmShadowSplitTexture._camera->attach(osg::Camera::DEPTH_BUFFER, 
pssmShadowSplitTexture._texture.get());

                        osg::StateSet* stateset = 
pssmShadowSplitTexture._camera->getOrCreateStateSet();

                        float factor = .0;
                        float units  = 1.0;

                        osg::ref_ptr<osg::PolygonOffset> 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<osg::CullFace> cull_face = new 
osg::CullFace;
                        cull_face->setMode(osg::CullFace::BACK);
                        stateset->setAttribute(cull_face.get(), 
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
                        stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON 
| osg::StateAttribute::OVERRIDE);
                }
                
                // set up stateset and append texture, texGen ,...
                {
                        pssmShadowSplitTexture._stateset = new osg::StateSet;   
     
                        
pssmShadowSplitTexture._stateset->setTextureAttributeAndModes(pssmShadowSplitTexture._textureUnit,pssmShadowSplitTexture._texture.get(),osg::StateAttribute::ON
 | osg::StateAttribute::OVERRIDE);
                        
pssmShadowSplitTexture._stateset->setTextureMode(pssmShadowSplitTexture._textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
                        
pssmShadowSplitTexture._stateset->setTextureMode(pssmShadowSplitTexture._textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
                        
pssmShadowSplitTexture._stateset->setTextureMode(pssmShadowSplitTexture._textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
                        
pssmShadowSplitTexture._stateset->setTextureMode(pssmShadowSplitTexture._textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON);

                        pssmShadowSplitTexture._texgen = new osg::TexGen;
                }
                
                // set up shader (GLSL)
                if ( 1 ) {
                        osg::Program* program = new osg::Program;
                        pssmShadowSplitTexture._stateset->setAttribute(program);

                        osg::Shader* fragment_shader = new 
osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture);
                        program->addShader(fragment_shader);

                        std::stringstream strST; strST << "shadowTexture" << 
pssmShadowSplitTexture._textureUnit;
                        osg::Uniform* shadowTextureSampler = new 
osg::Uniform(strST.str().c_str(),(int)(pssmShadowSplitTexture._textureUnit));
                        
pssmShadowSplitTexture._stateset->addUniform(shadowTextureSampler);

                        std::stringstream strAB; strAB << "ambientBias" << 
pssmShadowSplitTexture._textureUnit;
                        osg::Uniform* ambientBias = new 
osg::Uniform(strAB.str().c_str(),pssmShadowSplitTexture._ambientBias);
                        
pssmShadowSplitTexture._stateset->addUniform(ambientBias);
                }
                

                
//////////////////////////////////////////////////////////////////////////
                // DEBUG
                if ( _displayTexturesGroupingNode ) {
                        {
                                pssmShadowSplitTexture._debug_textureUnit = 0;
                                pssmShadowSplitTexture._debug_texture = new 
osg::Texture2D;
                                
pssmShadowSplitTexture._debug_texture->setTextureSize(TEXTURE_RESOLUTION, 
TEXTURE_RESOLUTION);
                                
pssmShadowSplitTexture._debug_texture->setInternalFormat(GL_RGBA);
                                
pssmShadowSplitTexture._debug_texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
                                
pssmShadowSplitTexture._debug_texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
                                // create the camera
                                pssmShadowSplitTexture._debug_camera = new 
osg::Camera;
                                
pssmShadowSplitTexture._debug_camera->setCullCallback(new 
CameraCullCallback(this));
                                
pssmShadowSplitTexture._debug_camera->setClearMask(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
                                
pssmShadowSplitTexture._debug_camera->setClearColor(osg::Vec4(1.0,1.0,1.0,1.0));
                                
pssmShadowSplitTexture._debug_camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
                                // set viewport
                                
pssmShadowSplitTexture._debug_camera->setViewport(0,0,TEXTURE_RESOLUTION,TEXTURE_RESOLUTION);
                                // set the camera to render before the main 
camera.
                                
pssmShadowSplitTexture._debug_camera->setRenderOrder(osg::Camera::PRE_RENDER);
                                // tell the camera to use OpenGL frame buffer 
object where supported.
                                
pssmShadowSplitTexture._debug_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
                                // attach the texture and use it as the color 
buffer.
                                
pssmShadowSplitTexture._debug_camera->attach(osg::Camera::COLOR_BUFFER, 
pssmShadowSplitTexture._debug_texture.get());
                                osg::StateSet* stateset = 
pssmShadowSplitTexture._debug_camera->getOrCreateStateSet();

                                pssmShadowSplitTexture._debug_stateset = new 
osg::StateSet;        
                                
pssmShadowSplitTexture._debug_stateset->setTextureAttributeAndModes(pssmShadowSplitTexture._debug_textureUnit,pssmShadowSplitTexture._debug_texture.get(),osg::StateAttribute::ON
 | osg::StateAttribute::OVERRIDE);
                                
pssmShadowSplitTexture._debug_stateset->setTextureMode(pssmShadowSplitTexture._debug_textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
                                
pssmShadowSplitTexture._debug_stateset->setTextureMode(pssmShadowSplitTexture._debug_textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
                                
pssmShadowSplitTexture._debug_stateset->setTextureMode(pssmShadowSplitTexture._debug_textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
                                
pssmShadowSplitTexture._debug_stateset->setTextureMode(pssmShadowSplitTexture._debug_textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON);
                        }

                        osg::Geode* geode = 
_displayTexturesGroupingNode[iCameras];
                        
geode->getOrCreateStateSet()->setTextureAttributeAndModes(0,pssmShadowSplitTexture._debug_texture.get(),osg::StateAttribute::ON);

                }               
                
//////////////////////////////////////////////////////////////////////////

                
_PSSMShadowSplitTextureMap.insert(PSSMShadowSplitTextureMap::value_type(iCameras,pssmShadowSplitTexture));


        }


        _dirty = false;
}

void ShadowPSSM::update(osg::NodeVisitor& nv){
        getShadowedScene()->osg::Group::traverse(nv);
}

void ShadowPSSM::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
        for (PSSMShadowSplitTextureMap::iterator 
it=_PSSMShadowSplitTextureMap.begin();it!=_PSSMShadowSplitTextureMap.end();it++)
        {
                PSSMShadowSplitTexture pssmShadowSplitTexture = it->second;
                cv.pushStateSet(pssmShadowSplitTexture._stateset.get());

                
//////////////////////////////////////////////////////////////////////////
                // DEGUBG
                if ( _displayTexturesGroupingNode ) {
                        
cv.pushStateSet(pssmShadowSplitTexture._debug_stateset.get());
                }
                
//////////////////////////////////////////////////////////////////////////

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

                cv.popStateSet();

        }

        // need to compute view frustum for RTT camera.
        // 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();

        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<const 
osg::Light*>(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;
        osg::Vec3d lightPosition(lightpos.x(), lightpos.y(), lightpos.z());
        osg::Vec3d lightdir = bb.center() - lightPosition;
        lightdir.normalize();
        
        if (selectLight)
        {
 
                // do traversal of shadow recieving scene which does need to be 
decorated by the shadow map
                unsigned int iMaxSplit = _PSSMShadowSplitTextureMap.size();
                
                for (PSSMShadowSplitTextureMap::iterator 
it=_PSSMShadowSplitTextureMap.begin();it!=_PSSMShadowSplitTextureMap.end();it++)
                {
                        PSSMShadowSplitTexture pssmShadowSplitTexture = 
it->second;
                        unsigned int iSplit = it->first;

                        pssmShadowSplitTexture._splitID = iSplit;
                        
//////////////////////////////////////////////////////////////////////////
                        // SETUP pssmShadowSplitTexture for rendering 
                        // 
                        pssmShadowSplitTexture._lightSource     = lightPosition;
                        pssmShadowSplitTexture._lightTarget     = bb.center();
                        pssmShadowSplitTexture._cameraView      = 
cv.getRenderInfo().getView()->getCamera()->getViewMatrix();
                        pssmShadowSplitTexture._cameraProj      = 
cv.getRenderInfo().getView()->getCamera()->getProjectionMatrix();

                        
//////////////////////////////////////////////////////////////////////////
                        // CALCULATE

 
 
                        // Calculate corner points of frustum split
                        //
                        // To avoid edge problems, scale the frustum so
                        // that it's at least a few pixels larger
                        //
                        osg::Vec3d pCorners[8];
                        
calculateFrustumCorners(pssmShadowSplitTexture,pCorners);

                        // Calculate near and far for light view
                        //
                        
calculateLightNearFarFormFrustum(pssmShadowSplitTexture,pCorners);
                        
                        // Calculate view and projection matrices
                        //
                        
calculateLightViewProjectionFormFrustum(pssmShadowSplitTexture,pCorners);


                        
//////////////////////////////////////////////////////////////////////////
                        // DEBUG
                        if ( _displayTexturesGroupingNode ) {
                                
pssmShadowSplitTexture._debug_camera->setViewMatrix(pssmShadowSplitTexture._camera->getViewMatrix());
                                
pssmShadowSplitTexture._debug_camera->setProjectionMatrix(pssmShadowSplitTexture._camera->getProjectionMatrix());
                                
pssmShadowSplitTexture._debug_camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
 

                        }

                        
//////////////////////////////////////////////////////////////////////////
                        // compute the matrix which takes a vertex from local 
coords into tex coords
                        // will use this later to specify osg::TexGen..
                        osg::Matrix MVPT = 
pssmShadowSplitTexture._camera->getViewMatrix() * 
                                
pssmShadowSplitTexture._camera->getProjectionMatrix() *
                                osg::Matrix::translate(1.0,1.0,1.0) *
                                osg::Matrix::scale(0.5f,0.5f,0.5f);

                        
pssmShadowSplitTexture._texgen->setMode(osg::TexGen::EYE_LINEAR);
                        
pssmShadowSplitTexture._texgen->setPlanesFromMatrix(MVPT);
                        
//////////////////////////////////////////////////////////////////////////


                        
//////////////////////////////////////////////////////////////////////////
                        cv.setTraversalMask( traversalMask & 
getShadowedScene()->getCastsShadowTraversalMask() );

                        // do RTT camera traversal
                        pssmShadowSplitTexture._camera->accept(cv);
                        
                        
//////////////////////////////////////////////////////////////////////////
                        // DEBUG
                        if ( _displayTexturesGroupingNode ) {
                                
pssmShadowSplitTexture._debug_camera->accept(cv);
                        }

                        
                        
orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(pssmShadowSplitTexture._textureUnit,
 cv.getModelViewMatrix(), pssmShadowSplitTexture._texgen.get());


                }
        } // if light



        // reapply the original traversal mask
        cv.setTraversalMask( traversalMask );
}

void ShadowPSSM::cleanSceneGraph(){

}



// Computes corner points of a frustum
//
//
void ShadowPSSM::calculateFrustumCorners(
        PSSMShadowSplitTexture &pssmShadowSplitTexture,
        osg::Vec3d *frustumCorners
) {
        double fovy,aspectRatio,camNear,camFar;
        
pssmShadowSplitTexture._cameraProj.getPerspective(fovy,aspectRatio,camNear,camFar);
        double camNearFar = camFar - camNear;
        camFar  = camNear + camNearFar * 
((double)(pssmShadowSplitTexture._splitID+1))/((double)(NUM_SPLITS));
        camNear = camNear + camNearFar * 
((double)(pssmShadowSplitTexture._splitID))/((double)(NUM_SPLITS));
        
        
pssmShadowSplitTexture._cameraProj.makePerspective(fovy,aspectRatio,camNear,camFar);

        //unit box representing frustum in clip space
        frustumCorners[0].set(1.0f, -1.0f, 1.0f);
        frustumCorners[1].set(1.0f, -1.0f, -1.0f);
        frustumCorners[2].set(1.0f, 1.0f, -1.0f);       
        frustumCorners[3].set(1.0f, 1.0f, 1.0f);
        frustumCorners[4].set(-1.0f, 1.0f, 1.0f);
        frustumCorners[5].set(-1.0f, -1.0f, 1.0f);
        frustumCorners[6].set(-1.0f, -1.0f, -1.0f);
        frustumCorners[7].set(-1.0f, 1.0f, -1.0f);
 
        osg::Matrixd vp = 
pssmShadowSplitTexture._cameraView*pssmShadowSplitTexture._cameraProj;
        osg::Matrixd ivp =vp; ivp.invert(ivp);

        for(int i=0;i<8;i++) {
                frustumCorners[i] =frustumCorners[i]*ivp;
        }
                
} 
 
void ShadowPSSM::calculateLightNearFarFormFrustum(
        PSSMShadowSplitTexture &pssmShadowSplitTexture,
        osg::Vec3d *frustumCorners
) {

        osg::Vec3d centerLightTarget(0,0,0);
        for(int i=0;i<8;i++) {
                centerLightTarget += frustumCorners[i];
        }
        centerLightTarget /= 8;
        
        osg::Vec3d dLight =  pssmShadowSplitTexture._lightTarget - 
centerLightTarget; 
        pssmShadowSplitTexture._lightSource -= dLight;
        pssmShadowSplitTexture._lightTarget -= dLight;

        // light direction for scalar product projected z length
        osg::Vec3d lightDir = pssmShadowSplitTexture._lightTarget - 
pssmShadowSplitTexture._lightSource;
        lightDir.normalize();

        //calculate near, far
        double zNear=-1;
        double zFar =-1;

        // force zNear > 0.0 
        while ( zNear < 0.0 ){
                zNear= DBL_MAX;
                zFar =-DBL_MAX;
                for(int i=0;i<8;i++) {
                        double dist_z_from_light = (frustumCorners[i] - 
pssmShadowSplitTexture._lightSource) * lightDir;
                        if ( zNear > dist_z_from_light ) zNear = 
dist_z_from_light;
                        if ( zFar  < dist_z_from_light ) zFar  = 
dist_z_from_light;
                }
                pssmShadowSplitTexture._lightNear = zNear;
                pssmShadowSplitTexture._lightFar  = zFar;



                if ( zNear < 0.0 ) {
                        // update light, zNear and zFar
                        pssmShadowSplitTexture._lightSource += 
lightDir*(zNear-1.0);
                }
        } // ( zNear > 0.0 )
}

void ShadowPSSM::calculateLightViewProjectionFormFrustum(
        PSSMShadowSplitTexture &pssmShadowSplitTexture,
        osg::Vec3d *frustumCorners
) {
        osg::Vec3d upVector(0,1,0);

        //light direction for scalar product projected z length
        osg::Vec3d lightDir = pssmShadowSplitTexture._lightTarget - 
pssmShadowSplitTexture._lightSource;
        double centerDistance = lightDir.length();
        lightDir.normalize();
        
        
        double left   =-DBL_MAX;
        double top    =-DBL_MAX;
        double right   =-DBL_MAX;
        double bottom    =-DBL_MAX;

        osg::Vec3d vLeft = upVector^lightDir;
        osg::Vec3d vUp   = lightDir^vLeft;
        double radius = -DBL_MAX;
        for(int i=0;i<8;i++) {
                double dist_left = (frustumCorners[i] - 
pssmShadowSplitTexture._lightSource) * vLeft;
                double dist_top  = (frustumCorners[i] - 
pssmShadowSplitTexture._lightSource) * vUp;
                if ( left < dist_left ) left = dist_left;
                if ( top  < dist_top  )  top = dist_top;

                double dist_right = (frustumCorners[i] - 
pssmShadowSplitTexture._lightSource) * (-vLeft);
                double dist_bottom  = (frustumCorners[i] - 
pssmShadowSplitTexture._lightSource) * (-vUp);
                if ( right < dist_right ) right = dist_right;
                if ( bottom  < dist_bottom  )  bottom = dist_bottom;

                double r = 
(frustumCorners[i]-pssmShadowSplitTexture._lightTarget).length();
                if ( radius < r ) radius = r;
        }
        double l = max(left,right);
        double t = max(bottom,top);
        
        t = (radius/centerDistance)*pssmShadowSplitTexture._lightNear;
        l = t;


        {

                float centerDistance = 
(pssmShadowSplitTexture._lightSource-pssmShadowSplitTexture._lightTarget).length();
                float znear = centerDistance-radius;
                float zfar  = centerDistance+radius;
                float zNearRatio = 0.001f;
                if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;
                float top   = (radius/centerDistance)*znear;
                float right = top;

                
//////////////////////////////////////////////////////////////////////////
                // set up shadow rendering camera

                
pssmShadowSplitTexture._camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); 
                
pssmShadowSplitTexture._camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar);
                
pssmShadowSplitTexture._camera->setViewMatrixAsLookAt(pssmShadowSplitTexture._lightSource,pssmShadowSplitTexture._lightTarget,upVector);

        }



}







#ifndef OSGSHADOW_SHADOWPSSM 
#define OSGSHADOW_SHADOWPSSM 1

#include <osg/Camera>
#include <osg/Material>

#include <osgShadow/ShadowTechnique>

namespace osgShadow {
class ShadowPSSM :  public ShadowTechnique 
{
        public:
                ShadowPSSM(osg::Geode** debugGroup=NULL, int icountplanes=1);

                ShadowPSSM(const ShadowPSSM& es, const osg::CopyOp& 
copyop=osg::CopyOp::SHALLOW_COPY);
                
                META_Object(osgShadow, ShadowPSSM);


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

                /** Clean scene graph from any shadow technique specific nodes, 
state and drawables.*/
                virtual void cleanSceneGraph();

        protected :

                virtual ~ShadowPSSM() {}

        
                struct PSSMShadowSplitTexture {
                        // RTT
                        osg::ref_ptr<osg::Camera>       _camera;
                        osg::ref_ptr<osg::TexGen>       _texgen;
                        osg::ref_ptr<osg::Texture2D>    _texture;
                        osg::ref_ptr<osg::StateSet>     _stateset;
                        unsigned int                    _textureUnit;
                        osg::Vec2d                      _ambientBias;


                        osg::ref_ptr<osg::Camera>       _debug_camera;
                        osg::ref_ptr<osg::Texture2D>    _debug_texture;
                        osg::ref_ptr<osg::StateSet>     _debug_stateset;
                        unsigned int                    _debug_textureUnit;


                        
                        // Light (SUN)
                        osg::Vec3d                                              
_lightSource;
                        osg::Vec3d                                              
_lightTarget;
                        double                                                  
_lightNear;
                        double                                                  
_lightFar;

                        osg::Matrix                                             
_cameraView;
                        osg::Matrix                                             
_cameraProj;

                        unsigned int                                    
_splitID;
         

                };
                typedef std::map<unsigned int,PSSMShadowSplitTexture> 
PSSMShadowSplitTextureMap;
                PSSMShadowSplitTextureMap _PSSMShadowSplitTextureMap;


        private:
                void calculateFrustumCorners(PSSMShadowSplitTexture 
&pssmShadowSplitTexture,osg::Vec3d *frustumCorners);
                void calculateLightNearFarFormFrustum(PSSMShadowSplitTexture 
&pssmShadowSplitTexture,osg::Vec3d *frustumCorners);
                void 
calculateLightViewProjectionFormFrustum(PSSMShadowSplitTexture 
&pssmShadowSplitTexture,osg::Vec3d *frustumCorners);

                osg::Geode** _displayTexturesGroupingNode;



};
}
#endif

Attachment: PSSM.vcproj
Description: application/xml

Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PSSM", "PSSM.vcproj", 
"{4C33E02F-0D14-413B-8A1F-76FCDAC080A2}"
        ProjectSection(ProjectDependencies) = postProject
        EndProjectSection
EndProject
Global
        GlobalSection(SolutionConfiguration) = preSolution
                Debug = Debug
                Release = Release
        EndGlobalSection
        GlobalSection(ProjectConfiguration) = postSolution
                {4C33E02F-0D14-413B-8A1F-76FCDAC080A2}.Debug.ActiveCfg = 
Debug|Win32
                {4C33E02F-0D14-413B-8A1F-76FCDAC080A2}.Debug.Build.0 = 
Debug|Win32
                {4C33E02F-0D14-413B-8A1F-76FCDAC080A2}.Release.ActiveCfg = 
Release|Win32
                {4C33E02F-0D14-413B-8A1F-76FCDAC080A2}.Release.Build.0 = 
Release|Win32
        EndGlobalSection
        GlobalSection(ExtensibilityGlobals) = postSolution
        EndGlobalSection
        GlobalSection(ExtensibilityAddIns) = postSolution
        EndGlobalSection
EndGlobal
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to