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
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

