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

[ADD] - removed old ugly postprocessing code. This is now modularized. Removes...

[ADD] - removed old ugly postprocessing code. This is now modularized. Removes some not very useful postprocessors. Will soon write a small tutorial in wiki how to program own postprocessors.
parent 42531011
......@@ -26,8 +26,20 @@
#include <osg/Geode>
#include "../../common/WAssert.h"
#include "WGEOffscreenRenderNode.h"
bool isPowerOfTwo( size_t x )
{
return ( (x != 0 ) && ( (x & ( ~x + 1 ) ) == x ) );
}
bool checkTextureSize( size_t size )
{
return !( ( size > 4096 ) || ( size < 8 ) || !isPowerOfTwo( size ) );
}
WGEOffscreenRenderNode::WGEOffscreenRenderNode( osg::ref_ptr< osg::Camera > reference, size_t width, size_t height, bool noHud ):
WGEGroupNode(),
m_referenceCamera( reference ),
......@@ -36,6 +48,8 @@ WGEOffscreenRenderNode::WGEOffscreenRenderNode( osg::ref_ptr< osg::Camera > refe
m_textureHeight( height ),
m_nextPassNum( 0 )
{
WAssert( checkTextureSize( width ) && checkTextureSize( height ), "Invalid offscreen texture size. Must be power of two and in [8,4096]." );
// initialize members
m_hud = new WGETextureHud();
if( !noHud )
......
......@@ -69,9 +69,13 @@ public:
* viewport, clear-mask and clear-color get used. The default texture resolution is 2048x2048 which is more than full-HD resolution. So it
* should be enough.
*
* \note The width and hight define the offscreen texture size. The viewport if each rendering is automatically set to the one of the
* reference camera. This means, width and height only define the maximal supported resolution without upscaling of your offscreen renderer.
*
* \param reference camera used as reference
* \param width the width of the textures used in this rendering. The real used space is determined by the reference camera.
* \param height the height of the textures used in this rendering. The real used space is determined by the reference camera.
* \param width the width of the textures used in this rendering. Must be in [8,4096] and a power of two.
* \param height the height of the textures used in this rendering. Must be in [8,4096] and a power of two.
*
* \param noHud If true, no hud gets displayed showing the created and used textures.
*/
WGEOffscreenRenderNode( osg::ref_ptr< osg::Camera > reference, size_t width = 2048, size_t height = 2048, bool noHud = false );
......
......@@ -22,101 +22,91 @@
//
//---------------------------------------------------------------------------
#include <string>
#include <vector>
#include "../../common/WPropertyHelper.h"
#include "../../common/WItemSelection.h"
#include "../shaders/WGEShaderPropertyDefineOptions.h"
#include "../callbacks/WGENodeMaskCallback.h"
#include "../WGEUtils.h"
#include "WGEPostprocessor.h"
#include "WGEPostprocessingNode.h"
WGEPostprocessingNode::WGEPostprocessingNode( osg::ref_ptr< osg::Camera > reference, size_t width, size_t height, bool noHud ):
osg::Switch(),
m_offscreen( new WGEOffscreenRenderNode( reference, width, height, noHud ) ),
m_childs( new WGEGroupNode() ),
m_postProcessShader( new WGEShader( "WGEPostprocessor" ) ),
m_properties( boost::shared_ptr< WProperties >( new WProperties( "Post-processing", "Post-processing properties" ) ) )
{
// create both render pass
m_render = m_offscreen->addGeometryRenderPass(
m_childs,
"Rendered"
);
m_postprocess = m_offscreen->addFinalOnScreenPass( m_postProcessShader, "Post-processed" );
// link them together with the corresponding textures
osg::ref_ptr< osg::Texture2D > renderColorTexture = m_render->attach( osg::Camera::COLOR_BUFFER0 );
osg::ref_ptr< osg::Texture2D > renderNormalTexture = m_render->attach( osg::Camera::COLOR_BUFFER1, GL_RGB );
osg::ref_ptr< osg::Texture2D > renderParameterTexture = m_render->attach( osg::Camera::COLOR_BUFFER2, GL_LUMINANCE );
osg::ref_ptr< osg::Texture2D > renderTangentTexture = m_render->attach( osg::Camera::COLOR_BUFFER3, GL_RGB );
osg::ref_ptr< osg::Texture2D > renderDepthTexture = m_render->attach( osg::Camera::DEPTH_BUFFER );
m_postprocess->bind( renderColorTexture, 0 );
m_postprocess->bind( renderNormalTexture, 1 );
m_postprocess->bind( renderParameterTexture, 2 );
m_postprocess->bind( renderDepthTexture, 3 );
// add the offscreen renderer and the original node to the switch
// the geometry is always the first in the switch node
addChild( m_childs );
addChild( m_offscreen );
// some info text:
m_infoText = m_properties->addProperty( "Hint", "This is for advanced users.",
std::string( "The post-processing has to be seen as facility to create appealing images. The here offered options are not all "
"possibilities. The most powerful effects can be achieved by using custom combinations (using custom GLSL code) of "
"post-processors and is recommended for <b>advanced users</b> only." )
);
m_infoText->setPurpose( PV_PURPOSE_INFORMATION );
// add some properties here:
m_active = m_properties->addProperty( "Enable", "If set, post-processing is enabled.", true );
m_showHUD = m_properties->addProperty( "Show HUD", "If set, the intermediate textures are shown.", false );
// Post-processings:
// First: Create a list with name, description and shader define which is used to enable it
typedef WGEShaderPropertyDefineOptionsTools::NameDescriptionDefineTuple Tuple;
std::vector< Tuple > namesAndDefs;
namesAndDefs.push_back( Tuple( "Color Only", "No Post-Processing.", "WGE_POSTPROCESSOR_COLOR" ) );
namesAndDefs.push_back( Tuple( "Smoothed Color", "Smoothed Color Image using Gauss Filter.", "WGE_POSTPROCESSOR_GAUSSEDCOLOR" ) );
namesAndDefs.push_back( Tuple( "PPL - Phong", "Per-Pixel-Lighting using Phong.", "WGE_POSTPROCESSOR_PPLPHONG" ) );
namesAndDefs.push_back( Tuple( "Cel-Shading", "Under-sampling of the color for cartoon-like shading.", "WGE_POSTPROCESSOR_CELSHADING" ) );
namesAndDefs.push_back( Tuple( "Depth-Cueing", "Use the Depth to fade out the pixel's brightness.", "WGE_POSTPROCESSOR_DEPTHFADING" ) );
namesAndDefs.push_back( Tuple( "Edge", "Edge of Rendered Geometry.", "WGE_POSTPROCESSOR_EDGE" ) );
namesAndDefs.push_back( Tuple( "Depth", "Depth Value only.", "WGE_POSTPROCESSOR_DEPTH" ) );
namesAndDefs.push_back( Tuple( "Smoothed Depth", "Gauss-Smoothed Depth Value only.", "WGE_POSTPROCESSOR_GAUSSEDDEPTH" ) );
namesAndDefs.push_back( Tuple( "Normal", "Geometry Normal.", "WGE_POSTPROCESSOR_NORMAL" ) );
namesAndDefs.push_back( Tuple( "Custom", "Provide Your Own Post-processing-Code.", "WGE_POSTPROCESSOR_CUSTOM" ) );
// Second: create the Shader option object and the corresponding property automatically:
WGEShaderPropertyDefineOptions< WPropSelection >::SPtr activePostprocessorsOpts(
WGEShaderPropertyDefineOptionsTools::createSelection(
"Post-processors",
"Select the post-processings you want.",
m_properties,
namesAndDefs
)
);
m_activePostprocessors = activePostprocessorsOpts->getProperty();
// avoid that a user selects nothing
WPropertyHelper::PC_NOTEMPTY::addTo( m_activePostprocessors );
// this node has some properties:
boost::shared_ptr< WItemSelection > m_possibleSelections = boost::shared_ptr< WItemSelection >( new WItemSelection() );
m_possibleSelections->addItem( "None", "No postprocessing." );
m_showHud = m_properties->addProperty( "Texture Debug", "If set, all intermediate texture are shown on screen for debugging.", false );
m_active = m_properties->addProperty( "Enable", "If set, post-processing is enabled.", false, true );
m_activePostprocessor = m_properties->addProperty( "Postprocessor", "Selection one of the postprocessors.",
m_possibleSelections->getSelectorFirst(),
boost::bind( &WGEPostprocessingNode::postprocessorSelected, this ) );
WPropertyHelper::PC_SELECTONLYONE::addTo( m_activePostprocessor );
WPropertyHelper::PC_NOTEMPTY::addTo( m_activePostprocessor );
// control texture HUD
osg::ref_ptr< WGENodeMaskCallback > textureHudCallback = new WGENodeMaskCallback( m_showHud );
// get available postprocessors and setup the node
WGEPostprocessor::ProcessorList processors = WGEPostprocessor::getPostprocessors();
for( WGEPostprocessor::ProcessorList::const_iterator iter = processors.begin(); iter != processors.end(); ++iter )
{
// offscreen node
osg::ref_ptr< WGEOffscreenRenderNode > offscreen( new WGEOffscreenRenderNode( reference, width, height, noHud ) );
offscreen->getTextureHUD()->addUpdateCallback( textureHudCallback );
// the geometry render step
osg::ref_ptr< WGEOffscreenRenderPass > render = offscreen->addGeometryRenderPass(
m_childs,
"Rendered"
);
// create G-Buffer
WGEPostprocessor::PostprocessorInput buf( WGEPostprocessor::PostprocessorInput::attach( render ) );
// let the specific post processor build its pipeline
WGEPostprocessor::SPtr processor = ( *iter )->create( offscreen, buf );
m_postprocs.push_back( processor );
// add the postprocessor's properties
m_properties->addProperty( processor->getProperties() );
processor->getProperties()->setHidden( true );
// add it to the selection prop
m_possibleSelections->addItem( processor->getName(), processor->getDescription() );
// the final step
osg::ref_ptr< WGEOffscreenFinalPass > output = offscreen->addFinalOnScreenPass( new WGEShader( "WGEPostprocessorCombiner" ),
"Output" );
output->bind( processor->getOutput(), 0 );
output->bind( processor->getDepth(), 1 );
// add the offscreen renderer and the original node to the switch
addChild( offscreen );
}
// let the props control some stuff
addUpdateCallback( new WGESwitchCallback< WPropBool >( m_active ) );
m_offscreen->getTextureHUD()->addUpdateCallback( new WGENodeMaskCallback( m_showHUD ) );
// let the activePostprocessors property control the options in the shader:
m_postProcessShader->addPreprocessor( activePostprocessorsOpts );
addUpdateCallback( new WGESwitchCallback< WPropSelection >( m_activePostprocessor ) );
// some of the post-processors need some white noise, like the ssao
const size_t size = 64;
/* const size_t size = 64;
osg::ref_ptr< WGETexture2D > randTex = wge::genWhiteNoiseTexture( size, size, 3 );
m_postprocess->bind( randTex, 4 );
m_postprocess->bind( renderTangentTexture, 5 );
*/
}
WGEPostprocessingNode::~WGEPostprocessingNode()
{
// cleanup
m_render->detach( osg::Camera::COLOR_BUFFER0 );
m_render->detach( osg::Camera::COLOR_BUFFER1 );
}
WPropGroup WGEPostprocessingNode::getProperties() const
......@@ -178,8 +168,22 @@ void WGEPostprocessingNode::clear()
m_childs->clear();
}
void WGEPostprocessingNode::setEnabled( bool enable )
void WGEPostprocessingNode::postprocessorSelected()
{
m_active->set( enable );
}
if( m_postprocs.size() == 0 )
{
m_active->set( false );
return;
}
size_t active = m_activePostprocessor->get();
// this triggers several shader preprocessors of all child nodes
m_active->set( active != 0 );
// hide all, but not the active one
for( size_t i = 0; i < m_postprocs.size(); ++i )
{
m_postprocs[ i ]->getProperties()->setHidden( i != ( active - 1 ) );
}
}
......@@ -42,6 +42,8 @@
#include "../WGEGroupNode.h"
#include "../WExportWGE.h"
#include "WGEPostprocessor.h"
/**
* This class enables you to add arbitrary nodes that get post-processed in screen space. The only thing you need to take care of is your shader.
* You need some special parts in it. Please see the all-in-one super-shader-example module WMShaderExample in modules/template.
......@@ -63,12 +65,15 @@ public:
typedef osg::ref_ptr< const WGEPostprocessingNode > ConstRefPtr;
/**
* Create a new post-processing node. It used the WGEOffscreenRenderNode to setup an offscreen, shader-based post-processing for rendered
* Create a new post-processing node. It uses the WGEOffscreenRenderNode to setup an offscreen, shader-based post-processing for rendered
* images. This is not limited to geometry but can also be used for ray-traced images.
*
* \note The width and hight define the offscreen texture size. The viewport if each rendering is automatically set to the one of the
* reference camera. This means, width and height only define the maximal supported resolution without upscaling of your postprocessor.
*
* \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 width the width of the textures used in this rendering. Must be in [8,4096] and a power of two.
* \param height the height of the textures used in this rendering. Must be in [8,4096] and a power of two.
* \param noHud If true, no hud gets displayed showing the created and used textures.
*/
WGEPostprocessingNode( osg::ref_ptr< osg::Camera > reference, size_t width = 2048, size_t height = 2048, bool noHud = false );
......@@ -114,13 +119,6 @@ public:
*/
void clear();
/**
* Activates/Deactivates the post-processing. This is a shortcut for getProperties()->getProperty( "Enable" )->toPropBool()->set( enable ).
*
* \param enable if true, post-processing is active-
*/
void setEnabled( bool enable = true );
protected:
private:
/**
......@@ -141,31 +139,11 @@ private:
*/
NodeShaderAssociation m_nodeShaderAssociation;
/**
* The actual offscreen render node.
*/
osg::ref_ptr< WGEOffscreenRenderNode > m_offscreen;
/**
* The group of child nodes to post-process.
*/
osg::ref_ptr< WGEGroupNode > m_childs;
/**
* The first pass, rendering.
*/
osg::ref_ptr< WGEOffscreenRenderPass > m_render;
/**
* The actual post-processing.
*/
osg::ref_ptr< WGEOffscreenFinalPass > m_postprocess;
/**
* This shader actually does post-processing in screen space.
*/
WGEShader::RefPtr m_postProcessShader;
/**
* All the properties of the post-processor.
*/
......@@ -177,24 +155,24 @@ private:
WPropBool m_active;
/**
* If true, a HUD with intermediate textures is shown.
* Activate to show the texture HUDs
*/
WPropBool m_showHUD;
WPropBool m_showHud;
/**
* The property containing the currently active method or a combination.
*/
WPropSelection m_activePostprocessors;
WPropSelection m_activePostprocessor;
/**
* Possible post-processors.
* The postprocessors.
*/
boost::shared_ptr< WItemSelection > m_possiblePostprocessors;
WGEPostprocessor::ProcessorList m_postprocs;
/**
* Some text denoting that this is not yet completely done.
* Callback for changes in m_activePostprocessor.
*/
WPropString m_infoText;
void postprocessorSelected();
};
#endif // WGEPOSTPROCESSINGNODE_H
......
//---------------------------------------------------------------------------
//
// 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 "WGEPostprocessorEdgeEnhance.h"
#include "WGEPostprocessorCelShading.h"
#include "WGEPostprocessor.h"
WGEPostprocessor::WGEPostprocessor( std::string name, std::string description ):
WPrototyped(),
m_name( name ),
m_description( description )
{
}
WGEPostprocessor::WGEPostprocessor( osg::ref_ptr< WGEOffscreenRenderNode > /* offscreen */,
const WGEPostprocessor::PostprocessorInput& gbuffer,
std::string name,
std::string description ):
WPrototyped(),
m_resultTexture( gbuffer.m_colorTexture ),
m_depthTexture( gbuffer.m_depthTexture ),
m_properties( boost::shared_ptr< WProperties >( new WProperties( "Settings for " + name, "Post-processing properties" ) ) ),
m_name( name ),
m_description( description )
{
// there is always one property:
m_effectOnly = m_properties->addProperty( "Effect only", "If active, the plain effect will be shown instead a combination of effect "
"and color. This settings does not affect all postprocessors.", false );
// for convenience, also create a preprocessor for this property
m_effectOnlyPreprocessor = WGEShaderPreprocessor::SPtr( new WGEShaderPropertyDefineOptions< WPropBool >( m_effectOnly,
"WGE_POSTPROCESSOR_OUTPUT_COMBINE", "WGE_POSTPROCESSOR_OUTPUT_EFFECT_ONLY" ) );
}
WGEPostprocessor::~WGEPostprocessor()
{
// cleanup
}
WPropGroup WGEPostprocessor::getProperties() const
{
return m_properties;
}
osg::ref_ptr< osg::Texture2D > WGEPostprocessor::getOutput() const
{
return m_resultTexture;
}
osg::ref_ptr< osg::Texture2D > WGEPostprocessor::getDepth() const
{
return m_depthTexture;
}
WGEPostprocessor::PostprocessorInput WGEPostprocessor::PostprocessorInput::attach( osg::ref_ptr< WGEOffscreenRenderPass > from )
{
PostprocessorInput buf;
buf.m_colorTexture = from->attach( osg::Camera::COLOR_BUFFER0 );
buf.m_normalTexture = from->attach( osg::Camera::COLOR_BUFFER1, GL_RGB );
buf.m_parameterTexture = from->attach( osg::Camera::COLOR_BUFFER2, GL_LUMINANCE );
buf.m_tangentTexture = from->attach( osg::Camera::COLOR_BUFFER3, GL_RGB );
buf.m_depthTexture = from->attach( osg::Camera::DEPTH_BUFFER );
return buf;
}
void WGEPostprocessor::PostprocessorInput::bind( osg::ref_ptr< WGEOffscreenRenderPass > to ) const
{
to->bind( m_colorTexture, 0 );
to->bind( m_normalTexture, 1 );
to->bind( m_parameterTexture, 2 );
to->bind( m_depthTexture, 3 );
to->bind( m_tangentTexture, 4 );
}
WGEPostprocessor::ProcessorList WGEPostprocessor::getPostprocessors()
{
WGEPostprocessor::ProcessorList postprocs;
// create prototypes of the postprocessors OW knows about
postprocs.push_back( WGEPostprocessor::SPtr( new WGEPostprocessorEdgeEnhance() ) );
postprocs.push_back( WGEPostprocessor::SPtr( new WGEPostprocessorCelShading() ) );
return postprocs;
}
const std::string WGEPostprocessor::getName() const
{
return m_name;
}
const std::string WGEPostprocessor::getDescription() const
{
return m_description;
}
//---------------------------------------------------------------------------
//
// 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 WGEPOSTPROCESSOR_H
#define WGEPOSTPROCESSOR_H
#include <vector>
#include <string>
#include <boost/shared_ptr.hpp>
#include <osg/ref_ptr>
#include <osg/Node>
#include <osg/Camera>
#include <osg/Texture>
#include "../offscreen/WGEOffscreenRenderNode.h"
#include "../offscreen/WGEOffscreenRenderPass.h"
#include "../offscreen/WGEOffscreenFinalPass.h"
#include "../shaders/WGEShaderPropertyDefineOptions.h"
#include "../../common/WProperties.h"
#include "../../common/WPrototyped.h"
#include "../WExportWGE.h"
/**
* The base class for all custom post-processors. It allows building an own texture processing pipeline for special processings.
*/
class WGEPostprocessor: public WPrototyped
{
public:
/**
* This class encapsulates a G-Buffer. Basically, this is a collection of per-pixel geometry information.
*/
class PostprocessorInput
{
public:
/**
* Attaches the needed textures to the specified render pass and returns the G-Buffer
*
* \param from the renderpass to attach this to
*
* \return the buffer.
*/
static PostprocessorInput attach( osg::ref_ptr< WGEOffscreenRenderPass > from );
/**
* Attaches these textures to the specified renderpass
*
* \param to attach to this
*/
void bind( osg::ref_ptr< WGEOffscreenRenderPass > to ) const;
/**
* Color in RGBA
*/
osg::ref_ptr< osg::Texture2D > m_colorTexture;
/**
* Normal in RGB
*/
osg::ref_ptr< osg::Texture2D > m_normalTexture;
/**
* Some not yet defined parameter texture, LUMINANCE only
*/
osg::ref_ptr< osg::Texture2D > m_parameterTexture;
/**
* Tangent in RGB
*/
osg::ref_ptr< osg::Texture2D > m_tangentTexture;
/**
* Depth
*/
osg::ref_ptr< osg::Texture2D > m_depthTexture;
};
/**
* Convenience typedef for an osg::ref_ptr< WGEPostprocessor >.
*/
typedef boost::shared_ptr< WGEPostprocessor > SPtr;
/**
* Convenience typedef for an osg::ref_ptr< const WGEPostprocessor >.
*/
typedef boost::shared_ptr< const WGEPostprocessor > ConstSPtr;
/**
* Type used for returning lists of postprocessor prototypes.
*/
typedef std::vector< WGEPostprocessor::SPtr > ProcessorList;
/**
* Returns a list of all known postprocessor prototypes
*
* \return the list
*/
static ProcessorList getPostprocessors();
/**
* Create named prototype. You should call this in your prototype constructor.
*
* \param name name of processor