diff --git a/include/osgVolume/MultipassTechnique b/include/osgVolume/MultipassTechnique index 2abd4809d..0b383265c 100644 --- a/include/osgVolume/MultipassTechnique +++ b/include/osgVolume/MultipassTechnique @@ -19,6 +19,24 @@ namespace osgVolume { +/** Container for render to texture objects used when doing multi-pass volume rendering techniques.*/ +struct OSGVOLUME_EXPORT MultipassTileData : public TileData +{ + MultipassTileData(osgUtil::CullVisitor* cv); + + virtual void update(osgUtil::CullVisitor* cv); + + + osg::ref_ptr frontFaceDepthTexture; + osg::ref_ptr frontFaceRttCamera; + + osg::ref_ptr backFaceDepthTexture; + osg::ref_ptr backFaceRttCamera; + + osg::ref_ptr texgenUniform; +}; + + class OSGVOLUME_EXPORT MultipassTechnique : public VolumeTechnique { public: @@ -43,6 +61,10 @@ class OSGVOLUME_EXPORT MultipassTechnique : public VolumeTechnique /** Traverse the terrain subgraph.*/ virtual void traverse(osg::NodeVisitor& nv); + /** Called from VolumeScene to create the TileData container when a multi-pass technique is being used. + * The TileData container caches any render to texture objects that are required. */ + virtual TileData* createTileData(osgUtil::CullVisitor* cv) { return new MultipassTileData(cv); } + protected: virtual ~MultipassTechnique(); diff --git a/include/osgVolume/VolumeScene b/include/osgVolume/VolumeScene index c9c3d0b1a..5c116ce4e 100644 --- a/include/osgVolume/VolumeScene +++ b/include/osgVolume/VolumeScene @@ -36,24 +36,8 @@ class OSGVOLUME_EXPORT VolumeScene : public osg::Group virtual void traverse(osg::NodeVisitor& nv); - struct TileData : public osg::Referenced - { - TileData() : active(false) {} - - bool active; - - osg::NodePath nodePath; - osg::ref_ptr projectionMatrix; - osg::ref_ptr modelviewMatrix; - - osg::ref_ptr depthTexture; - osg::ref_ptr rttCamera; - osg::ref_ptr stateset; - osg::ref_ptr texgenUniform; - }; - - TileData* tileVisited(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile); - TileData* getTileData(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile); + TileData* tileVisited(osgUtil::CullVisitor* cv, VolumeTile* tile); + TileData* getTileData(osgUtil::CullVisitor* cv, VolumeTile* tile); protected: diff --git a/include/osgVolume/VolumeTechnique b/include/osgVolume/VolumeTechnique index dec084ad3..79639eaf3 100644 --- a/include/osgVolume/VolumeTechnique +++ b/include/osgVolume/VolumeTechnique @@ -25,6 +25,23 @@ namespace osgVolume { class VolumeTile; +/** Container for render to texture objects used when doing multi-pass volume rendering techniques.*/ +struct TileData : public osg::Referenced +{ + TileData() : active(false) {} + + virtual void update(osgUtil::CullVisitor* cv) = 0; + + bool active; + + osg::NodePath nodePath; + osg::ref_ptr projectionMatrix; + osg::ref_ptr modelviewMatrix; + + osg::ref_ptr stateset; +}; + + class OSGVOLUME_EXPORT VolumeTechnique : public osg::Object { public: @@ -53,6 +70,10 @@ class OSGVOLUME_EXPORT VolumeTechnique : public osg::Object /** Traverse the terrain subgraph.*/ virtual void traverse(osg::NodeVisitor& nv); + /** Called from VolumeScene to create the TileData container when a multi-pass technique is being used. + * The TileData container caches any render to texture objects that are required. */ + virtual TileData* createTileData(osgUtil::CullVisitor* cv) { return 0; } + protected: void setDirty(bool dirty); diff --git a/src/osgVolume/MultipassTechnique.cpp b/src/osgVolume/MultipassTechnique.cpp index c9f3dd521..738c3a415 100644 --- a/src/osgVolume/MultipassTechnique.cpp +++ b/src/osgVolume/MultipassTechnique.cpp @@ -147,7 +147,97 @@ osg::Image* createDownsampledImage(osg::Image* sourceImage) return targetImage.release(); } +//////////////////////////////////////////////////////////////////////// +// +// MultipassTileData +// +MultipassTileData::MultipassTileData(osgUtil::CullVisitor* cv): + TileData() +{ + int width = 512; + int height = 512; + osg::Viewport* viewport = cv->getCurrentRenderStage()->getViewport(); + if (viewport) + { + width = static_cast(viewport->width()); + height = static_cast(viewport->height()); + } + + osg::ref_ptr depthTexture = new osg::Texture2D; + frontFaceDepthTexture = depthTexture; + + depthTexture->setTextureSize(width, height); + depthTexture->setInternalFormat(GL_DEPTH_COMPONENT); + depthTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); + depthTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); + depthTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER); + depthTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER); + depthTexture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); + + osg::ref_ptr camera = new osg::Camera; + frontFaceRttCamera = camera; + frontFaceRttCamera->setName("frontFaceRttCamera"); + camera->attach(osg::Camera::DEPTH_BUFFER, depthTexture.get()); + camera->setViewport(0, 0, width, height); + + // clear the depth and colour bufferson each clear. + camera->setClearMask(GL_DEPTH_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); + + camera->setReferenceFrame(osg::Transform::RELATIVE_RF); + camera->setProjectionMatrix(osg::Matrixd::identity()); + camera->setViewMatrix(osg::Matrixd::identity()); + + stateset = new osg::StateSet; + stateset->setTextureAttribute(2, depthTexture.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + texgenUniform = new osg::Uniform("texgen",osg::Matrixf()); + + stateset->addUniform(texgenUniform.get()); +} + +void MultipassTileData::update(osgUtil::CullVisitor* cv) +{ + active = true; + nodePath = cv->getNodePath(); + projectionMatrix = cv->getProjectionMatrix(); + modelviewMatrix = cv->getModelViewMatrix(); + + int width = 512; + int height = 512; + + osg::Viewport* viewport = cv->getCurrentRenderStage()->getViewport(); + if (viewport) + { + width = static_cast(viewport->width()); + height = static_cast(viewport->height()); + } + + if (frontFaceDepthTexture.valid()) + { + if (frontFaceDepthTexture->getTextureWidth()!=width || frontFaceDepthTexture->getTextureHeight()!=height) + { + OSG_NOTICE<<"Need to change texture size to "<setTextureSize(width, height); + frontFaceRttCamera->setViewport(0, 0, width, height); + if (frontFaceRttCamera->getRenderingCache()) + { + frontFaceRttCamera->getRenderingCache()->releaseGLObjects(0); + } + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// +// MultipassTechnique +// MultipassTechnique::MultipassTechnique() { } @@ -678,7 +768,7 @@ class RTTBackfaceCameraCullCallback : public osg::NodeCallback { public: - RTTBackfaceCameraCullCallback(VolumeScene::TileData* tileData, MultipassTechnique* mt): + RTTBackfaceCameraCullCallback(MultipassTileData* tileData, MultipassTechnique* mt): _tileData(tileData), _mt(mt) {} @@ -697,7 +787,7 @@ class RTTBackfaceCameraCullCallback : public osg::NodeCallback virtual ~RTTBackfaceCameraCullCallback() {} - osg::observer_ptr _tileData; + osg::observer_ptr _tileData; osg::observer_ptr _mt; }; @@ -720,16 +810,16 @@ void MultipassTechnique::cull(osgUtil::CullVisitor* cv) { if (vs) { - VolumeScene::TileData* tileData = vs->tileVisited(cv, getVolumeTile()); - if (tileData->rttCamera.valid()) + MultipassTileData* tileData = dynamic_cast(vs->tileVisited(cv, getVolumeTile())); + if (tileData && tileData->frontFaceRttCamera.valid()) { - if (!(tileData->rttCamera->getCullCallback())) + if (!(tileData->frontFaceRttCamera->getCullCallback())) { - tileData->rttCamera->setCullCallback(new RTTBackfaceCameraCullCallback(tileData, this)); + tileData->frontFaceRttCamera->setCullCallback(new RTTBackfaceCameraCullCallback(tileData, this)); } // traverse RTT Camera - tileData->rttCamera->accept(*cv); + tileData->frontFaceRttCamera->accept(*cv); } osg::BoundingBox bb; @@ -776,7 +866,7 @@ void MultipassTechnique::cull(osgUtil::CullVisitor* cv) if (vs) { - VolumeScene::TileData* tileData = vs->getTileData(cv, getVolumeTile()); + MultipassTileData* tileData = dynamic_cast(vs->getTileData(cv, getVolumeTile())); if (tileData) { Locator* layerLocator = _volumeTile->getLayer()->getLocator(); diff --git a/src/osgVolume/VolumeScene.cpp b/src/osgVolume/VolumeScene.cpp index b5e34b919..78a43748b 100644 --- a/src/osgVolume/VolumeScene.cpp +++ b/src/osgVolume/VolumeScene.cpp @@ -49,6 +49,10 @@ class RTTCameraCullCallback : public osg::NodeCallback }; +//////////////////////////////////////////////////////////////////////// +// +// VolumeScene::ViewData +// VolumeScene::ViewData::ViewData() { } @@ -67,6 +71,10 @@ void VolumeScene::ViewData::visitTile(VolumeTile* tile) { } +//////////////////////////////////////////////////////////////////////// +// +// VolumeScene +// VolumeScene::VolumeScene() { } @@ -81,7 +89,7 @@ VolumeScene::~VolumeScene() { } -VolumeScene::TileData* VolumeScene::tileVisited(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile) +TileData* VolumeScene::tileVisited(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile) { osg::ref_ptr viewData; @@ -95,73 +103,15 @@ VolumeScene::TileData* VolumeScene::tileVisited(osgUtil::CullVisitor* cv, osgVol if (viewData.valid()) { - int textureWidth = 512; - int textureHeight = 512; - - osg::Viewport* viewport = cv->getCurrentRenderStage()->getViewport(); - if (viewport) - { - textureWidth = static_cast(viewport->width()); - textureHeight = static_cast(viewport->height()); - } - osg::ref_ptr& tileData = viewData->_tiles[tile]; if (!tileData) { - tileData = new TileData; - - tileData->depthTexture = new osg::Texture2D; - tileData->depthTexture->setTextureSize(textureWidth, textureHeight); - tileData->depthTexture->setInternalFormat(GL_DEPTH_COMPONENT); - tileData->depthTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); - tileData->depthTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); - tileData->depthTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER); - tileData->depthTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER); - tileData->depthTexture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); - - tileData->rttCamera = new osg::Camera; - tileData->rttCamera->setName("tileData->rttCamera"); - tileData->rttCamera->attach(osg::Camera::DEPTH_BUFFER, tileData->depthTexture.get()); - tileData->rttCamera->setViewport(0,0,textureWidth,textureHeight); - - // clear the depth and colour bufferson each clear. - tileData->rttCamera->setClearMask(GL_DEPTH_BUFFER_BIT); - - // set the camera to render before the main camera. - tileData->rttCamera->setRenderOrder(osg::Camera::PRE_RENDER); - - // tell the camera to use OpenGL frame buffer object where supported. - tileData->rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); - - tileData->rttCamera->setReferenceFrame(osg::Transform::RELATIVE_RF); - tileData->rttCamera->setProjectionMatrix(osg::Matrixd::identity()); - tileData->rttCamera->setViewMatrix(osg::Matrixd::identity()); - - tileData->stateset = new osg::StateSet; - tileData->stateset->setTextureAttribute(2, tileData->depthTexture.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - - tileData->texgenUniform = new osg::Uniform("texgen",osg::Matrixf()); - tileData->stateset->addUniform(tileData->texgenUniform.get()); + tileData = tile->getVolumeTechnique() ? tile->getVolumeTechnique()->createTileData(cv) : 0; } - tileData->active = true; - tileData->nodePath = cv->getNodePath(); - tileData->projectionMatrix = cv->getProjectionMatrix(); - tileData->modelviewMatrix = cv->getModelViewMatrix(); - - - if (tileData->depthTexture.valid()) + if (tileData) { - if (tileData->depthTexture->getTextureWidth()!=textureWidth || tileData->depthTexture->getTextureHeight()!=textureHeight) - { - OSG_NOTICE<<"Need to change texture size to "<depthTexture->setTextureSize(textureWidth, textureHeight); - tileData->rttCamera->setViewport(0, 0, textureWidth, textureHeight); - if (tileData->rttCamera->getRenderingCache()) - { - tileData->rttCamera->getRenderingCache()->releaseGLObjects(0); - } - } + tileData->update(cv); } return tileData.get(); @@ -169,7 +119,7 @@ VolumeScene::TileData* VolumeScene::tileVisited(osgUtil::CullVisitor* cv, osgVol return 0; } -VolumeScene::TileData* VolumeScene::getTileData(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile) +TileData* VolumeScene::getTileData(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile) { osg::ref_ptr viewData; { @@ -479,7 +429,7 @@ void VolumeScene::traverse(osg::NodeVisitor& nv) osg::NodePath::iterator np_itr = nodePath.begin(); - // skip over all nodes above VolumeScene as this will have already been traverse by CullVisitor + // skip over all nodes above VolumeScene as this will have already been traversed by CullVisitor while(np_itr!=nodePath.end() && (*np_itr)!=viewData->_rttCamera.get()) { ++np_itr; } if (np_itr!=nodePath.end()) ++np_itr;