Restructured the handling of TileData to make it more extensible and flexible.

This commit is contained in:
Robert Osfield 2014-03-19 17:56:40 +00:00
parent d7944b6ca9
commit 2f8b0f7a70
5 changed files with 157 additions and 90 deletions

View File

@ -19,6 +19,24 @@
namespace osgVolume { 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<osg::Texture2D> frontFaceDepthTexture;
osg::ref_ptr<osg::Camera> frontFaceRttCamera;
osg::ref_ptr<osg::Texture2D> backFaceDepthTexture;
osg::ref_ptr<osg::Camera> backFaceRttCamera;
osg::ref_ptr<osg::Uniform> texgenUniform;
};
class OSGVOLUME_EXPORT MultipassTechnique : public VolumeTechnique class OSGVOLUME_EXPORT MultipassTechnique : public VolumeTechnique
{ {
public: public:
@ -43,6 +61,10 @@ class OSGVOLUME_EXPORT MultipassTechnique : public VolumeTechnique
/** Traverse the terrain subgraph.*/ /** Traverse the terrain subgraph.*/
virtual void traverse(osg::NodeVisitor& nv); 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: protected:
virtual ~MultipassTechnique(); virtual ~MultipassTechnique();

View File

@ -36,24 +36,8 @@ class OSGVOLUME_EXPORT VolumeScene : public osg::Group
virtual void traverse(osg::NodeVisitor& nv); virtual void traverse(osg::NodeVisitor& nv);
struct TileData : public osg::Referenced TileData* tileVisited(osgUtil::CullVisitor* cv, VolumeTile* tile);
{ TileData* getTileData(osgUtil::CullVisitor* cv, VolumeTile* tile);
TileData() : active(false) {}
bool active;
osg::NodePath nodePath;
osg::ref_ptr<osg::RefMatrix> projectionMatrix;
osg::ref_ptr<osg::RefMatrix> modelviewMatrix;
osg::ref_ptr<osg::Texture2D> depthTexture;
osg::ref_ptr<osg::Camera> rttCamera;
osg::ref_ptr<osg::StateSet> stateset;
osg::ref_ptr<osg::Uniform> texgenUniform;
};
TileData* tileVisited(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile);
TileData* getTileData(osgUtil::CullVisitor* cv, osgVolume::VolumeTile* tile);
protected: protected:

View File

@ -25,6 +25,23 @@ namespace osgVolume {
class VolumeTile; 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<osg::RefMatrix> projectionMatrix;
osg::ref_ptr<osg::RefMatrix> modelviewMatrix;
osg::ref_ptr<osg::StateSet> stateset;
};
class OSGVOLUME_EXPORT VolumeTechnique : public osg::Object class OSGVOLUME_EXPORT VolumeTechnique : public osg::Object
{ {
public: public:
@ -53,6 +70,10 @@ class OSGVOLUME_EXPORT VolumeTechnique : public osg::Object
/** Traverse the terrain subgraph.*/ /** Traverse the terrain subgraph.*/
virtual void traverse(osg::NodeVisitor& nv); 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: protected:
void setDirty(bool dirty); void setDirty(bool dirty);

View File

@ -147,7 +147,97 @@ osg::Image* createDownsampledImage(osg::Image* sourceImage)
return targetImage.release(); 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<int>(viewport->width());
height = static_cast<int>(viewport->height());
}
osg::ref_ptr<osg::Texture2D> 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<osg::Camera> 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<int>(viewport->width());
height = static_cast<int>(viewport->height());
}
if (frontFaceDepthTexture.valid())
{
if (frontFaceDepthTexture->getTextureWidth()!=width || frontFaceDepthTexture->getTextureHeight()!=height)
{
OSG_NOTICE<<"Need to change texture size to "<<width<<", "<<height<<std::endl;
frontFaceDepthTexture->setTextureSize(width, height);
frontFaceRttCamera->setViewport(0, 0, width, height);
if (frontFaceRttCamera->getRenderingCache())
{
frontFaceRttCamera->getRenderingCache()->releaseGLObjects(0);
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// MultipassTechnique
//
MultipassTechnique::MultipassTechnique() MultipassTechnique::MultipassTechnique()
{ {
} }
@ -678,7 +768,7 @@ class RTTBackfaceCameraCullCallback : public osg::NodeCallback
{ {
public: public:
RTTBackfaceCameraCullCallback(VolumeScene::TileData* tileData, MultipassTechnique* mt): RTTBackfaceCameraCullCallback(MultipassTileData* tileData, MultipassTechnique* mt):
_tileData(tileData), _tileData(tileData),
_mt(mt) {} _mt(mt) {}
@ -697,7 +787,7 @@ class RTTBackfaceCameraCullCallback : public osg::NodeCallback
virtual ~RTTBackfaceCameraCullCallback() {} virtual ~RTTBackfaceCameraCullCallback() {}
osg::observer_ptr<osgVolume::VolumeScene::TileData> _tileData; osg::observer_ptr<osgVolume::MultipassTileData> _tileData;
osg::observer_ptr<osgVolume::MultipassTechnique> _mt; osg::observer_ptr<osgVolume::MultipassTechnique> _mt;
}; };
@ -720,16 +810,16 @@ void MultipassTechnique::cull(osgUtil::CullVisitor* cv)
{ {
if (vs) if (vs)
{ {
VolumeScene::TileData* tileData = vs->tileVisited(cv, getVolumeTile()); MultipassTileData* tileData = dynamic_cast<MultipassTileData*>(vs->tileVisited(cv, getVolumeTile()));
if (tileData->rttCamera.valid()) 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 // traverse RTT Camera
tileData->rttCamera->accept(*cv); tileData->frontFaceRttCamera->accept(*cv);
} }
osg::BoundingBox bb; osg::BoundingBox bb;
@ -776,7 +866,7 @@ void MultipassTechnique::cull(osgUtil::CullVisitor* cv)
if (vs) if (vs)
{ {
VolumeScene::TileData* tileData = vs->getTileData(cv, getVolumeTile()); MultipassTileData* tileData = dynamic_cast<MultipassTileData*>(vs->getTileData(cv, getVolumeTile()));
if (tileData) if (tileData)
{ {
Locator* layerLocator = _volumeTile->getLayer()->getLocator(); Locator* layerLocator = _volumeTile->getLayer()->getLocator();

View File

@ -49,6 +49,10 @@ class RTTCameraCullCallback : public osg::NodeCallback
}; };
////////////////////////////////////////////////////////////////////////
//
// VolumeScene::ViewData
//
VolumeScene::ViewData::ViewData() VolumeScene::ViewData::ViewData()
{ {
} }
@ -67,6 +71,10 @@ void VolumeScene::ViewData::visitTile(VolumeTile* tile)
{ {
} }
////////////////////////////////////////////////////////////////////////
//
// VolumeScene
//
VolumeScene::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> viewData; osg::ref_ptr<ViewData> viewData;
@ -95,73 +103,15 @@ VolumeScene::TileData* VolumeScene::tileVisited(osgUtil::CullVisitor* cv, osgVol
if (viewData.valid()) if (viewData.valid())
{ {
int textureWidth = 512;
int textureHeight = 512;
osg::Viewport* viewport = cv->getCurrentRenderStage()->getViewport();
if (viewport)
{
textureWidth = static_cast<int>(viewport->width());
textureHeight = static_cast<int>(viewport->height());
}
osg::ref_ptr<TileData>& tileData = viewData->_tiles[tile]; osg::ref_ptr<TileData>& tileData = viewData->_tiles[tile];
if (!tileData) if (!tileData)
{ {
tileData = new TileData; tileData = tile->getVolumeTechnique() ? tile->getVolumeTechnique()->createTileData(cv) : 0;
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->active = true; if (tileData)
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) tileData->update(cv);
{
OSG_NOTICE<<"Need to change texture size to "<<textureHeight<<", "<<textureWidth<<std::endl;
tileData->depthTexture->setTextureSize(textureWidth, textureHeight);
tileData->rttCamera->setViewport(0, 0, textureWidth, textureHeight);
if (tileData->rttCamera->getRenderingCache())
{
tileData->rttCamera->getRenderingCache()->releaseGLObjects(0);
}
}
} }
return tileData.get(); return tileData.get();
@ -169,7 +119,7 @@ VolumeScene::TileData* VolumeScene::tileVisited(osgUtil::CullVisitor* cv, osgVol
return 0; 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> viewData; osg::ref_ptr<ViewData> viewData;
{ {
@ -479,7 +429,7 @@ void VolumeScene::traverse(osg::NodeVisitor& nv)
osg::NodePath::iterator np_itr = nodePath.begin(); 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; } while(np_itr!=nodePath.end() && (*np_itr)!=viewData->_rttCamera.get()) { ++np_itr; }
if (np_itr!=nodePath.end()) ++np_itr; if (np_itr!=nodePath.end()) ++np_itr;