OpenWalnut  1.5.0dev
WMImageSpaceLIC.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 <cmath>
26 #include <cstdlib>
27 #include <memory>
28 #include <string>
29 #include <vector>
30 
31 #include <osg/BoundingSphere>
32 #include <osg/Drawable>
33 #include <osg/Geode>
34 #include <osg/Geometry>
35 #include <osg/Vec3>
36 
37 #include "WMImageSpaceLIC.h"
38 #include "core/common/WPropertyHelper.h"
39 #include "core/common/math/WMath.h"
40 #include "core/dataHandler/WDataHandler.h"
41 #include "core/dataHandler/WDataTexture3D.h"
42 #include "core/dataHandler/WGridRegular3D.h"
43 #include "core/graphicsEngine/WGEColormapping.h"
44 #include "core/graphicsEngine/WGEGeodeUtils.h"
45 #include "core/graphicsEngine/WGETextureUtils.h"
46 #include "core/graphicsEngine/WGEUtils.h"
47 #include "core/graphicsEngine/callbacks/WGELinearTranslationCallback.h"
48 #include "core/graphicsEngine/callbacks/WGENodeMaskCallback.h"
49 #include "core/graphicsEngine/offscreen/WGEOffscreenRenderNode.h"
50 #include "core/graphicsEngine/offscreen/WGEOffscreenRenderPass.h"
51 #include "core/graphicsEngine/shaders/WGEPropertyUniform.h"
52 #include "core/graphicsEngine/shaders/WGEShader.h"
53 #include "core/graphicsEngine/shaders/WGEShaderDefineOptions.h"
54 #include "core/graphicsEngine/shaders/WGEShaderPropertyDefineOptions.h"
55 #include "core/kernel/WKernel.h"
56 
57 // This line is needed by the module loader to actually find your module. You need to add this to your module too. Do NOT add a ";" here.
58 W_LOADABLE_MODULE( WMImageSpaceLIC )
59 
61  WModule()
62 {
63 }
64 
66 {
67  // Cleanup!
68 }
69 
70 std::shared_ptr< WModule > WMImageSpaceLIC::factory() const
71 {
72  return std::shared_ptr< WModule >( new WMImageSpaceLIC() );
73 }
74 
75 const std::string WMImageSpaceLIC::getName() const
76 {
77  return "Image Space LIC";
78 }
79 
80 const std::string WMImageSpaceLIC::getDescription() const
81 {
82  return "This module takes an vector dataset and creates an LIC-like texture on an arbitrary surface. You can specify the surface as input or"
83  "leave it unspecified to use slices.";
84 }
85 
87 {
88  // vector input
89  m_vectorsIn = WModuleInputData< WDataSetVector >::createAndAdd( shared_from_this(), "vectors", "The vector dataset."
90  "Needs to be in the same grid as the mesh." );
91  // scalar input
92  m_scalarIn = WModuleInputData< WDataSetScalar >::createAndAdd( shared_from_this(), "scalars", "The scalar dataset."
93  "Needs to be in the same grid as the mesh." );
94 
95  // mesh input
96  m_meshIn = WModuleInputData< WTriangleMesh >::createAndAdd( shared_from_this(), "surface", "The optional surface to use." );
97 
98  // call WModule's initialization
100 }
101 
103 {
104  m_propCondition = std::shared_ptr< WCondition >( new WCondition() );
105 
106  m_geometryGroup = m_properties->addPropertyGroup( "Geometry", "Selection of used geometry to apply LIC to." );
107 
108  m_useSlices = m_geometryGroup->addProperty( "Use Slices", "Show vectors on slices.", true, m_propCondition );
109 
110  m_sliceGroup = m_geometryGroup->addPropertyGroup( "Slices", "Slice based LIC." );
111 
112  // enable slices
113  // Flags denoting whether the glyphs should be shown on the specific slice
114  m_showonX = m_sliceGroup->addProperty( "Show Sagittal", "Show vectors on sagittal slice.", true );
115  m_showonY = m_sliceGroup->addProperty( "Show Coronal", "Show vectors on coronal slice.", true );
116  m_showonZ = m_sliceGroup->addProperty( "Show Axial", "Show vectors on axial slice.", true );
117 
118  // The slice positions. These get update externally.
119  // TODO(all): this should somehow be connected to the nav slices.
120  m_xPos = m_sliceGroup->addProperty( "Sagittal Position", "Slice X position.", 80 );
121  m_yPos = m_sliceGroup->addProperty( "Coronal Position", "Slice Y position.", 100 );
122  m_zPos = m_sliceGroup->addProperty( "Axial Position", "Slice Z position.", 80 );
123  m_xPos->setMin( 0 );
124  m_xPos->setMax( 159 );
125  m_yPos->setMin( 0 );
126  m_yPos->setMax( 199 );
127  m_zPos->setMin( 0 );
128  m_zPos->setMax( 159 );
129 
130  m_licGroup = m_properties->addPropertyGroup( "LIC", "LIC properties." );
131 
132  m_useLight = m_licGroup->addProperty( "Use Light", "Check to enable lightning using the Phong model.", false );
133  m_lightIntensity = m_licGroup->addProperty( "Light Intensity", "Define how intense the light should be.", 1.0 );
134  m_lightIntensity->setMin( 0.0 );
135  m_lightIntensity->setMax( 10.0 );
136 
137  m_useEdges = m_licGroup->addProperty( "Edges", "Check to enable blending in edges.", true );
138  m_useEdgesColor = m_licGroup->addProperty( "Edge Color", "Define the color of the edges.", defaultColor::WHITE );
139  m_useEdgesStep = m_licGroup->addProperty( "Edge Step", "Define the steepness of the blend function between color and edge color.", 1.0 );
140  m_useEdgesStep->setMin( 0.0 );
141  m_useEdgesStep->setMax( 10.0 );
142 
143  m_useHighContrast = m_licGroup->addProperty( "High Contrast", "Use an extremely increased contrast.", false );
144  m_useDepthCueing = m_licGroup->addProperty( "Depth Cueing", "Use depth as additional cue? Mostly useful for isosurfaces.",
145  false );
146 
147  m_cmapRatio = m_licGroup->addProperty( "Ratio Colormap to LIC", "Blending ratio between LIC and colormap.", 0.5 );
148  m_cmapRatio->setMin( 0.0 );
149  m_cmapRatio->setMax( 1.0 );
150 
151  m_advancedLicGroup = m_properties->addPropertyGroup( "Advanced", "More advanced LIC properties." );
152  // show hud?
153  m_showHUD = m_advancedLicGroup->addProperty( "Show HUD", "Check to enable the debugging texture HUD.", false );
154  m_3dNoise = m_advancedLicGroup->addProperty( "Use 3D noise", "Use 3D noise? This provides better coherence during transformation of "
155  "the geometry but might introduce resolution problems.", true );
156  m_3dNoiseRes = m_advancedLicGroup->addProperty( "3D Noise Resolution", "The 3D noise is of 128^3 pixels size. This scaler allows "
157  "modification of this size.", 1.5 );
158  m_3dNoiseRes->setMin( 0 );
159  m_3dNoiseRes->setMax( 10 );
160 
161  m_3dNoiseAutoRes = m_advancedLicGroup->addProperty( "3D Noise Auto-Resolution", "If checked, the resolution of the 3D noise gets calculated "
162  "automatically according to the screen size. If disabled, the user can zoom into the LIC.",
163  true );
164 
165  m_numIters = m_advancedLicGroup->addProperty( "Number of Iterations", "How much iterations along a streamline should be done per frame.",
166  30 );
167  m_numIters->setMin( 1 );
168  m_numIters->setMax( 1000 );
169 
170  m_projectionAngleThreshold = m_advancedLicGroup->addProperty( "Projection Angle Threshold", "This defines the threshold of the angle between "
171  "tangential plane of the surface and the vector which is going to be projected. You can adjust how steep a vector can be before it is "
172  "clipped and NOT projected. Note: all vectors with an angle below this threshold are projected but linearly reduced in influence "
173  "depending on the angle.", 90.0 );
174  m_projectionAngleThreshold->setMin( 0.0 );
175  m_projectionAngleThreshold->setMax( 90.0 );
176 
177 
178  // call WModule's initialization
180 }
181 
182 void WMImageSpaceLIC::initOSG( std::shared_ptr< WGridRegular3D > grid, std::shared_ptr< WTriangleMesh > mesh )
183 {
184  // remove the old slices
185  m_output->clear();
186 
187  if( mesh && !m_useSlices->get( true ) )
188  {
189  // we have a mesh and want to use it
190  // create geometry and geode
191  osg::Geometry* surfaceGeometry = new osg::Geometry();
192  osg::ref_ptr< osg::Geode > surfaceGeode = osg::ref_ptr< osg::Geode >( new osg::Geode );
193 
194  surfaceGeometry->setVertexArray( mesh->getVertexArray() );
195  osg::DrawElementsUInt* surfaceElement;
196  surfaceElement = new osg::DrawElementsUInt( osg::PrimitiveSet::TRIANGLES, 0 );
197  std::vector< size_t > tris = mesh->getTriangles();
198  surfaceElement->reserve( tris.size() );
199  for( unsigned int vertId = 0; vertId < tris.size(); ++vertId )
200  {
201  surfaceElement->push_back( tris[vertId] );
202  }
203  surfaceGeometry->addPrimitiveSet( surfaceElement );
204 
205  // normals
206  surfaceGeometry->setNormalArray( mesh->getVertexNormalArray() );
207  surfaceGeometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
208 
209  // texture coordinates
210  surfaceGeometry->setTexCoordArray( 0, mesh->getTextureCoordinateArray() );
211 
212  // render
213  surfaceGeode->addDrawable( surfaceGeometry );
214  m_output->insert( surfaceGeode );
215  }
216  else if( !mesh && !m_useSlices->get( true ) )
217  {
218  warnLog() << "No surface connected to input but surface render mode enabled. Nothing rendered.";
219  }
220  else
221  {
222  // create a new geode containing the slices
223  osg::ref_ptr< osg::Node > xSlice = wge::genFinitePlane( grid->getOrigin(), grid->getNbCoordsY() * grid->getDirectionY(),
224  grid->getNbCoordsZ() * grid->getDirectionZ() );
225 
226  osg::ref_ptr< osg::Node > ySlice = wge::genFinitePlane( grid->getOrigin(), grid->getNbCoordsX() * grid->getDirectionX(),
227  grid->getNbCoordsZ() * grid->getDirectionZ() );
228 
229  osg::ref_ptr< osg::Node > zSlice = wge::genFinitePlane( grid->getOrigin(), grid->getNbCoordsX() * grid->getDirectionX(),
230  grid->getNbCoordsY() * grid->getDirectionY() );
231 
232  // disable picking
233  xSlice->setName( "_X SLice" );
234  ySlice->setName( "_Y SLice" );
235  zSlice->setName( "_Z SLice" );
236 
237  // The movement of the slice is done in the shader. An alternative would be WGELinearTranslationCallback but there, the needed matrix is
238  // not available in the shader
239  osg::StateSet* ss = xSlice->getOrCreateStateSet();
240  ss->addUniform( new WGEPropertyUniform< WPropInt >( "u_vertexShift", m_xPos ) );
241  ss->addUniform( new osg::Uniform( "u_vertexShiftDirection", grid->getDirectionX().as< osg::Vec3f >() ) ); // the axis to move along
242  ss = ySlice->getOrCreateStateSet();
243  ss->addUniform( new WGEPropertyUniform< WPropInt >( "u_vertexShift", m_yPos ) );
244  ss->addUniform( new osg::Uniform( "u_vertexShiftDirection", grid->getDirectionY().as< osg::Vec3f >() ) ); // the axis to move along
245  ss = zSlice->getOrCreateStateSet();
246  ss->addUniform( new WGEPropertyUniform< WPropInt >( "u_vertexShift", m_zPos ) );
247  ss->addUniform( new osg::Uniform( "u_vertexShiftDirection", grid->getDirectionZ().as< osg::Vec3f >() ) ); // the axis to move along
248 
249  // set callbacks for en-/disabling the nodes
250  xSlice->addUpdateCallback( new WGENodeMaskCallback( m_showonX ) );
251  ySlice->addUpdateCallback( new WGENodeMaskCallback( m_showonY ) );
252  zSlice->addUpdateCallback( new WGENodeMaskCallback( m_showonZ ) );
253 
254  // disable culling.
255  xSlice->setCullingActive( false );
256  ySlice->setCullingActive( false );
257  zSlice->setCullingActive( false );
258 
259  // add the transformation nodes to the output group
260  m_output->insert( xSlice );
261  m_output->insert( ySlice );
262  m_output->insert( zSlice );
263  m_output->dirtyBound();
264  }
265 }
266 
268 {
269  // get notified about data changes
270  m_moduleState.setResetable( true, true );
271  m_moduleState.add( m_vectorsIn->getDataChangedCondition() );
272  m_moduleState.add( m_scalarIn->getDataChangedCondition() );
273  m_moduleState.add( m_meshIn->getDataChangedCondition() );
274  // Remember the condition provided to some properties in properties()? The condition can now be used with this condition set.
276 
277  /////////////////////////////////////////////////////////////////////////////////////////////////////////
278  // Preparation 1: create noise texture
279  /////////////////////////////////////////////////////////////////////////////////////////////////////////
280 
281  // we need a noise texture with a sufficient resolution. Create it.
282  const size_t resX = 1024;
283 
284  // finally, create a texture from the image
285  osg::ref_ptr< osg::Texture2D > randTexture = wge::genWhiteNoiseTexture( resX, resX, 1 );
286 
287  // create a 3D texture too. This allows transformation-invariant noise but is prone to flickering artifacts due to down/upscaling
288  osg::ref_ptr< osg::Texture3D > rand3DTexture = wge::genWhiteNoiseTexture( 128, 128, 128, 1 );
289  rand3DTexture->setWrap( osg::Texture::WRAP_S, osg::Texture::REPEAT );
290  rand3DTexture->setWrap( osg::Texture::WRAP_T, osg::Texture::REPEAT );
291  rand3DTexture->setWrap( osg::Texture::WRAP_R, osg::Texture::REPEAT );
292  WGEShaderPreprocessor::SPtr define3dNoise( new WGEShaderPropertyDefineOptions< WPropBool >( m_3dNoise, "NOISE3D_DISABLED", "NOISE3D_ENABLED" ) );
293 
294  // done.
295  ready();
296 
297  /////////////////////////////////////////////////////////////////////////////////////////////////////////
298  // Preparation 2: initialize offscreen renderer and hardwire it
299  /////////////////////////////////////////////////////////////////////////////////////////////////////////
300 
301  // create the root node for all the geometry
302  m_root = osg::ref_ptr< WGEManagedGroupNode > ( new WGEManagedGroupNode( m_active ) );
303 
304  // root geometry node for the offscreen path
305  m_output = osg::ref_ptr< WGEGroupNode > ( new WGEGroupNode() );
306 
307  // the WGEOffscreenRenderNode manages each of the render-passes for us
308  osg::ref_ptr< WGEOffscreenRenderNode > offscreen = new WGEOffscreenRenderNode(
309  WKernel::getRunningKernel()->getGraphicsEngine()->getViewer()->getCamera()
310  );
311 
312  // allow en-/disabling the HUD:
313  offscreen->getTextureHUD()->addUpdateCallback( new WGENodeMaskCallback( m_showHUD ) );
314 
315  // setup all the passes needed for image space advection
316  osg::ref_ptr< WGEShader > transformationShader = new WGEShader( "WMImageSpaceLIC-Transformation", m_localPath );
317  WGEShaderDefineOptions::SPtr availableDataDefines = WGEShaderDefineOptions::SPtr( new WGEShaderDefineOptions( "SCALARDATA", "VECTORDATA" ) );
318  transformationShader->addPreprocessor( availableDataDefines );
319  transformationShader->addPreprocessor( define3dNoise );
320  transformationShader->addPreprocessor( WGEShaderPreprocessor::SPtr(
321  new WGEShaderPropertyDefineOptions< WPropBool >( m_3dNoiseAutoRes, "NOISE3DAUTORES_DISABLED", "NOISE3DAUTORES_ENABLED" )
322  ) );
323 
324  // This should not be needed. But somehow, the u_vertexShift uniforms does not get removed by OSG when switching to mesh.
325  transformationShader->addPreprocessor( WGEShaderPreprocessor::SPtr(
326  new WGEShaderPropertyDefineOptions< WPropBool >( m_useSlices, "VERTEXSHIFT_DISABLED", "VERTEXSHIFT_ENABLED" )
327  ) );
328 
329  osg::ref_ptr< WGEOffscreenRenderPass > transformation = offscreen->addGeometryRenderPass(
330  m_output,
331  transformationShader,
332  "Transformation"
333  );
334  transformation->bind( rand3DTexture, 1 );
335  // apply colormapping to transformation
336  WGEColormapping::apply( transformation, transformationShader, 2 );
337 
338  osg::ref_ptr< WGEShader > edgeShader = new WGEShader( "WMImageSpaceLIC-Edge", m_localPath );
339  osg::ref_ptr< WGEOffscreenRenderPass > edgeDetection = offscreen->addTextureProcessingPass(
340  edgeShader,
341  "Edge Detection"
342  );
343  edgeShader->addPreprocessor( define3dNoise );
344 
345  // we use two advection passes per frame as the input A of the first produces the output B whereas the second pass uses B as input and
346  // produces A as output. This way we can use A as input for the next step (clipping and blending).
347  osg::ref_ptr< WGEOffscreenRenderPass > advection = offscreen->addTextureProcessingPass(
348  new WGEShader( "WMImageSpaceLIC-Advection", m_localPath ),
349  "Advection"
350  );
351 
352  // finally, put it back on screen, clip it, color it and apply depth buffer to on-screen buffer
353  osg::ref_ptr< WGEOffscreenRenderPass > clipBlend = offscreen->addFinalOnScreenPass(
354  new WGEShader( "WMImageSpaceLIC-ClipBlend", m_localPath ),
355  "Clip & Blend"
356  );
357 
358  // hardwire the textures to use for each pass:
359 
360  // Transformation Pass, needs Geometry
361  // * Creates 2D projected Vectors in RG
362  // * Lighting in B
363  // * Depth
364  osg::ref_ptr< osg::Texture2D > transformationOut1 = transformation->attach( WGECamera::COLOR_BUFFER0 );
365  osg::ref_ptr< osg::Texture2D > transformationColormapped = transformation->attach( WGECamera::COLOR_BUFFER1 );
366  osg::ref_ptr< osg::Texture2D > transformationDepth = transformation->attach( WGECamera::DEPTH_BUFFER );
367  // and some uniforms
368  transformation->addUniform( new WGEPropertyUniform< WPropDouble >( "u_noise3DResoultuion", m_3dNoiseRes ) );
369  transformation->addUniform( new WGEPropertyUniform< WPropDouble >( "u_projectionAngleThreshold", m_projectionAngleThreshold ) );
370 
371  // Edge Detection Pass, needs Depth as input
372  // * Edges in R
373  // * Depth in G
374  // * Un-advected Noise in B
375  osg::ref_ptr< osg::Texture2D > edgeDetectionOut1 = edgeDetection->attach( WGECamera::COLOR_BUFFER0 );
376  edgeDetection->bind( transformationDepth, 0 );
377  edgeDetection->bind( randTexture, 1 );
378  edgeDetection->bind( transformationOut1, 2 );
379 
380  // Advection Pass, needs edges and projected vectors as well as noise texture
381  // * Advected noise in luminance channel
382  osg::ref_ptr< osg::Texture2D > advectionOutA = advection->attach( WGECamera::COLOR_BUFFER0, GL_LUMINANCE );
383  advection->bind( transformationOut1, 0 );
384  advection->bind( edgeDetectionOut1, 1 );
385 
386  // advection needs some uniforms controlled by properties
387  osg::ref_ptr< osg::Uniform > numIters = new WGEPropertyUniform< WPropInt >( "u_numIter", m_numIters );
388  advection->addUniform( numIters );
389 
390  // provide the Gbuffer input, with several mipmap levels
391  advectionOutA->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR );
392  edgeDetectionOut1->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR );
393  transformationColormapped->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR );
394 
395  // Final clipping and blending phase, needs Advected Noise, Edges, Depth and Light
396  clipBlend->bind( advectionOutA, 0 );
397  clipBlend->bind( edgeDetectionOut1, 1 );
398  clipBlend->bind( transformationColormapped, 2 );
399 
400  // final pass needs some uniforms controlled by properties
401  clipBlend->addUniform( new WGEPropertyUniform< WPropBool >( "u_useEdges", m_useEdges ) );
402  clipBlend->addUniform( new WGEPropertyUniform< WPropColor >( "u_useEdgesColor", m_useEdgesColor ) );
403  clipBlend->addUniform( new WGEPropertyUniform< WPropDouble >( "u_useEdgesStep", m_useEdgesStep ) );
404  clipBlend->addUniform( new WGEPropertyUniform< WPropBool >( "u_useLight", m_useLight ) );
405  clipBlend->addUniform( new WGEPropertyUniform< WPropDouble >( "u_lightIntensity", m_lightIntensity ) );
406  clipBlend->addUniform( new WGEPropertyUniform< WPropBool >( "u_useDepthCueing", m_useDepthCueing ) );
407  clipBlend->addUniform( new WGEPropertyUniform< WPropBool >( "u_useHighContrast", m_useHighContrast ) );
408  clipBlend->addUniform( new WGEPropertyUniform< WPropDouble >( "u_cmapRatio", m_cmapRatio ) );
409 
410  // add everything to root node
411  m_root->insert( offscreen );
412 
413  // Cull proxy. Updated on dataset change
414  osg::ref_ptr< osg::Node > cullProxy;
415 
416  // register scene
417  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_root );
418 
419  /////////////////////////////////////////////////////////////////////////////////////////////////////////
420  // Main loop
421  /////////////////////////////////////////////////////////////////////////////////////////////////////////
422 
423  // main loop
424  while( !m_shutdownFlag() )
425  {
426  debugLog() << "Waiting ...";
428 
429  // woke up since the module is requested to finish?
430  if( m_shutdownFlag() )
431  {
432  break;
433  }
434 
435  // To query whether an input was updated, simply ask the input:
436  bool dataUpdated = m_vectorsIn->handledUpdate() || m_scalarIn->handledUpdate() || m_meshIn->handledUpdate();
437  bool propertyUpdated = m_useSlices->changed();
438  std::shared_ptr< WDataSetVector > dataSetVec = m_vectorsIn->getData();
439  std::shared_ptr< WDataSetScalar > dataSetScal = m_scalarIn->getData();
440  std::shared_ptr< WTriangleMesh > mesh = m_meshIn->getData();
441 
442  bool dataValid = ( dataSetVec || dataSetScal );
443 
444  // is data valid? If not, remove graphics
445  if( !dataValid )
446  {
447  debugLog() << "Resetting.";
448  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( offscreen );
449  continue;
450  }
451 
452  // something interesting for us?
453  if( dataValid && !dataUpdated && !propertyUpdated )
454  {
455  continue;
456  }
457 
458  // prefer vector dataset if existing
459  std::shared_ptr< WGridRegular3D > grid;
460  if( dataSetVec )
461  {
462  debugLog() << "Using vector data";
463 
464  // get grid and prepare OSG
465  grid = std::dynamic_pointer_cast< WGridRegular3D >( dataSetVec->getGrid() );
466  m_xPos->setMax( grid->getNbCoordsX() - 1 );
467  m_yPos->setMax( grid->getNbCoordsY() - 1 );
468  m_zPos->setMax( grid->getNbCoordsZ() - 1 );
469  initOSG( grid, mesh );
470 
471  // prepare offscreen render chain
472  availableDataDefines->activateOption( 1 ); // vector input
473  transformation->bind( dataSetVec->getTexture(), 0 );
474  }
475  else if( dataSetScal )
476  {
477  debugLog() << "Using scalar data";
478 
479  // get grid and prepare OSG
480  grid = std::dynamic_pointer_cast< WGridRegular3D >( dataSetScal->getGrid() );
481  m_xPos->setMax( grid->getNbCoordsX() - 1 );
482  m_yPos->setMax( grid->getNbCoordsY() - 1 );
483  m_zPos->setMax( grid->getNbCoordsZ() - 1 );
484  initOSG( grid, mesh );
485 
486  // prepare offscreen render chain
487  availableDataDefines->activateOption( 0 ); // scalar input
488  transformation->bind( dataSetScal->getTexture(), 0 );
489  }
490 
491  // Update CullProxy when we get new data
492  // add a cull-proxy as we modify the geometry on the GPU
493  WBoundingBox bbox = grid->getVoxelBoundingBox();
494  m_root->remove( cullProxy );
495  cullProxy = wge::generateCullProxy( bbox );
496  m_root->insert( cullProxy );
497  debugLog() << "Done";
498  }
499 
500  // clean up
501  m_root->clear();
502  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_root );
503 }
504 
virtual void wait() const
Wait for the condition.
void setResetable(bool resetable=true, bool autoReset=true)
Sets the resetable flag.
virtual void add(std::shared_ptr< WCondition > condition)
Adds another condition to the set of conditions to wait for.
Class to encapsulate boost::condition_variable_any.
Definition: WCondition.h:42
static void apply(osg::ref_ptr< osg::Node > node, WMatrix4d preTransform=WMatrix4d::identity(), osg::ref_ptr< WGEShader > shader=osg::ref_ptr< WGEShader >(), size_t startTexUnit=0)
Apply the colormapping to the specified node.
Class to wrap around the osg Group node and providing a thread safe add/removal mechanism.
Definition: WGEGroupNode.h:48
This class adds some convenience methods to WGEGroupNode.
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.
Class implementing a uniform which can be controlled by a property instance.
This GLSL preprocessor is able to set one define from a list of defines depending on the active optio...
std::shared_ptr< WGEShaderDefineOptions > SPtr
Shared pointer for this class.
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
static WKernel * getRunningKernel()
Returns pointer to the currently running kernel.
Definition: WKernel.cpp:117
std::shared_ptr< WGraphicsEngine > getGraphicsEngine() const
Returns pointer to currently running instance of graphics engine.
Definition: WKernel.cpp:122
This module takes an vector dataset and used it to apply an image space based (fast) LIC to an arbitr...
std::shared_ptr< WCondition > m_propCondition
A condition used to notify about changes in several properties.
WPropBool m_showonY
indicates whether the vector should be shown on slice Y
WPropBool m_useEdges
indicates whether to show the edges
WPropDouble m_cmapRatio
the ratio between colormap and LIC
WPropInt m_yPos
y position of the slice
WPropBool m_showHUD
indicates whether to show the texture HUD
WPropGroup m_geometryGroup
the group contains several input geometry parameters
WPropInt m_numIters
the number of iterations done per frame
WPropBool m_useLight
indicates whether to use Phong
virtual void moduleMain()
Entry point after loading the module.
WPropColor m_useEdgesColor
indicated whether the edges (if enabled) should be black or white or green or red or ....
WPropGroup m_sliceGroup
the group contains several slice properties
WPropBool m_useHighContrast
use the high contrast version?
WPropBool m_useSlices
indicates whether the vector should be shown on slices or input geometry
std::shared_ptr< WModuleInputData< WTriangleMesh > > m_meshIn
The input containing the surface on which the LIC should be applied on.
std::shared_ptr< WModuleInputData< WDataSetVector > > m_vectorsIn
The input connector containing the vector field.
WPropGroup m_advancedLicGroup
The group for more advanced LIC features.
void initOSG(std::shared_ptr< WGridRegular3D > grid, std::shared_ptr< WTriangleMesh > mesh)
Initializes the needed geodes, transformations and vertex arrays.
virtual const std::string getDescription() const
Gives back a description of this module.
WPropBool m_3dNoiseAutoRes
Automatically adapt resolution of 3d texture according to zoom level.
osg::ref_ptr< WGEManagedGroupNode > m_root
Scene root node.
WPropBool m_showonX
indicates whether the vector should be shown on slice X
WPropDouble m_3dNoiseRes
The resolution scaling for the 3d noise.
WPropDouble m_lightIntensity
light intensity
WPropDouble m_useEdgesStep
define the steepness of the step function used to blend in the edge color.
WPropInt m_xPos
x position of the slice
osg::ref_ptr< WGEGroupNode > m_output
The Geode containing all the slices and the mesh.
WPropGroup m_licGroup
the group contains several LIC properties
WPropInt m_zPos
z position of the slice
WPropBool m_3dNoise
If true, a 3d noise texture is used for advection.
std::shared_ptr< WModuleInputData< WDataSetScalar > > m_scalarIn
The input connector containing the scalar field whose derived field is used for LIC.
WPropBool m_useDepthCueing
indicates whether to use depth cueing in the shader
virtual void connectors()
Initialize the connectors this module is using.
virtual ~WMImageSpaceLIC()
Destructor.
virtual void properties()
Initialize the properties for this module.
WPropBool m_showonZ
indicates whether the vector should be shown on slice Z
WMImageSpaceLIC()
Default constructor.
virtual const std::string getName() const
Gives back the name of this module.
virtual std::shared_ptr< WModule > factory() const
Due to the prototype design pattern used to build modules, this method returns a new instance of this...
WPropDouble m_projectionAngleThreshold
the angle threshold between surface and vector before clipping the vector.
static PtrType createAndAdd(std::shared_ptr< WModule > module, std::string name="", std::string description="")
Convenience method to create a new instance of this in data connector with proper type and add it to ...
Class representing a single module of OpenWalnut.
Definition: WModule.h:72
boost::filesystem::path m_localPath
The path where the module binary resides in.
Definition: WModule.h:734
virtual void properties()
Initialize properties in this function.
Definition: WModule.cpp:212
wlog::WStreamedLogger debugLog() const
Logger instance for comfortable debug logging.
Definition: WModule.cpp:575
wlog::WStreamedLogger warnLog() const
Logger instance for comfortable warning- logs.
Definition: WModule.cpp:580
std::shared_ptr< WProperties > m_properties
The property object for the module.
Definition: WModule.h:640
void ready()
Call this whenever your module is ready and can react on property changes.
Definition: WModule.cpp:505
WConditionSet m_moduleState
The internal state of the module.
Definition: WModule.h:703
WPropBool m_active
True whenever the module should be active.
Definition: WModule.h:723
virtual void connectors()
Initialize connectors in this function.
Definition: WModule.cpp:208
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
osg::ref_ptr< osg::Node > generateCullProxy(const WBoundingBox &bbox)
Generate a proxy cube, which ensures OSG does proper near-far plane calculation and culling.
Definition: WGEUtils.cpp:236
osg::ref_ptr< WGETexture< osg::Texture1D > > genWhiteNoiseTexture(size_t sizeX, size_t channels)
This generates an 1D texture only containing white noise in its channels.
osg::ref_ptr< osg::Geode > genFinitePlane(double xSize, double ySize, const WPlane &p, const WColor &color=WColor(0.0, 0.7, 0.7, 1.0), bool border=false)
Generates a geode out of a Plane with a fixed size in direction of the vectors which span that plane.