OpenWalnut  1.5.0dev
WGEPostprocessingNode.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <memory>
26 
27 #include "../../common/WItemSelection.h"
28 #include "../../common/WPropertyHelper.h"
29 #include "../WGEUtils.h"
30 #include "../callbacks/WGENodeMaskCallback.h"
31 #include "../shaders/WGEShaderPropertyDefineOptions.h"
32 #include "WGEPostprocessingNode.h"
33 #include "WGEPostprocessor.h"
34 
35 WGEPostprocessingNode::WGEPostprocessingNode( osg::ref_ptr< WGECamera > reference, size_t width, size_t height, bool noHud ):
36  osg::Switch(),
37  m_childs( new WGEGroupNode() ),
38  m_properties( std::shared_ptr< WProperties >( new WProperties( "Post-processing", "Post-processing properties" ) ) )
39 {
40  // the geometry is always the first in the switch node
41  addChild( m_childs );
42 
43  // this node has some properties:
44  std::shared_ptr< WItemSelection > m_possibleSelections( new WItemSelection() );
45  m_possibleSelections->addItem( "None", "No postprocessing." );
46 
47  m_showHud = m_properties->addProperty( "Texture debug", "If set, all intermediate texture are shown on screen for debugging.", false );
48 
49  m_depthGroup = WPropGroup( new WPropertyGroup( "Additional Depth Shading", "Allows to emphasize depth by shading." ) );
50  m_shadeByDepth = m_depthGroup->addProperty( "Enable", "Enable depth-based shading.", false );
51  m_depthThresholdL = m_depthGroup->addProperty( "Lower depth threshold", "All depths in front of this are assumed to be foreground.", 0.25 );
52  m_depthThresholdU = m_depthGroup->addProperty( "Upper depth threshold",
53  "All depths behind this are assumed to be background.", 0.75 );
54  m_depthThresholdU->setMin( 0.0 );
55  m_depthThresholdU->setMax( 1.0 );
56  m_depthThresholdL->setMin( 0.0 );
57  m_depthThresholdL->setMax( 1.0 );
58 
59  m_depthShadeL = m_depthGroup->addProperty( "Lower shading intensity", "How much to shade the background.", 0.75 );
60  m_depthShadeU = m_depthGroup->addProperty( "Upper shading intensity",
61  "How much to shade the foreground. Use values higher than one to brighten the foreground.", 1.0 );
62  m_depthShadeL->setMin( 0.0 );
63  m_depthShadeL->setMax( 1.0 );
64  m_depthShadeU->setMin( 0.0 );
65  m_depthShadeU->setMax( 3.0 );
66 
67  m_active = m_properties->addProperty( "Enable", "If set, post-processing is enabled.", false, true );
68  m_activePostprocessor = m_properties->addProperty( "Postprocessor", "Selection one of the postprocessors.",
69  m_possibleSelections->getSelectorFirst(),
70  boost::bind( &WGEPostprocessingNode::postprocessorSelected, this ) );
73 
74  // control texture HUD
75  osg::ref_ptr< WGENodeMaskCallback > textureHudCallback = new WGENodeMaskCallback( m_showHud );
76 
77  // get available postprocessors and setup the node
79  for( WGEPostprocessor::ProcessorList::const_iterator iter = processors.begin(); iter != processors.end(); ++iter )
80  {
81  // offscreen node
82  osg::ref_ptr< WGEOffscreenRenderNode > offscreen( new WGEOffscreenRenderNode( reference, width, height, noHud ) );
83  offscreen->getTextureHUD()->addUpdateCallback( textureHudCallback );
84 
85  // if the specific postprocessor requires us to fix the viewport size to the result-texture size:
86  offscreen->setLinkViewportToTextureSize( ( *iter )->getFixedViewportSize() );
87 
88  // the geometry render step
89  osg::ref_ptr< WGEOffscreenRenderPass > render = offscreen->addGeometryRenderPass(
90  m_childs,
91  "Rendered"
92  );
93 
94  // create G-Buffer
96 
97  // let the specific post processor build its pipeline
98  WGEPostprocessor::SPtr processor = ( *iter )->create( offscreen, buf );
99  m_postprocs.push_back( processor );
100 
101  // add the postprocessor's properties
102  m_properties->addProperty( processor->getProperties() );
103  processor->getProperties()->setHidden( true );
104 
105  // add it to the selection prop
106  m_possibleSelections->addItem( processor->getName(), processor->getDescription() );
107 
108  // the final step
109  osg::ref_ptr< WGEShader > combinerShader( new WGEShader( "WGEPostprocessorCombiner" ) );
110  osg::ref_ptr< WGEOffscreenFinalPass > output = offscreen->addFinalOnScreenPass( combinerShader, "Output" );
111 
112  // register the depth-shading values:
113  output->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropDouble >( "u_depthThresholdU", m_depthThresholdU ) );
114  output->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropDouble >( "u_depthThresholdL", m_depthThresholdL ) );
115  output->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropDouble >( "u_depthShadeU", m_depthShadeU ) );
116  output->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropDouble >( "u_depthShadeL", m_depthShadeL ) );
117 
118  // Enable depth-shade via compile-time options:
119  combinerShader->addPreprocessor( WGEShaderPreprocessor::SPtr(
120  new WGEShaderPropertyDefineOptions< WPropBool >( m_shadeByDepth, "DEPTH_SHADING_DISABLED", "DEPTH_SHADING_ENABLED" ) ) );
121 
122  osg::ref_ptr< osg::Texture2D > colorTex = processor->getOutput();
123  colorTex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR );
124  colorTex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR );
125  output->bind( colorTex, 0 );
126 
127  // does this processor provide a depth?
128  osg::ref_ptr< osg::Texture2D > depthTex = processor->getDepth();
129  if( !depthTex )
130  {
131  depthTex = buf.m_depthTexture;
132  }
133  output->bind( depthTex, 1 );
134 
135  // add the offscreen renderer and the original node to the switch
136  addChild( offscreen );
137  }
138 
139  m_properties->addProperty( m_depthGroup );
140 
141  // let the props control some stuff
143 }
144 
146 {
147  // cleanup
148 }
149 
151 {
152  return m_properties;
153 }
154 
155 void WGEPostprocessingNode::insert( osg::ref_ptr< osg::Node > node, WGEShader::RefPtr shader )
156 {
157  // the shader needs an own preprocessor.
159  m_active, "WGE_POSTPROCESSING_DISABLED", "WGE_POSTPROCESSING_ENABLED" )
160  );
161 
162  // we need to inject some code to the shader at this point.
163  shader->addPreprocessor( preproc );
164 
165  // do it thread-safe as we promise to be thread-safe
167  // to keep track of which node is associated with which shader and preprocessor:
168  w->get()[ node ] = std::make_pair( shader, preproc );
169 
170  // insert node to group node of all children
171  m_childs->insert( node );
172 }
173 
174 void WGEPostprocessingNode::remove( osg::ref_ptr< osg::Node > node )
175 {
176  // do it thread-safe as we promise to be thread-safe
178 
179  // remove the item from our map
180  NodeShaderAssociation::Iterator item = w->get().find( node );
181 
182  if( item != w->get().end() )
183  {
184  // we need to remove the preprocessor from the shader.
185  ( *item ).second.first->removePreprocessor( ( *item ).second.second );
186  w->get().erase( item );
187  }
188 
189  // although we may not find the node in our association list, try to remove it
190  m_childs->remove( node );
191 }
192 
194 {
195  // do it thread-safe as we promise to be thread-safe
197 
198  // remove from node-shader association list
199  for( NodeShaderAssociation::Iterator iter = w->get().begin(); iter != w->get().end(); ++iter )
200  {
201  ( *iter ).second.first->removePreprocessor( ( *iter ).second.second );
202  }
203  w->get().clear();
204 
205  // remove the node from the render group
206  m_childs->clear();
207 }
208 
210 {
211  return m_postprocs[ m_activePostprocessor->get() - 1 ];
212 }
213 
215 {
216  if( m_postprocs.size() == 0 )
217  {
218  m_active->set( false );
219  return;
220  }
221 
222  size_t active = m_activePostprocessor->get();
223 
224  // this triggers several shader preprocessors of all child nodes
225  m_active->set( active != 0 );
226 
227  // hide all, but not the active one
228  for( size_t i = 0; i < m_postprocs.size(); ++i )
229  {
230  m_postprocs[ i ]->getProperties()->setHidden( i != ( active - 1 ) );
231  }
232 
233  // Show depth shading?
234  m_depthGroup->setHidden( active == 0 );
235 }
Class to wrap around the osg Group node and providing a thread safe add/removal mechanism.
Definition: WGEGroupNode.h:48
This callback is useful to en-/disable nodes using the node mask based on properties.
This type of node basically is a convenience class for managing and creating offscreen renderings.
WGEPostprocessor::SPtr getCurrentPostprocessor() const
The post processor currently in use.
WPropDouble m_depthShadeU
Upper depth threshold -> how bright to get.
WPropGroup m_depthGroup
Group these depth-shading props.
virtual ~WGEPostprocessingNode()
Destructor.
WPropBool m_shadeByDepth
Activate depth based darkening.
WPropBool m_showHud
Activate to show the texture HUDs.
WPropDouble m_depthShadeL
Lower depth shade threshold -> how dark to get.
WPropSelection m_activePostprocessor
The property containing the currently active method or a combination.
WPropDouble m_depthThresholdU
Upper depth threshold -> higher depth is foreground.
void postprocessorSelected()
Callback for changes in m_activePostprocessor.
WGEPostprocessingNode(osg::ref_ptr< WGECamera > reference, size_t width=2048, size_t height=2048, bool noHud=false)
Create a new post-processing node.
osg::ref_ptr< WGEGroupNode > m_childs
The group of child nodes to post-process.
WPropDouble m_depthThresholdL
Lower depth threshold -> lower depth is background.
void insert(osg::ref_ptr< osg::Node > node, WGEShader::RefPtr shader=NULL)
Inserts a node to the post-processor and injects the needed code to the specified shader.
NodeShaderAssociation m_nodeShaderAssociation
List of nodes and their corresponding shader and preprocessor.
WPropGroup m_properties
All the properties of the post-processor.
void clear()
Removes all associated nodes.
WGEPostprocessor::ProcessorList m_postprocs
The postprocessors.
void remove(osg::ref_ptr< osg::Node > node)
Removes the node from the post-processing.
WPropGroup getProperties() const
Returns the set of properties controlling the post-processing node.
WPropBool m_active
If true, post-processing is enabled.
This class encapsulates a G-Buffer.
static PostprocessorInput attach(osg::ref_ptr< WGEOffscreenRenderPass > from)
Attaches the needed textures to the specified render pass and returns the G-Buffer.
osg::ref_ptr< osg::Texture2D > m_depthTexture
Depth.
static ProcessorList getPostprocessors()
Returns a list of all known postprocessor prototypes.
std::shared_ptr< WGEPostprocessor > SPtr
Convenience typedef for an osg::ref_ptr< WGEPostprocessor >.
std::vector< WGEPostprocessor::SPtr > ProcessorList
Type used for returning lists of postprocessor prototypes.
Class implementing a uniform which can be controlled by a property instance.
std::shared_ptr< WGEShaderPreprocessor > SPtr
Shared pointer for this class.
This is a WGEShaderDefineOptions class which additionally uses a property to automatically control th...
Class encapsulating the OSG Program class for a more convenient way of adding and modifying shader.
Definition: WGEShader.h:48
osg::ref_ptr< WGEShader > RefPtr
Convenience typedef for an osg::ref_ptr.
Definition: WGEShader.h:53
This callback is able to switch a osg::Switch node using a property.
A class containing a list of named items.
Class to manage properties of an object and to provide convenience methods for easy access and manipu...
std::shared_ptr< WSharedObjectTicketWrite< T > > WriteTicket
Type for write tickets.
Definition: WSharedObject.h:70
WriteTicket getWriteTicket(bool suppressNotify=false) const
Returns a ticket to get write access to the contained data.
void addTo(WPropSelection prop)
Add the PC_NOTEMPTY constraint to the property.
void addTo(WPropSelection prop)
Add the PC_SELECTONLYONE constraint to the property.