From 4aa16bc8e397407276a78cf7d96c10ac44400dea Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 9 Aug 2011 13:39:57 +0000 Subject: [PATCH] Implemented caching of Camera, Texture and TexGen --- include/osgShadow/ViewDependentShadowMap | 88 +-- src/osgShadow/ViewDependentShadowMap.cpp | 699 ++++++++++++++--------- 2 files changed, 468 insertions(+), 319 deletions(-) diff --git a/include/osgShadow/ViewDependentShadowMap b/include/osgShadow/ViewDependentShadowMap index 7ee1d7225..3d9d0e5dc 100644 --- a/include/osgShadow/ViewDependentShadowMap +++ b/include/osgShadow/ViewDependentShadowMap @@ -45,36 +45,6 @@ class OSGSHADOW_EXPORT ViewDependentShadowMap : public ShadowTechnique /** Clean scene graph from any shadow technique specific nodes, state and drawables.*/ virtual void cleanSceneGraph(); - struct OSGSHADOW_EXPORT LightShadowData : public osg::Referenced - { - unsigned int _textureUnit; - osg::ref_ptr _texture; - osg::ref_ptr _texgen; - - osg::ref_ptr _light; - osg::ref_ptr _camera; - }; - - class OSGSHADOW_EXPORT ViewDependentData : public osg::Referenced - { - public: - ViewDependentData(ViewDependentShadowMap* vdsm, osgUtil::CullVisitor* cv); - - - - void cullShadowCastingScene(osgUtil::CullVisitor* cv); - - void cull(osgUtil::CullVisitor*); - - protected: - virtual ~ViewDependentData() {} - - osg::ref_ptr _stateset; - }; - - virtual ViewDependentData* createViewDependentData(osgUtil::CullVisitor* cv); - - ViewDependentData* getViewDependentData(osgUtil::CullVisitor* cv); struct OSGSHADOW_EXPORT Frustum { @@ -99,10 +69,13 @@ class OSGSHADOW_EXPORT ViewDependentShadowMap : public ShadowTechnique osg::Vec3d frustumCenterLine; }; - struct OSGSHADOW_EXPORT PositionedLight + struct OSGSHADOW_EXPORT LightData : public osg::Referenced { - PositionedLight(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix); + LightData(); + + virtual void setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix); + bool active; osg::ref_ptr lightMatrix; osg::ref_ptr light; @@ -115,13 +88,54 @@ class OSGSHADOW_EXPORT ViewDependentShadowMap : public ShadowTechnique ActiveTextureUnits textureUnits; }; - typedef std::list< PositionedLight > PositionedLightList; + typedef std::list< osg::ref_ptr > LightDataList; - virtual bool selectActiveLights(osgUtil::CullVisitor* cv, PositionedLightList& pll) const; + struct OSGSHADOW_EXPORT ShadowData : public osg::Referenced + { + ShadowData(); - virtual osg::Polytope computeLightViewFrustumPolytope(Frustum& frustum, PositionedLight& positionedLight); + bool _active; + unsigned int _textureUnit; + osg::ref_ptr _texture; + osg::ref_ptr _texgen; + osg::ref_ptr _camera; + }; - virtual bool computeShadowCameraSettings(Frustum& frustum, PositionedLight& positionedLight, osg::Camera* camera); + typedef std::list< osg::ref_ptr > ShadowDataList; + + + class OSGSHADOW_EXPORT ViewDependentData : public osg::Referenced + { + public: + ViewDependentData(); + + LightDataList& getLightDataList() { return _lightDataList; } + + ShadowDataList& getShadowDataList() { return _shadowDataList; } + + osg::StateSet* getStateSet() { return _stateset.get(); } + + protected: + virtual ~ViewDependentData() {} + + osg::ref_ptr _stateset; + + LightDataList _lightDataList; + ShadowDataList _shadowDataList; + }; + + virtual ViewDependentData* createViewDependentData(osgUtil::CullVisitor* cv); + + ViewDependentData* getViewDependentData(osgUtil::CullVisitor* cv); + + + virtual void createShaders(); + + virtual bool selectActiveLights(osgUtil::CullVisitor* cv, LightDataList& pll) const; + + virtual osg::Polytope computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight); + + virtual bool computeShadowCameraSettings(Frustum& frustum, LightData& positionedLight, osg::Camera* camera); virtual bool assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen); @@ -129,7 +143,7 @@ class OSGSHADOW_EXPORT ViewDependentShadowMap : public ShadowTechnique virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const; - virtual osg::StateSet* selectStateSetForRenderingShadow(PositionedLightList& pll) const; + virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd) const; protected: virtual ~ViewDependentShadowMap(); diff --git a/src/osgShadow/ViewDependentShadowMap.cpp b/src/osgShadow/ViewDependentShadowMap.cpp index 36cdba58d..7c595d1d6 100644 --- a/src/osgShadow/ViewDependentShadowMap.cpp +++ b/src/osgShadow/ViewDependentShadowMap.cpp @@ -17,6 +17,10 @@ using namespace osgShadow; +/////////////////////////////////////////////////////////////////////////////////////////////// +// +// VDSMCameraCullCallback +// class VDSMCameraCullCallback : public osg::NodeCallback { public: @@ -41,11 +45,11 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) { osgUtil::CullVisitor* cv = dynamic_cast(nv); osg::Camera* camera = dynamic_cast(node); - OSG_NOTICE<<"VDSMCameraCullCallback::operator()(osg::Node* "<getProjectionCullingStack().back(); @@ -61,7 +65,7 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) if (!_polytope.empty()) { - OSG_NOTICE<<"Popping custom Polytope"<popCullingSet(); } @@ -69,7 +73,7 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) { osg::Matrixd projection = *(cv->getProjectionMatrix()); - OSG_NOTICE<<"RTT Projection matrix "<setProjectionMatrix(projection); @@ -110,236 +114,19 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) /////////////////////////////////////////////////////////////////////////////////////////////// // -// ViewDependentShadowMap +// LightData // -ViewDependentShadowMap::ViewDependentShadowMap(): - ShadowTechnique() -{ - _shadowRecievingPlaceholderStateSet = new osg::StateSet; -} - -ViewDependentShadowMap::ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop): - ShadowTechnique(vdsm,copyop) -{ - _shadowRecievingPlaceholderStateSet = new osg::StateSet; -} - -ViewDependentShadowMap::~ViewDependentShadowMap() +ViewDependentShadowMap::LightData::LightData(): + active(false), + directionalLight(false) { } - -void ViewDependentShadowMap::init() +void ViewDependentShadowMap::LightData::setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix) { - if (!_shadowedScene) return; + lightMatrix = lm; + light = l; - OSG_NOTICE<<"ViewDependentShadowMap::init()"< lock(_viewDependentDataMapMutex); - ViewDependentDataMap::iterator itr = _viewDependentDataMap.find(cv); - if (itr!=_viewDependentDataMap.end()) return itr->second.get(); - - osg::ref_ptr vdd = createViewDependentData(cv); - _viewDependentDataMap[cv] = vdd; - return vdd.release(); -} - -void ViewDependentShadowMap::update(osg::NodeVisitor& nv) -{ - OSG_NOTICE<<"ViewDependentShadowMap::update(osg::NodeVisitor& "<<&nv<<")"<osg::Group::traverse(nv); -} - -void ViewDependentShadowMap::cull(osgUtil::CullVisitor& cv) -{ - OSG_NOTICE< decoratorStateGraph = cv.getCurrentStateGraph(); - - cullShadowReceivingScene(&cv); - - cv.popStateSet(); - - - // 2. select active light sources - // create a list of light sources + their matrices to place them - PositionedLightList pll; - selectActiveLights(&cv, pll); - - unsigned int pos_x = 0; - unsigned int baseTextureUnit = 1; - unsigned int textureUnit = baseTextureUnit; - unsigned int numValidShadows = 0; - - Frustum frustum(&cv); - - for(PositionedLightList::iterator itr = pll.begin(); - itr != pll.end(); - ++itr) - { - // 3. create per light/per shadow map division of lightspace/frustum - // create a list of light/shadow map data structures - - PositionedLight& pl = *itr; - - // 4. For each light/shadow map - { - osg::ref_ptr camera; - - { - camera = new osg::Camera; - - camera->ref(); - - camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT); - - camera->setClearMask(GL_DEPTH_BUFFER_BIT); - //_camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); - //camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); - - // set viewport - //camera->setViewport(0,0,_textureSize.x(),_textureSize.y()); - camera->setViewport(pos_x,0,400,400); - - pos_x += 440; - - // set the camera to render before the main camera. - //camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setRenderOrder(osg::Camera::POST_RENDER); - - // tell the camera to use OpenGL frame buffer object where supported. - //camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); - //camera->setRenderTargetImplementation(osg::Camera::SEPERATE_WINDOW); - - // attach the texture and use it as the color buffer. - // camera->attach(osg::Camera::DEPTH_BUFFER, texture.get()); - } - - osg::ref_ptr texgen = new osg::TexGen; - - // 4.1 compute light space polytope - // - - osg::Polytope polytope = computeLightViewFrustumPolytope(frustum, pl); - - // if polytope is empty then no rendering. - if (polytope.empty()) - { - OSG_NOTICE<<"Polytope empty no shadow to render"<getViewMatrix()); - - polytope.transformProvidingInverse(invertModelView); - - camera->setCullCallback(new VDSMCameraCullCallback(this, polytope)); - - // 4.3 traverse RTT camera - // - - cullShadowCastingScene(&cv, camera.get()); - - // 4.4 compute main scene graph TexGen + uniform settings + setup state - // - - assignTexGenSettings(&cv, camera.get(), textureUnit, texgen); - - - // mark the light as one that has active shadows and requires shaders - pl.textureUnits.push_back(textureUnit); - - - // increment counters. - ++textureUnit; - ++numValidShadows ; - } - } - - if (numValidShadows>0) - { - OSG_NOTICE<<"Need to assign "<setStateSet(selectStateSetForRenderingShadow(pll)); - - } - -} - -bool ViewDependentShadowMap::selectActiveLights(osgUtil::CullVisitor* cv, PositionedLightList& pll) const -{ - OSG_NOTICE<<"selectActiveLights"<getRenderStage(); - - osg::Matrixd modelViewMatrix = *(cv->getModelViewMatrix()); - - osgUtil::PositionalStateContainer::AttrMatrixList& aml = - rs->getPositionalStateContainer()->getAttrMatrixList(); - - for(osgUtil::PositionalStateContainer::AttrMatrixList::reverse_iterator itr = aml.rbegin(); - itr != aml.rend(); - ++itr) - { - const osg::Light* light = dynamic_cast(itr->first.get()); - if (light) - { - PositionedLightList::iterator pll_itr = pll.begin(); - for(; pll_itr != pll.end(); ++pll_itr) - { - if (pll_itr->light->getLightNum()==light->getLightNum()) break; - } - - if (pll_itr==pll.end()) - { - OSG_NOTICE<<"Light num "<getLightNum()<second, light, modelViewMatrix)); - } - else - { - OSG_NOTICE<<"Light num "<getLightNum()<<" already used, ignore light"<getPosition(); directionalLight = (light->getPosition().w()== 0.0); if (directionalLight) @@ -376,6 +163,78 @@ ViewDependentShadowMap::PositionedLight::PositionedLight(osg::RefMatrix* lm, con } } +/////////////////////////////////////////////////////////////////////////////////////////////// +// +// ShadowData +// +ViewDependentShadowMap::ShadowData::ShadowData(): + _active(false), + _textureUnit(0) +{ + bool debug = false; + + // set up texgen + _texgen = new osg::TexGen; + + // set up the texture + _texture = new osg::Texture2D; + + unsigned int textureSize = debug ? 512 : 2048; + + _texture->setTextureSize(textureSize, textureSize); + //_texture->setInternalFormat(GL_DEPTH_COMPONENT); + _texture->setInternalFormat(GL_RGB); + //_texture->setShadowComparison(true); + //_texture->setShadowTextureMode(osg::Texture2D::LUMINANCE); + _texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); + _texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); + + // the shadow comparison should fail if object is outside the texture + _texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER); + _texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER); + _texture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); + + // set up the camera + _camera = new osg::Camera; + + _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT); + + _camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); + //camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); + + // set viewport + _camera->setViewport(0,0,textureSize,textureSize); + + + if (debug) + { + // clear just the depth buffer + _camera->setClearMask(GL_DEPTH_BUFFER_BIT); + + // render after the main camera + _camera->setRenderOrder(osg::Camera::POST_RENDER); + } + else + { + // clear the depth and colour bufferson each clear. + _camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + // set the camera to render before the main camera. + _camera->setRenderOrder(osg::Camera::PRE_RENDER); + + // tell the camera to use OpenGL frame buffer object where supported. + _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + + // attach the texture and use it as the color buffer. + //_camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get()); + _camera->attach(osg::Camera::COLOR_BUFFER, _texture.get()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +// Frustum +// ViewDependentShadowMap::Frustum::Frustum(osgUtil::CullVisitor* cv): corners(8), faces(6), @@ -391,8 +250,8 @@ ViewDependentShadowMap::Frustum::Frustum(osgUtil::CullVisitor* cv): cv->clampProjectionMatrix(projectionMatrix,zNear,zFar); - OSG_NOTICE<<"zNear = "< lock(_viewDependentDataMapMutex); + ViewDependentDataMap::iterator itr = _viewDependentDataMap.find(cv); + if (itr!=_viewDependentDataMap.end()) return itr->second.get(); + + osg::ref_ptr vdd = createViewDependentData(cv); + _viewDependentDataMap[cv] = vdd; + return vdd.release(); +} + +void ViewDependentShadowMap::update(osg::NodeVisitor& nv) +{ + OSG_NOTICE<<"ViewDependentShadowMap::update(osg::NodeVisitor& "<<&nv<<")"<osg::Group::traverse(nv); +} + +void ViewDependentShadowMap::cull(osgUtil::CullVisitor& cv) +{ + OSG_NOTICE<osg::Group::traverse(cv); + return; + } + + + // 1. Traverse main scene graph + cv.pushStateSet( _shadowRecievingPlaceholderStateSet.get() ); + + osg::ref_ptr decoratorStateGraph = cv.getCurrentStateGraph(); + + cullShadowReceivingScene(&cv); + + cv.popStateSet(); + + + // 2. select active light sources + // create a list of light sources + their matrices to place them + LightDataList& pll = vdd->getLightDataList(); + selectActiveLights(&cv, pll); + + unsigned int pos_x = 0; + unsigned int baseTextureUnit = 0; + unsigned int textureUnit = baseTextureUnit; + unsigned int numValidShadows = 0; + + bool debug = false; + + Frustum frustum(&cv); + + ShadowDataList& sdl = vdd->getShadowDataList(); + ShadowDataList previous_sdl; + previous_sdl.swap(sdl); + + for(LightDataList::iterator itr = pll.begin(); + itr != pll.end(); + ++itr) + { + // 3. create per light/per shadow map division of lightspace/frustum + // create a list of light/shadow map data structures + + LightData& pl = **itr; + + // 4. For each light/shadow map + { + osg::ref_ptr sd; + + if (previous_sdl.empty()) + { + OSG_NOTICE<<"Create new ShadowData"< camera = sd->_camera; + + if (debug) + { + camera->setViewport(pos_x,0,400,400); + pos_x += 440; + } + + osg::ref_ptr texgen = sd->_texgen; + + // 4.1 compute light space polytope + // + + osg::Polytope polytope = computeLightViewFrustumPolytope(frustum, pl); + + // if polytope is empty then no rendering. + if (polytope.empty()) + { + OSG_NOTICE<<"Polytope empty no shadow to render"<getViewMatrix()); + + polytope.transformProvidingInverse(invertModelView); + + camera->setCullCallback(new VDSMCameraCullCallback(this, polytope)); + + // 4.3 traverse RTT camera + // + + cullShadowCastingScene(&cv, camera.get()); + + // 4.4 compute main scene graph TexGen + uniform settings + setup state + // + + assignTexGenSettings(&cv, camera.get(), textureUnit, texgen); + + + // mark the light as one that has active shadows and requires shaders + pl.textureUnits.push_back(textureUnit); + + // pass on shadow data to ShadowDataList + sd->_textureUnit = textureUnit; + + sdl.push_back(sd); + + // increment counters. + ++textureUnit; + ++numValidShadows ; + } + } + + if (numValidShadows>0) + { + OSG_NOTICE<<"Need to assign "<setStateSet(selectStateSetForRenderingShadow(*vdd)); + } + +} + +bool ViewDependentShadowMap::selectActiveLights(osgUtil::CullVisitor* cv, LightDataList& pll) const +{ + OSG_NOTICE<<"selectActiveLights"<getRenderStage(); + + osg::Matrixd modelViewMatrix = *(cv->getModelViewMatrix()); + + osgUtil::PositionalStateContainer::AttrMatrixList& aml = + rs->getPositionalStateContainer()->getAttrMatrixList(); + + for(osgUtil::PositionalStateContainer::AttrMatrixList::reverse_iterator itr = aml.rbegin(); + itr != aml.rend(); + ++itr) + { + const osg::Light* light = dynamic_cast(itr->first.get()); + if (light) + { + LightDataList::iterator pll_itr = pll.begin(); + for(; pll_itr != pll.end(); ++pll_itr) + { + if ((*pll_itr)->light->getLightNum()==light->getLightNum()) break; + } + + if (pll_itr==pll.end()) + { + OSG_NOTICE<<"Light num "<getLightNum()<setLightData(itr->second, light, modelViewMatrix); + pll.push_back(ld); + } + else + { + OSG_NOTICE<<"Light num "<getLightNum()<<" already used, ignore light"<setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); + osg::ref_ptr stateset = vdd.getStateSet(); + + vdd.getStateSet()->clear(); + //vdd.getStateSet()->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); - for(PositionedLightList::iterator itr = pll.begin(); + LightDataList& pll = vdd.getLightDataList(); + for(LightDataList::iterator itr = pll.begin(); itr != pll.end(); ++itr) { // 3. create per light/per shadow map division of lightspace/frustum // create a list of light/shadow map data structures - PositionedLight& pl = *itr; + LightData& pl = (**itr); // if no texture units have been activated for this light then no shadow state required. if (pl.textureUnits.empty()) continue; - for(PositionedLight::ActiveTextureUnits::iterator atu_itr = pl.textureUnits.begin(); + for(LightData::ActiveTextureUnits::iterator atu_itr = pl.textureUnits.begin(); atu_itr != pl.textureUnits.end(); ++atu_itr) { @@ -839,15 +962,27 @@ osg::StateSet* ViewDependentShadowMap::selectStateSetForRenderingShadow(Position } } - return newStateSet.release(); + + ShadowDataList& sdl = vdd.getShadowDataList(); + for(ShadowDataList::iterator itr = sdl.begin(); + itr != sdl.end(); + ++itr) + { + // 3. create per light/per shadow map division of lightspace/frustum + // create a list of light/shadow map data structures + + ShadowData& sd = (**itr); + + OSG_NOTICE<<" ShadowData for "<setTextureAttributeAndModes(sd._textureUnit, sd._texture.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + + stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); + stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); + stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); + stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); + } + + return vdd.getStateSet(); } - -/////////////////////////////////////////////////////////////////////////////////////////////// -// -// ViewDependentData -// -ViewDependentShadowMap::ViewDependentData::ViewDependentData(ViewDependentShadowMap* vdsm, osgUtil::CullVisitor* cv) -{ - OSG_NOTICE<<"ViewDependentData::ViewDependentData("<