Commit a508ea96 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[CHANGE] - reformed offscreen render mechanism. Now more modular with less typing.

parent c02f32b1
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include "callbacks/WGEViewportCallback.h"
#include "WGEOffscreenRenderNode.h"
WGEOffscreenRenderNode::WGEOffscreenRenderNode( osg::ref_ptr< osg::Camera > reference, size_t width, size_t height, bool noHud ):
WGEGroupNode(),
m_referenceCamera( reference ),
m_hud( new WGETextureHud() ),
m_textureWidth( width ),
m_textureHeight( height ),
m_nextPassNum( 0 )
{
// initialize members
if ( !noHud )
{
m_hud->addUpdateCallback( new WGEViewportCallback< WGETextureHud >( m_referenceCamera ) );
insert( m_hud );
}
}
WGEOffscreenRenderNode::~WGEOffscreenRenderNode()
{
// cleanup
}
osg::ref_ptr< WGEOffscreenRenderPass > WGEOffscreenRenderNode::addGeometryRenderPass( osg::ref_ptr< osg::Node > node )
{
osg::ref_ptr< WGEOffscreenRenderPass > pass = new WGEOffscreenRenderPass( m_textureWidth, m_textureHeight, m_hud, m_nextPassNum );
m_nextPassNum++;
pass->addChild( node );
insert( pass ); // insert into this group
// ensure proper propagation of viewport changes
pass->addUpdateCallback( new WGEViewportCallback< WGEOffscreenRenderPass >( m_referenceCamera ) );
return pass;
}
osg::ref_ptr< WGEOffscreenRenderPass > WGEOffscreenRenderNode::addTextureProcessingPass()
{
osg::ref_ptr< WGEOffscreenRenderPass > pass = new WGEOffscreenRenderPass( m_textureWidth, m_textureHeight, m_hud, m_nextPassNum );
m_nextPassNum++;
insert( pass ); // insert into this group
// we need to create a nice quad for texture processing spanning the whole texture space
// ensure proper propagation of viewport changes
pass->addUpdateCallback( new WGEViewportCallback< WGEOffscreenRenderPass >( m_referenceCamera ) );
return pass;
}
WGEOffscreenRenderNode::ViewportUpdate::ViewportUpdate( osg::ref_ptr< osg::Camera > reference ):
osg::NodeCallback(),
m_reference( reference )
{
// initialize members
}
void WGEOffscreenRenderNode::ViewportUpdate::operator()( osg::Node* node, osg::NodeVisitor* nv )
{
osg::ref_ptr< osg::Camera > cam = dynamic_cast< osg::Camera* >( node );
cam->setViewport( m_reference->getViewport() );
traverse( node, nv );
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WGEOFFSCREENRENDERNODE_H
#define WGEOFFSCREENRENDERNODE_H
#include <osg/Camera>
#include "WGEGroupNode.h"
#include "WGEOffscreenRenderPass.h"
#include "WGETextureHud.h"
/**
* This type of node basically is a convenience class for managing and creating offscreen renderings. The children of this node should be of type
* \ref WGEOffscreenPass. This class provides factories to create offscreen-render-pass instances with proper sizes with a coupling to a
* reference camera. This is useful to provide automatic viewport scaling etc. to each render-pass. You do not explicitly need this class to
* create offscreen-renderings at all. You can manually manage multiple WGEOffscreenPass instances.
*
* It is important to understand, that the graph (your scene) must not be a children of this node. This node can be placed somewhere in your
* scene. The OSG collects all the cameras (and offscreen-cameras) and render then independently from their position in the graph (except for
* transformations inherited from others).
*
* \note Please not that you should not modify the whole wiring and offscreen configuration if the this node has been added as it is not
* thread-safe.
*/
class WGEOffscreenRenderNode: public WGEGroupNode
{
public:
/**
* Create a new managing instance. It uses the specified camera as reference to all created offscreen-render-pass instances. Especially
* viewport, clear-mask and clear-color get used.
*
* \param reference camera used as reference
* \param width the width of the textures used in this rendering
* \param height the height of the textures used in this rendering*
* \param noHud If true, no hud gets displayed showing the created and used textures.
*/
WGEOffscreenRenderNode( osg::ref_ptr< osg::Camera > reference, size_t width, size_t height, bool noHud = false );
/**
* Destructor.
*/
virtual ~WGEOffscreenRenderNode();
/**
* Creates a new offscreen-render-pass coupled with the reference camera which renders a specified OSG graph to a texture.
*
* \param node the node which represents the subgraph.
*
* \note never forget to remove the returned node if not used anymore or use WGEGroup::clean.
*
* \return the geometry render pass.
*/
virtual osg::ref_ptr< WGEOffscreenRenderPass > addGeometryRenderPass( osg::ref_ptr< osg::Node > node );
/**
* Creates a new offscreen-render-pass coupled with the reference camera which simply processes textures. All the in- and output textures
* have to be specified manually.
*
* \note never forget to remove the returned node if not used anymore or use WGEGroup::clean.
*
* \return the texture processing pass created.
*/
virtual osg::ref_ptr< WGEOffscreenRenderPass > addTextureProcessingPass();
protected:
private:
/**
* The camera to which is used for setting this camera up.
*/
osg::ref_ptr< osg::Camera > m_referenceCamera;
/**
* The pointer to the hud used to render all used texture buffers. This can be NULL. It gets distributed to all created render-pass
* instances.
*/
osg::ref_ptr< WGETextureHud > m_hud;
/**
* The width of each texture in this offscreen rendering.
*/
size_t m_textureWidth;
/**
* The height of each texture in this offscreen rendering.
*/
size_t m_textureHeight;
/**
* The number of the next pass getting added.
*/
size_t m_nextPassNum;
/**
* Callback which sets the viewport of the camera to the viewport of the reference camera. It gets added to each created render pass to
* ensure proper viewport adoption.
*/
class ViewportUpdate: public osg::NodeCallback
{
public: // NOLINT
/**
* Creates new instance of viewport callback.
*
* \param reference set the viewport to the one of the reference camera.
*/
explicit ViewportUpdate( osg::ref_ptr< osg::Camera > reference );
/**
* This operator gets called by OSG every update cycle. It applies the viewport.
*
* \param node the osg node
* \param nv the node visitor
*/
virtual void operator()( osg::Node* node, osg::NodeVisitor* nv );
private: // NOLINT
/**
* The reference camera to use.
*/
osg::ref_ptr< osg::Camera > m_reference;
};
};
#endif // WGEOFFSCREENRENDERNODE_H
......@@ -25,51 +25,89 @@
#include <osg/Texture>
#include <osg/Texture2D>
#include "WGEOffscreen.h"
#include "WGETextureHud.h"
WGEOffscreen::WGEOffscreen( osg::ref_ptr< osg::Camera > reference, int num ):
#include "WGEOffscreenRenderPass.h"
WGEOffscreenRenderPass::WGEOffscreenRenderPass( size_t textureWidth, size_t textureHeight, int num ):
osg::Camera(),
m_referenceCamera( reference ),
m_fbo( new osg::FrameBufferObject() )
m_width( textureWidth ),
m_height( textureHeight ),
m_fbo( new osg::FrameBufferObject() ),
m_hud( NULL )
{
// initialize members
setClearColor( reference->getClearColor() );
setClearMask( reference->getClearMask() );
setClearColor( osg::Vec4( 0.0, 0.0, 0.0, 0.0 ) );
setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
setReferenceFrame( osg::Transform::RELATIVE_RF );
setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
setRenderOrder( osg::Camera::PRE_RENDER, num );
}
WGEOffscreen::~WGEOffscreen()
WGEOffscreenRenderPass::WGEOffscreenRenderPass( size_t textureWidth, size_t textureHeight, osg::ref_ptr< WGETextureHud > hud, int num ):
osg::Camera(),
m_width( textureWidth ),
m_height( textureHeight ),
m_fbo( new osg::FrameBufferObject() ),
m_hud( hud )
{
// initialize members
setClearColor( osg::Vec4( 0.0, 0.0, 0.0, 0.0 ) );
setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
setReferenceFrame( osg::Transform::RELATIVE_RF );
setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
setRenderOrder( osg::Camera::PRE_RENDER, num );
}
WGEOffscreenRenderPass::~WGEOffscreenRenderPass()
{
// cleanup
}
void WGEOffscreen::attach( BufferComponent buffer, osg::ref_ptr< osg::Texture2D > texture )
void WGEOffscreenRenderPass::attach( BufferComponent buffer, osg::ref_ptr< osg::Texture2D > texture )
{
m_fbo->setAttachment( buffer, osg::FrameBufferAttachment( texture ) );
if ( m_hud )
{
m_hud->addTexture( new WGETextureHud::WGETextureHudEntry( texture ) );
}
osg::Camera::attach( buffer, texture );
}
osg::ref_ptr< osg::Texture2D > WGEOffscreen::attach( BufferComponent buffer )
osg::ref_ptr< osg::Texture2D > WGEOffscreenRenderPass::attach( BufferComponent buffer )
{
osg::ref_ptr< osg::Texture2D > tex = createTexture();
osg::ref_ptr< osg::Texture2D > tex;
if ( buffer == DEPTH_BUFFER ) // depth buffers need a special texture type (else: FBO status = 0x8cd6 (FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT))
{
tex = createTexture( GL_DEPTH_COMPONENT );
}
else
{
tex = createTexture();
}
attach( buffer, tex );
return tex;
}
void WGEOffscreen::detach( BufferComponent buffer )
void WGEOffscreenRenderPass::detach( BufferComponent buffer )
{
// remove the texture from hud if existing
if ( m_hud && osg::Camera::getBufferAttachmentMap().count( buffer ) )
{
m_hud->removeTexture( osg::Camera::getBufferAttachmentMap()[ buffer ]._texture );
}
m_fbo->setAttachment( buffer, osg::FrameBufferAttachment() );
osg::Camera::detach( buffer );
}
osg::ref_ptr< osg::Texture2D > WGEOffscreen::createTexture( GLint internalFormat )
osg::ref_ptr< osg::Texture2D > WGEOffscreenRenderPass::createTexture( GLint internalFormat )
{
osg::ref_ptr< osg::Texture2D > tex = new osg::Texture2D;
tex->setTextureSize( m_referenceCamera->getViewport()->width(), m_referenceCamera->getViewport()->height() );
tex->setTextureSize( m_width, m_height );
tex->setInternalFormat( internalFormat );
// setup interpolation
......
......@@ -22,33 +22,50 @@
//
//---------------------------------------------------------------------------
#ifndef WGEOFFSCREEN_H
#define WGEOFFSCREEN_H
#ifndef WGEOFFSCREENRENDERPASS_H
#define WGEOFFSCREENRENDERPASS_H
#include <osg/Camera>
#include <osg/FrameBufferObject>
class WGETextureHud;
/**
* This class encapsulates an OSG Camera and a corresponding framebuffer object. It is especially useful for offscreen renderings. It is a camera
* which, by default, is the same as the camera in the this instance nesting graph. It allows simple attachment of textures to a offscreen
* rendering as well as easy texture creation.
* rendering as well as easy texture creation. It builds the base for \ref WGEOffscreenRenderPassGeometry and \ref WGEOffscreenRenderPassTexture.
*/
class WGEOffscreen: public osg::Camera
class WGEOffscreenRenderPass: public osg::Camera
{
public:
/**
* Creates a new offscreen rendering instance. It uses the specified camera for setup.
* Creates a new offscreen rendering instance.
*
* \param textureWidth the width of all the textures created and used by this render pass. This should be large enough for every reasonable
* viewport size.
* \param textureHeight the height of all the textures created and used by this render pass. This should be large enough for every reasonable
* viewport size.*
* \param num the order number. This camera gets rendered at the num'th place in the pre render queue of the subgraph it is attached to.
*/
WGEOffscreenRenderPass( size_t textureWidth, size_t textureHeight, int num = 0 );
/**
* Creates a new offscreen rendering instance.
*
* \param reference the reference camera.
* \param textureWidth the width of all the textures created and used by this render pass. This should be large enough for every reasonable
* viewport size.
* \param textureHeight the height of all the textures created and used by this render pass. This should be large enough for every reasonable
* viewport size.*
* \param num the order number. This camera gets rendered at the num'th place in the pre render queue of the subgraph it is attached to.
* \param hud the hud that gets notified about attached and detached textures. Useful for debugging.
*/
WGEOffscreen( osg::ref_ptr< osg::Camera > reference, int num = 0 );
WGEOffscreenRenderPass( size_t textureWidth, size_t textureHeight, osg::ref_ptr< WGETextureHud > hud, int num = 0 );
/**
* Destructor.
*/
virtual ~WGEOffscreen();
virtual ~WGEOffscreenRenderPass();
/**
* Attach a given texture to a buffer.
......@@ -92,17 +109,27 @@ public:
protected:
/**
* The camera to which is used for setting this camera up.
* The width of the textures used for this pass. This should be as large as needed for each "common" viewport."
*/
osg::ref_ptr< osg::Camera > m_referenceCamera;
size_t m_width;
/**
* The height of the textures used for this pass. This should be as large as needed for each "common" viewport."
*/
size_t m_height;
/**
* The framebuffer object to use for this camera.
*/
osg::ref_ptr<osg::FrameBufferObject> m_fbo;
/**
* Gets notified about any added and removed attachment
*/
osg::ref_ptr< WGETextureHud > m_hud;
private:
};
#endif // WGEOFFSCREEN_H
#endif // WGEOFFSCREENRENDERPASS_H
......@@ -35,7 +35,8 @@
WGETextureHud::WGETextureHud():
osg::Projection(),
m_group( new WGEGroupNode ),
m_maxElementWidth( 256 )
m_maxElementWidth( 256 ),
m_viewport( new osg::Viewport() )
{
getOrCreateStateSet()->setRenderBinDetails( 1000, "RenderBin" );
m_group->addUpdateCallback( new SafeUpdateCallback( this ) );
......@@ -53,8 +54,8 @@ void WGETextureHud::SafeUpdateCallback::operator()( osg::Node* node, osg::NodeVi
// TODO(ebaum): use shader to selectively render channels ( if one only wants to see the alpha channel for example).
// set the new size of the widget (how can we get this data?)
unsigned int screenWidth = 1024;
unsigned int screenHeight = 768;
unsigned int screenWidth = m_hud->m_viewport->width();
unsigned int screenHeight = m_hud->m_viewport->height();
m_hud->setMatrix( osg::Matrix::ortho2D( 0, screenWidth, 0, screenHeight ) );
// border around each element
......@@ -107,6 +108,16 @@ void WGETextureHud::removeTexture( osg::ref_ptr< WGETextureHudEntry > texture )
m_group->remove( texture );
}
void WGETextureHud::removeTexture( osg::ref_ptr< osg::Texture > texture )
{
// TODO(ebaum): implement me.
}
void WGETextureHud::setViewport( osg::Viewport* viewport )
{
m_viewport = viewport;
}
WGETextureHud::WGETextureHudEntry::WGETextureHudEntry( osg::ref_ptr< osg::Texture2D > texture, bool transparency ):
osg::MatrixTransform(),
m_texture( texture )
......
......@@ -112,6 +112,13 @@ public:
*/
void removeTexture( osg::ref_ptr< WGETextureHudEntry > texture );
/**
* Remove the texture from the HUD.
*
* \param texture the texture to remove.
*/
void removeTexture( osg::ref_ptr< osg::Texture > texture );
/**
* Gets the maximum width of a tex element.
*
......@@ -126,6 +133,14 @@ public:
*/
void setMaxElementWidth( unsigned int width );
/**
* Sets the viewport of the camera housing this HUD. It is needed to have proper scaling of each texture tile. You can use
* \ref WGEViewportCallback to handle this automatically.
*
* \param viewport the viewport
*/
void setViewport( osg::Viewport* viewport );
protected:
/**
......@@ -139,6 +154,10 @@ protected:
*/
unsigned int m_maxElementWidth;
/**
* The current viewport of
*/
osg::Viewport* m_viewport;
private:
/**
......
......@@ -39,6 +39,8 @@
#include "../../dataHandler/WGridRegular3D.h"
#include "../../graphicsEngine/callbacks/WGELinearTranslationCallback.h"
#include "../../graphicsEngine/WGEGeodeUtils.h"
#include "../../graphicsEngine/WGEOffscreenRenderPass.h"
#include "../../graphicsEngine/WGEOffscreenRenderNode.h"
#include "WMImageSpaceLIC.h"
#include "WMImageSpaceLIC.xpm"
......@@ -158,10 +160,48 @@ void WMImageSpaceLIC::moduleMain()
ready();
// init OSG Stuff
// create the root node for all the geometry
m_output = osg::ref_ptr< WGEManagedGroupNode > ( new WGEManagedGroupNode( m_active ) );
// the WGEOffscreenRenderNode manages each of the render-passes for us
osg::ref_ptr< WGEOffscreenRenderNode > offscreen = new WGEOffscreenRenderNode(
WKernel::getRunningKernel()->getGraphicsEngine()->getViewer()->getCamera(),
1024,
1024
);
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( offscreen );
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_output );
// setup all the passes needed for image space advection
osg::ref_ptr< WGEOffscreenRenderPass > transformation = offscreen->addGeometryRenderPass( m_output );
/*osg::ref_ptr< WGEOffscreen > edgeDetection = new WGEOffscreen( WKernel::getRunningKernel()->getGraphicsEngine()->getViewer()->getCamera(), 1 );
osg::ref_ptr< WGEOffscreen > advection = new WGEOffscreen( WKernel::getRunningKernel()->getGraphicsEngine()->getViewer()->getCamera(), 2 );
osg::ref_ptr< WGEOffscreen > blending = new WGEOffscreen( WKernel::getRunningKernel()->getGraphicsEngine()->getViewer()->getCamera(), 3 );*/
// the first render-pass needs the geometry
// transformation->addChild( m_output );
// the others need a slice as large as the viewport on which the textures are projected so that the fragment shader can pass each fragment
// each pass needs to be rendered. The order of rendering is defined by the second construction argument
//WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( transformation );
//WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( edgeDetection );
//WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( advection );
//WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( blending );
// hardwire the textures to use for each pass:
// Transformation Pass, needs Geometry
// * Creates 2D projected Vectors in RG
// * Lighting in B
// * Noise mapping in A
// * Depth
osg::ref_ptr< osg::Texture2D > transformationOut1 = transformation->attach( osg::Camera::COLOR_BUFFER0 );
osg::ref_ptr< osg::Texture2D > transformationDepth = transformation->attach( osg::Camera::DEPTH_BUFFER );
// Edge Detection Pass, needs Depth
// * Depth in R
// * Edges in G
// osg::ref_ptr< osg::Texture2D > edgeDetectionOut1 = edgeDetection->attach( COLOR_BUFFER0 );
// main loop
while ( !m_shutdownFlag() )
{
......@@ -196,6 +236,7 @@ void WMImageSpaceLIC::moduleMain()
}
// clean up
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_output );
offscreen->clear();
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( offscreen );
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment