From 1264ec736aadb6302b4945714620d6bae6aa034b Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 16 Jan 2014 16:08:43 +0000 Subject: [PATCH] Added support for controlling the extents of the volume rendering by nesting the hull underneath VolumeTile. Currently only supported by the new osgVolume::MultipassTechnique --- include/osgVolume/MultipassTechnique | 7 +- include/osgVolume/VolumeScene | 17 +- src/osgVolume/MultipassTechnique.cpp | 166 +++++-- src/osgVolume/VolumeScene.cpp | 703 +++++++++++++++------------ 4 files changed, 544 insertions(+), 349 deletions(-) diff --git a/include/osgVolume/MultipassTechnique b/include/osgVolume/MultipassTechnique index 282ed7b69..6193a6516 100644 --- a/include/osgVolume/MultipassTechnique +++ b/include/osgVolume/MultipassTechnique @@ -33,7 +33,9 @@ class OSGVOLUME_EXPORT MultipassTechnique : public VolumeTechnique virtual void update(osgUtil::UpdateVisitor* nv); - virtual void cull(osgUtil::CullVisitor* nv); + virtual void backfaceSubgraphCullTraversal(osgUtil::CullVisitor* cv); + + virtual void cull(osgUtil::CullVisitor* cv); /** Clean scene graph from any terrain technique specific nodes.*/ virtual void cleanSceneGraph(); @@ -53,6 +55,7 @@ class OSGVOLUME_EXPORT MultipassTechnique : public VolumeTechnique ModelViewMatrixMap _modelViewMatrixMap; osg::ref_ptr _whenMovingStateSet; + osg::ref_ptr _volumeRenderStateSet; osg::StateSet* createStateSet(osg::StateSet* statesetPrototype, osg::Program* programPrototype, osg::Shader* shaderToAdd1=0, osg::Shader* shaderToAdd2=0); @@ -69,6 +72,8 @@ class OSGVOLUME_EXPORT MultipassTechnique : public VolumeTechnique typedef std::map > StateSetMap; StateSetMap _stateSetMap; + + osg::ref_ptr _frontFaceStateSet; }; } diff --git a/include/osgVolume/VolumeScene b/include/osgVolume/VolumeScene index 8e3e64199..c9c3d0b1a 100644 --- a/include/osgVolume/VolumeScene +++ b/include/osgVolume/VolumeScene @@ -36,12 +36,6 @@ class OSGVOLUME_EXPORT VolumeScene : public osg::Group virtual void traverse(osg::NodeVisitor& nv); - void tileVisited(osg::NodeVisitor* nv, osgVolume::VolumeTile* tile); - - protected: - - virtual ~VolumeScene(); - struct TileData : public osg::Referenced { TileData() : active(false) {} @@ -54,8 +48,17 @@ class OSGVOLUME_EXPORT VolumeScene : public osg::Group osg::ref_ptr depthTexture; osg::ref_ptr rttCamera; - osg::ref_ptr stateset; + osg::ref_ptr stateset; + osg::ref_ptr texgenUniform; }; + + TileData* tileVisited(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile); + TileData* getTileData(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile); + + protected: + + virtual ~VolumeScene(); + typedef std::map< VolumeTile*, osg::ref_ptr > Tiles; class ViewData : public osg::Referenced diff --git a/src/osgVolume/MultipassTechnique.cpp b/src/osgVolume/MultipassTechnique.cpp index 8d4453337..eeded4ef1 100644 --- a/src/osgVolume/MultipassTechnique.cpp +++ b/src/osgVolume/MultipassTechnique.cpp @@ -295,15 +295,17 @@ void MultipassTechnique::init() OSG_NOTICE<<"MultipassTechnique::init() : geometryMatrix = "<addUniform(new osg::Uniform("depthTexture",1)); + stateset->addUniform(new osg::Uniform("frontFaceDepthTexture",2)); stateset->setMode(GL_ALPHA_TEST,osg::StateAttribute::ON); @@ -355,7 +357,7 @@ void MultipassTechnique::init() } } - stateset->setTextureAttributeAndModes(texgenTextureUnit, texgen.get(), osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(texgenTextureUnit, texgen.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); } @@ -407,7 +409,7 @@ void MultipassTechnique::init() } texture3D->setImage(image_3d); - stateset->setTextureAttributeAndModes(volumeTextureUnit, texture3D, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(volumeTextureUnit, texture3D, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); osg::ref_ptr baseTextureSampler = new osg::Uniform("volumeTexture", int(volumeTextureUnit)); stateset->addUniform(baseTextureSampler.get()); @@ -446,7 +448,7 @@ void MultipassTechnique::init() unsigned int transferFunctionTextureUnit = volumeTextureUnit+1; - stateset->setTextureAttributeAndModes(transferFunctionTextureUnit, tf_texture.get(), osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(transferFunctionTextureUnit, tf_texture.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); stateset->addUniform(new osg::Uniform("tfTexture",int(transferFunctionTextureUnit))); stateset->addUniform(new osg::Uniform("tfOffset",tfOffset)); stateset->addUniform(new osg::Uniform("tfScale",tfScale)); @@ -487,12 +489,13 @@ void MultipassTechnique::init() #endif - osg::ref_ptr back_main_fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_multipass_back.frag"); + osg::ref_ptr back_main_fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_multipass_back_with_front_depthtexture.frag");; + //osg::ref_ptr back_main_fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_multipass_back.frag"); #if 0 if (!back_main_fragmentShader) { - #include "Shaders/volume_multipass_back_frag.cpp" - back_main_fragmentShader = new osg::Shader(osg::Shader::VERTEX, volume_multipass_back_frag)); + #include "Shaders/shaders/volume_multipass_back_with_front_depthtexture_frag.cpp" + back_main_fragmentShader = new osg::Shader(osg::Shader::VERTEX, volume_multipass_back_with_front_depthtexture_frag)); } #endif @@ -502,7 +505,7 @@ void MultipassTechnique::init() osg::ref_ptr front_stateset_prototype = new osg::StateSet; osg::ref_ptr front_program_prototype = new osg::Program; { - front_stateset_prototype->setAttributeAndModes(front_CullFace.get(), osg::StateAttribute::ON); + front_stateset_prototype->setAttributeAndModes(front_CullFace.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); front_program_prototype->addShader(main_vertexShader.get()); front_program_prototype->addShader(front_main_fragmentShader.get()); @@ -512,13 +515,28 @@ void MultipassTechnique::init() osg::ref_ptr back_stateset_prototype = new osg::StateSet; osg::ref_ptr back_program_prototype = new osg::Program; { - back_stateset_prototype->setAttributeAndModes(back_CullFace.get(), osg::StateAttribute::ON); + back_stateset_prototype->setAttributeAndModes(back_CullFace.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); back_program_prototype->addShader(main_vertexShader.get()); back_program_prototype->addShader(back_main_fragmentShader.get()); back_program_prototype->addShader(computeRayColorShader.get()); } + + // set up the rendering of the front face + { + _frontFaceStateSet = new osg::StateSet; + + // cull only the bac faces so we write only the front + _frontFaceStateSet->setAttributeAndModes(front_CullFace.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + // set up the front falce + osg::ref_ptr program = new osg::Program; + program->addShader(main_vertexShader.get()); + _frontFaceStateSet->setAttribute(program.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + // STANDARD_SHADERS { // STANDARD_SHADERS without TransferFunction @@ -690,7 +708,6 @@ void MultipassTechnique::init() if (cpv._sampleRatioWhenMovingProperty.valid()) { _whenMovingStateSet = new osg::StateSet; - //_whenMovingStateSet->setTextureAttributeAndModes(volumeTextureUnit, new osg::TexEnvFilter(1.0)); _whenMovingStateSet->addUniform(cpv._sampleRatioWhenMovingProperty->getUniform(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); } @@ -701,14 +718,89 @@ void MultipassTechnique::update(osgUtil::UpdateVisitor* /*uv*/) // OSG_NOTICE<<"MultipassTechnique:update(osgUtil::UpdateVisitor* nv):"<pushStateSet(_frontFaceStateSet.get()); + + if (getVolumeTile()->getNumChildren()>0) + { + getVolumeTile()->osg::Group::traverse(*cv); + } + else + { + _transform->accept(*cv); + } + + cv->popStateSet(); +} + +class RTTBackfaceCameraCullCallback : public osg::NodeCallback +{ + public: + + RTTBackfaceCameraCullCallback(VolumeScene::TileData* tileData, MultipassTechnique* mt): + _tileData(tileData), + _mt(mt) {} + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = dynamic_cast(nv); + + cv->pushProjectionMatrix(_tileData->projectionMatrix); + + _mt->backfaceSubgraphCullTraversal(cv); + + cv->popProjectionMatrix(); + } + + protected: + + virtual ~RTTBackfaceCameraCullCallback() {} + + osg::observer_ptr _tileData; + osg::observer_ptr _mt; +}; + void MultipassTechnique::cull(osgUtil::CullVisitor* cv) { std::string traversalPass; - bool postTraversal = cv->getUserValue("VolumeSceneTraversal", traversalPass) && traversalPass=="Post"; + bool rttTraversal = cv->getUserValue("VolumeSceneTraversal", traversalPass) && traversalPass=="RenderToTexture"; // OSG_NOTICE<<"MultipassTechnique::cull() traversalPass="<getNodePath(); + for(osg::NodePath::reverse_iterator itr = nodePath.rbegin(); + (itr != nodePath.rend()) && (vs == 0); + ++itr) + { + vs = dynamic_cast(*itr); + } - if (postTraversal) + if (rttTraversal) + { + if (vs) + { + VolumeScene::TileData* tileData = vs->tileVisited(cv, getVolumeTile()); + if (tileData->rttCamera.valid()) + { + if (!(tileData->rttCamera->getCullCallback())) + { + tileData->rttCamera->setCullCallback(new RTTBackfaceCameraCullCallback(tileData, this)); + } + + // traverse RTT Camera + tileData->rttCamera->accept(*cv); + } + + osg::BoundingBox bb; + if (_transform.valid()) bb.expandBy(_transform->getBound()); + if (getVolumeTile()->getNumChildren()>0) bb.expandBy(getVolumeTile()->getBound()); + cv->updateCalculatedNearFar(*(cv->getModelViewMatrix()),bb); + } + } + else { int shaderMask = 0; @@ -740,14 +832,27 @@ void MultipassTechnique::cull(osgUtil::CullVisitor* cv) } } - int shaderMaskFront = shaderMask | FRONT_SHADERS; + //int shaderMaskFront = shaderMask | FRONT_SHADERS; int shaderMaskBack = shaderMask | BACK_SHADERS; // OSG_NOTICE<<"shaderMaskFront "<getTileData(cv, getVolumeTile()); + if (tileData) + { + Locator* layerLocator = _volumeTile->getLayer()->getLocator(); + osg::Matrix imv = layerLocator->getTransform() * (*(cv->getModelViewMatrix())); + osg::Matrix inverse_imv; + inverse_imv.invert(imv); + tileData->texgenUniform->set(osg::Matrixf(inverse_imv)); + } + } - osg::ref_ptr front_stateset = _stateSetMap[shaderMaskFront]; + + //osg::ref_ptr front_stateset = _stateSetMap[shaderMaskFront]; osg::ref_ptr back_stateset = _stateSetMap[shaderMaskBack]; osg::ref_ptr moving_stateset = (_whenMovingStateSet.valid() && isMoving(cv)) ? _whenMovingStateSet : 0; @@ -757,6 +862,7 @@ void MultipassTechnique::cull(osgUtil::CullVisitor* cv) cv->pushStateSet(moving_stateset.get()); } +#if 0 if (front_stateset.valid()) { // OSG_NOTICE<<"Have front stateset"<accept(*cv); cv->popStateSet(); } - +#endif if (back_stateset.valid()) { // OSG_NOTICE<<"Have back stateset"<pushStateSet(back_stateset.get()); - _transform->accept(*cv); + cv->pushStateSet(_volumeRenderStateSet.get()); + + if (getVolumeTile()->getNumChildren()>0) + { + getVolumeTile()->osg::Group::traverse(*cv); + } + else + { + _transform->accept(*cv); + } + + cv->popStateSet(); cv->popStateSet(); } @@ -779,21 +896,6 @@ void MultipassTechnique::cull(osgUtil::CullVisitor* cv) cv->popStateSet(); } } - else - { - osg::NodePath& nodePath = cv->getNodePath(); - for(osg::NodePath::reverse_iterator itr = nodePath.rbegin(); - itr != nodePath.rend(); - ++itr) - { - osgVolume::VolumeScene* vs = dynamic_cast(*itr); - if (vs) - { - vs->tileVisited(cv, getVolumeTile()); - break; - } - } - } } void MultipassTechnique::cleanSceneGraph() diff --git a/src/osgVolume/VolumeScene.cpp b/src/osgVolume/VolumeScene.cpp index afdb8515a..ecb05eecd 100644 --- a/src/osgVolume/VolumeScene.cpp +++ b/src/osgVolume/VolumeScene.cpp @@ -45,7 +45,6 @@ class RTTCameraCullCallback : public osg::NodeCallback virtual ~RTTCameraCullCallback() {} osgVolume::VolumeScene* _volumeScene; - }; @@ -81,356 +80,442 @@ VolumeScene::~VolumeScene() { } -void VolumeScene::tileVisited(osg::NodeVisitor* nv, osgVolume::VolumeTile* tile) +VolumeScene::TileData* VolumeScene::tileVisited(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile) { - osgUtil::CullVisitor* cv = dynamic_cast(nv); - if (cv) + osg::ref_ptr viewData; + { - osg::ref_ptr viewData; - - { - OpenThreads::ScopedLock lock(_viewDataMapMutex); - viewData = _viewDataMap[cv]; - } - - if (viewData.valid()) - { - osg::ref_ptr& tileData = viewData->_tiles[tile]; - if (!tileData) tileData = new TileData; - tileData->active = true; - tileData->nodePath = cv->getNodePath(); - tileData->projectionMatrix = cv->getProjectionMatrix(); - tileData->modelviewMatrix = cv->getModelViewMatrix(); - } - - osg::BoundingBox bb(0.0f,0.0f,0.0f,1.0f,1.0f,1.0f); - cv->updateCalculatedNearFar(*(cv->getModelViewMatrix()),bb); + OpenThreads::ScopedLock lock(_viewDataMapMutex); + viewData = _viewDataMap[cv]; } -} + //osg::BoundingBox bb(0.0f,0.0f,0.0f,1.0f,1.0f,1.0f); + //cv->updateCalculatedNearFar(*(cv->getModelViewMatrix()),bb); -void VolumeScene::traverse(osg::NodeVisitor& nv) -{ - osgUtil::CullVisitor* cv = dynamic_cast(&nv); - if (cv) + if (viewData.valid()) { - osg::ref_ptr viewData; - bool initializeViewData = false; - { - OpenThreads::ScopedLock lock(_viewDataMapMutex); - if (!_viewDataMap[cv]) - { - _viewDataMap[cv] = new ViewData; - initializeViewData = true; - } - - viewData = _viewDataMap[cv]; - } - - if (initializeViewData) - { - OSG_NOTICE<<"Creating ViewData"<getCurrentRenderStage()->getViewport(); - if (viewport) - { - textureWidth = viewport->width(); - textureHeight = viewport->height(); - } - - // set up depth texture - viewData->_depthTexture = new osg::Texture2D; - - viewData->_depthTexture->setTextureSize(textureWidth, textureHeight); - viewData->_depthTexture->setInternalFormat(GL_DEPTH_COMPONENT); - viewData->_depthTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); - viewData->_depthTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); - - viewData->_depthTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER); - viewData->_depthTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER); - viewData->_depthTexture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); - - // set up color texture - viewData->_colorTexture = new osg::Texture2D; - - viewData->_colorTexture->setTextureSize(textureWidth, textureHeight); - viewData->_colorTexture->setInternalFormat(GL_RGBA); - viewData->_colorTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); - viewData->_colorTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); - - viewData->_colorTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_EDGE); - viewData->_colorTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_EDGE); - - - // set up the RTT Camera to capture the main scene to a color and depth texture that can be used in post processing - viewData->_rttCamera = new osg::Camera; - viewData->_rttCamera->attach(osg::Camera::DEPTH_BUFFER, viewData->_depthTexture.get()); - viewData->_rttCamera->attach(osg::Camera::COLOR_BUFFER, viewData->_colorTexture.get()); - viewData->_rttCamera->setCullCallback(new RTTCameraCullCallback(this)); - viewData->_rttCamera->setViewport(0,0,textureWidth,textureHeight); - - // clear the depth and colour bufferson each clear. - viewData->_rttCamera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - - // set the camera to render before the main camera. - viewData->_rttCamera->setRenderOrder(osg::Camera::PRE_RENDER); - - // tell the camera to use OpenGL frame buffer object where supported. - viewData->_rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); - - - viewData->_rttCamera->setReferenceFrame(osg::Transform::RELATIVE_RF); - viewData->_rttCamera->setProjectionMatrix(osg::Matrixd::identity()); - viewData->_rttCamera->setViewMatrix(osg::Matrixd::identity()); - - // create mesh for rendering the RTT textures onto the screen - osg::ref_ptr geode = new osg::Geode; - geode->setCullingActive(false); - - viewData->_backdropSubgraph = geode; - //geode->addDrawable(osg::createTexturedQuadGeometry(osg::Vec3(-1.0f,-1.0f,-1.0f),osg::Vec3(2.0f,0.0f,-1.0f),osg::Vec3(0.0f,2.0f,-1.0f))); - - viewData->_geometry = new osg::Geometry; - geode->addDrawable(viewData->_geometry.get()); - - viewData->_geometry->setUseDisplayList(false); - viewData->_geometry->setUseVertexBufferObjects(false); - - viewData->_vertices = new osg::Vec3Array(4); - viewData->_geometry->setVertexArray(viewData->_vertices.get()); - - osg::ref_ptr colors = new osg::Vec4Array(1); - (*colors)[0].set(1.0f,1.0f,1.0f,1.0f); - viewData->_geometry->setColorArray(colors.get(), osg::Array::BIND_OVERALL); - - osg::ref_ptr texcoords = new osg::Vec2Array(4); - (*texcoords)[0].set(0.0f,1.0f); - (*texcoords)[1].set(0.0f,0.0f); - (*texcoords)[2].set(1.0f,1.0f); - (*texcoords)[3].set(1.0f,0.0f); - viewData->_geometry->setTexCoordArray(0, texcoords.get(), osg::Array::BIND_PER_VERTEX); - - viewData->_geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP,0,4)); - - - osg::ref_ptr stateset = viewData->_geometry->getOrCreateStateSet(); - - stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON); - stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - stateset->setMode(GL_BLEND, osg::StateAttribute::ON); - stateset->setRenderBinDetails(10,"DepthSortedBin"); - - osg::ref_ptr program = new osg::Program; - stateset->setAttribute(program); - - // get vertex shaders from source - osg::ref_ptr vertexShader = osgDB::readRefShaderFile(osg::Shader::VERTEX, "shaders/volume_color_depth.vert"); - if (vertexShader.valid()) - { - program->addShader(vertexShader.get()); - } -#if 0 - else - { - #include "Shaders/volume_color_depth_vert.cpp" - program->addShader(new osg::Shader(osg::Shader::VERTEX, volume_color_depth_vert)); - } -#endif - // get fragment shaders from source - osg::ref_ptr fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_color_depth.frag"); - if (fragmentShader.valid()) - { - program->addShader(fragmentShader.get()); - } -#if 0 - else - { - #include "Shaders/volume_color_depth_frag.cpp" - program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_color_depth_frag)); - } -#endif - viewData->_stateset = new osg::StateSet; - viewData->_stateset->addUniform(new osg::Uniform("colorTexture",0)); - viewData->_stateset->addUniform(new osg::Uniform("depthTexture",1)); - - viewData->_stateset->setTextureAttributeAndModes(0, viewData->_colorTexture.get(), osg::StateAttribute::ON); - viewData->_stateset->setTextureAttributeAndModes(1, viewData->_depthTexture.get(), osg::StateAttribute::ON); - - viewData->_viewportDimensionsUniform = new osg::Uniform("viewportDimensions",osg::Vec4(0.0,0.0,1280.0,1024.0)); - viewData->_stateset->addUniform(viewData->_viewportDimensionsUniform.get()); - - geode->setStateSet(viewData->_stateset.get()); - - } - else - { - // OSG_NOTICE<<"Reusing ViewData"<getProjectionMatrix()); - osg::Matrix modelviewMatrix = *(cv->getModelViewMatrix()); - - - // new frame so need to clear last frames log of VolumeTiles - viewData->clearTiles(); + int textureWidth = 512; + int textureHeight = 512; osg::Viewport* viewport = cv->getCurrentRenderStage()->getViewport(); if (viewport) { - viewData->_viewportDimensionsUniform->set(osg::Vec4(viewport->x(), viewport->y(), viewport->width(),viewport->height())); + textureWidth = viewport->width(); + textureHeight = viewport->height(); + } - if (viewport->width() != viewData->_colorTexture->getTextureWidth() || - viewport->height() != viewData->_colorTexture->getTextureHeight()) + 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->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()); + + tileData->texgenUniform = new osg::Uniform("texgen2",osg::Matrixf()); + tileData->stateset->addUniform(tileData->texgenUniform); + } + + tileData->active = true; + tileData->nodePath = cv->getNodePath(); + tileData->projectionMatrix = cv->getProjectionMatrix(); + tileData->modelviewMatrix = cv->getModelViewMatrix(); + + + if (tileData->depthTexture.valid()) + { + if (tileData->depthTexture->getTextureWidth()!=textureWidth || tileData->depthTexture->getTextureHeight()!=textureHeight) { - OSG_NOTICE<<"Need to change texture size to "<width()<<", "<< viewport->height()<_colorTexture->setTextureSize(viewport->width(), viewport->height()); - viewData->_colorTexture->dirtyTextureObject(); - viewData->_depthTexture->setTextureSize(viewport->width(), viewport->height()); - viewData->_depthTexture->dirtyTextureObject(); - viewData->_rttCamera->setViewport(0, 0, viewport->width(), viewport->height()); - if (viewData->_rttCamera->getRenderingCache()) + OSG_NOTICE<<"Need to change texture size to "<depthTexture->setTextureSize(textureWidth, textureHeight); + tileData->rttCamera->setViewport(0, 0, textureWidth, textureHeight); + if (tileData->rttCamera->getRenderingCache()) { - viewData->_rttCamera->getRenderingCache()->releaseGLObjects(0); + tileData->rttCamera->getRenderingCache()->releaseGLObjects(0); } } } - cv->setUserValue("VolumeSceneTraversal",std::string("RenderToTexture")); + return tileData.get(); + } + return 0; +} - osg::Camera* parentCamera = cv->getCurrentCamera(); - viewData->_rttCamera->setClearColor(parentCamera->getClearColor()); +VolumeScene::TileData* VolumeScene::getTileData(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile) +{ + osg::ref_ptr viewData; + { + OpenThreads::ScopedLock lock(_viewDataMapMutex); + viewData = _viewDataMap[cv]; + } - //OSG_NOTICE<<"Ready to traverse RTT Camera"<_rttCamera->getProjectionMatrix()<_rttCamera->accept(nv); + if (!viewData) return 0; - //OSG_NOTICE<<" RTT Camera ProjectionMatrix After "<_rttCamera->getProjectionMatrix()<getProjectionMatrix())<_tiles.find(tile); + return (itr != viewData->_tiles.end()) ? itr->second.get() : 0; +} - //OSG_NOTICE<<" after RTT near ="<getCalculatedNearPlane()<_tiles.size()<setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); - typedef osgUtil::CullVisitor::value_type NearFarValueType; - NearFarValueType calculatedNearPlane = std::numeric_limits::max(); - NearFarValueType calculatedFarPlane = -std::numeric_limits::max(); - if (viewData->_rttCamera->getUserValue("CalculatedNearPlane",calculatedNearPlane) && - viewData->_rttCamera->getUserValue("CalculatedFarPlane",calculatedFarPlane)) + osg::ref_ptr viewData; + bool initializeViewData = false; + { + OpenThreads::ScopedLock lock(_viewDataMapMutex); + if (!_viewDataMap[cv]) { - calculatedNearPlane *= 0.5; - calculatedFarPlane *= 2.0; - - //OSG_NOTICE<<"Got from RTTCamera CalculatedNearPlane="<getCurrentRenderStage()->getViewport(); + if (viewport) { - cv->clampProjectionMatrix(projectionMatrix, calculatedNearPlane, calculatedFarPlane); + textureWidth = viewport->width(); + textureHeight = viewport->height(); } - osg::Matrix inv_projectionModelViewMatrix; - inv_projectionModelViewMatrix.invert(modelviewMatrix*projectionMatrix); + // set up depth texture + viewData->_depthTexture = new osg::Texture2D; - double depth = 1.0; - osg::Vec3d v00 = osg::Vec3d(-1.0,-1.0,depth)*inv_projectionModelViewMatrix; - osg::Vec3d v01 = osg::Vec3d(-1.0,1.0,depth)*inv_projectionModelViewMatrix; - osg::Vec3d v10 = osg::Vec3d(1.0,-1.0,depth)*inv_projectionModelViewMatrix; - osg::Vec3d v11 = osg::Vec3d(1.0,1.0,depth)*inv_projectionModelViewMatrix; + viewData->_depthTexture->setTextureSize(textureWidth, textureHeight); + viewData->_depthTexture->setInternalFormat(GL_DEPTH_COMPONENT); + viewData->_depthTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); + viewData->_depthTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); - // OSG_NOTICE<<"v00= "<_tiles; - for(Tiles::iterator itr = tiles.begin(); - itr != tiles.end(); - ++itr) + // set up the RTT Camera to capture the main scene to a color and depth texture that can be used in post processing + viewData->_rttCamera = new osg::Camera; + viewData->_rttCamera->attach(osg::Camera::DEPTH_BUFFER, viewData->_depthTexture.get()); + viewData->_rttCamera->attach(osg::Camera::COLOR_BUFFER, viewData->_colorTexture.get()); + viewData->_rttCamera->setCullCallback(new RTTCameraCullCallback(this)); + viewData->_rttCamera->setViewport(0,0,textureWidth,textureHeight); + + // clear the depth and colour bufferson each clear. + viewData->_rttCamera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + // set the camera to render before the main camera. + viewData->_rttCamera->setRenderOrder(osg::Camera::PRE_RENDER); + + // tell the camera to use OpenGL frame buffer object where supported. + viewData->_rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + + + viewData->_rttCamera->setReferenceFrame(osg::Transform::RELATIVE_RF); + viewData->_rttCamera->setProjectionMatrix(osg::Matrixd::identity()); + viewData->_rttCamera->setViewMatrix(osg::Matrixd::identity()); + + // create mesh for rendering the RTT textures onto the screen + osg::ref_ptr geode = new osg::Geode; + geode->setCullingActive(false); + + viewData->_backdropSubgraph = geode; + //geode->addDrawable(osg::createTexturedQuadGeometry(osg::Vec3(-1.0f,-1.0f,-1.0f),osg::Vec3(2.0f,0.0f,-1.0f),osg::Vec3(0.0f,2.0f,-1.0f))); + + viewData->_geometry = new osg::Geometry; + geode->addDrawable(viewData->_geometry.get()); + + viewData->_geometry->setUseDisplayList(false); + viewData->_geometry->setUseVertexBufferObjects(false); + + viewData->_vertices = new osg::Vec3Array(4); + viewData->_geometry->setVertexArray(viewData->_vertices.get()); + + osg::ref_ptr colors = new osg::Vec4Array(1); + (*colors)[0].set(1.0f,1.0f,1.0f,1.0f); + viewData->_geometry->setColorArray(colors.get(), osg::Array::BIND_OVERALL); + + osg::ref_ptr texcoords = new osg::Vec2Array(4); + (*texcoords)[0].set(0.0f,1.0f); + (*texcoords)[1].set(0.0f,0.0f); + (*texcoords)[2].set(1.0f,1.0f); + (*texcoords)[3].set(1.0f,0.0f); + viewData->_geometry->setTexCoordArray(0, texcoords.get(), osg::Array::BIND_PER_VERTEX); + + viewData->_geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP,0,4)); + + + osg::ref_ptr stateset = viewData->_geometry->getOrCreateStateSet(); + + stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON); + stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + stateset->setRenderBinDetails(10,"DepthSortedBin"); + + osg::ref_ptr program = new osg::Program; + stateset->setAttribute(program); + + // get vertex shaders from source + osg::ref_ptr vertexShader = osgDB::readRefShaderFile(osg::Shader::VERTEX, "shaders/volume_color_depth.vert"); + if (vertexShader.valid()) { - TileData* tileData = itr->second.get(); - if (!tileData || !(tileData->active)) - { - OSG_NOTICE<<"Skipping TileData that is inactive : "<projectionMatrix.get()<<", "<modelviewMatrix.get()<nodePath; - - cv->getNodePath() = nodePath; - cv->pushProjectionMatrix(tileData->projectionMatrix.get()); - cv->pushModelViewMatrix(tileData->modelviewMatrix.get(), osg::Transform::ABSOLUTE_RF_INHERIT_VIEWPOINT); - - - cv->pushStateSet(viewData->_stateset.get()); - ++numStateSetPushed; - - - osg::NodePath::iterator np_itr = nodePath.begin(); - - // skip over all nodes above VolumeScene as this will have already been traverse by CullVisitor - while(np_itr!=nodePath.end() && (*np_itr)!=viewData->_rttCamera.get()) { ++np_itr; } - if (np_itr!=nodePath.end()) ++np_itr; - - // push the stateset on the nodes between this VolumeScene and the VolumeTile - for(osg::NodePath::iterator ss_itr = np_itr; - ss_itr != nodePath.end(); - ++ss_itr) - { - if ((*ss_itr)->getStateSet()) - { - numStateSetPushed++; - cv->pushStateSet((*ss_itr)->getStateSet()); - // OSG_NOTICE<<" pushing StateSet"<traverse(*(tileData->nodePath.back())); - - // pop the StateSet's - for(unsigned int i=0; ipopStateSet(); - // OSG_NOTICE<<" popping StateSet"<popModelViewMatrix(); - cv->popProjectionMatrix(); + program->addShader(vertexShader.get()); } +#if 0 + else + { + #include "Shaders/volume_color_depth_vert.cpp" + program->addShader(new osg::Shader(osg::Shader::VERTEX, volume_color_depth_vert)); + } +#endif + // get fragment shaders from source + osg::ref_ptr fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_color_depth.frag"); + if (fragmentShader.valid()) + { + program->addShader(fragmentShader.get()); + } +#if 0 + else + { + #include "Shaders/volume_color_depth_frag.cpp" + program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_color_depth_frag)); + } +#endif + viewData->_stateset = new osg::StateSet; + viewData->_stateset->addUniform(new osg::Uniform("colorTexture",0)); + viewData->_stateset->addUniform(new osg::Uniform("depthTexture",1)); + + viewData->_stateset->setTextureAttributeAndModes(0, viewData->_colorTexture.get(), osg::StateAttribute::ON); + viewData->_stateset->setTextureAttributeAndModes(1, viewData->_depthTexture.get(), osg::StateAttribute::ON); + + viewData->_viewportDimensionsUniform = new osg::Uniform("viewportDimensions",osg::Vec4(0.0,0.0,1280.0,1024.0)); + viewData->_stateset->addUniform(viewData->_viewportDimensionsUniform.get()); + + geode->setStateSet(viewData->_stateset.get()); - cv->getNodePath() = nodePathPriorToTraversingSubgraph; } else { - Group::traverse(nv); + // OSG_NOTICE<<"Reusing ViewData"<getProjectionMatrix()); + osg::Matrix modelviewMatrix = *(cv->getModelViewMatrix()); + + + // new frame so need to clear last frames log of VolumeTiles + viewData->clearTiles(); + + osg::Viewport* viewport = cv->getCurrentRenderStage()->getViewport(); + if (viewport) + { + viewData->_viewportDimensionsUniform->set(osg::Vec4(viewport->x(), viewport->y(), viewport->width(),viewport->height())); + + if (viewport->width() != viewData->_colorTexture->getTextureWidth() || + viewport->height() != viewData->_colorTexture->getTextureHeight()) + { + OSG_NOTICE<<"Need to change texture size to "<width()<<", "<< viewport->height()<_colorTexture->setTextureSize(viewport->width(), viewport->height()); + viewData->_colorTexture->dirtyTextureObject(); + viewData->_depthTexture->setTextureSize(viewport->width(), viewport->height()); + viewData->_depthTexture->dirtyTextureObject(); + viewData->_rttCamera->setViewport(0, 0, viewport->width(), viewport->height()); + if (viewData->_rttCamera->getRenderingCache()) + { + viewData->_rttCamera->getRenderingCache()->releaseGLObjects(0); + } + } + } + + cv->setUserValue("VolumeSceneTraversal",std::string("RenderToTexture")); + + osg::Camera* parentCamera = cv->getCurrentCamera(); + viewData->_rttCamera->setClearColor(parentCamera->getClearColor()); + + //OSG_NOTICE<<"Ready to traverse RTT Camera"<_rttCamera->getProjectionMatrix()<_rttCamera->accept(nv); + + //OSG_NOTICE<<" RTT Camera ProjectionMatrix After "<_rttCamera->getProjectionMatrix()<getProjectionMatrix())<_tiles.size()<::max(); + NearFarValueType calculatedFarPlane = -std::numeric_limits::max(); + if (viewData->_rttCamera->getUserValue("CalculatedNearPlane",calculatedNearPlane) && + viewData->_rttCamera->getUserValue("CalculatedFarPlane",calculatedFarPlane)) + { + calculatedNearPlane *= 0.5; + calculatedFarPlane *= 2.0; + + //OSG_NOTICE<<"Got from RTTCamera CalculatedNearPlane="<_tiles; + for(Tiles::iterator itr = tiles.begin(); + itr != tiles.end(); + ++itr) + { + TileData* tileData = itr->second.get(); + if (!tileData || !(tileData->active)) + { + OSG_INFO<<"Skipping TileData that is inactive : "<projectionMatrix.get()<<", "<modelviewMatrix.get()<nodePath; + + cv->getNodePath() = nodePath; + cv->pushProjectionMatrix(tileData->projectionMatrix.get()); + cv->pushModelViewMatrix(tileData->modelviewMatrix.get(), osg::Transform::ABSOLUTE_RF_INHERIT_VIEWPOINT); + + + cv->pushStateSet(viewData->_stateset.get()); + ++numStateSetPushed; + + cv->pushStateSet(tileData->stateset.get()); + ++numStateSetPushed; + + osg::NodePath::iterator np_itr = nodePath.begin(); + + // skip over all nodes above VolumeScene as this will have already been traverse by CullVisitor + while(np_itr!=nodePath.end() && (*np_itr)!=viewData->_rttCamera.get()) { ++np_itr; } + if (np_itr!=nodePath.end()) ++np_itr; + + // push the stateset on the nodes between this VolumeScene and the VolumeTile + for(osg::NodePath::iterator ss_itr = np_itr; + ss_itr != nodePath.end(); + ++ss_itr) + { + if ((*ss_itr)->getStateSet()) + { + numStateSetPushed++; + cv->pushStateSet((*ss_itr)->getStateSet()); + // OSG_NOTICE<<" pushing StateSet"<traverse(*(tileData->nodePath.back())); + + // pop the StateSet's + for(unsigned int i=0; ipopStateSet(); + // OSG_NOTICE<<" popping StateSet"<popModelViewMatrix(); + cv->popProjectionMatrix(); + } + + // need to synchronize projection matrices: + // current CV projection matrix + // main scene RTT Camera projection matrix + // each tile RTT Camera + // each tile final render. + + cv->getNodePath() = nodePathPriorToTraversingSubgraph; + + // restore the previous cull settings + cv->setCullSettings(saved_cull_settings); }