From 8489397dded3cf3cc20667550fb358aa3a075134 Mon Sep 17 00:00:00 2001 From: Sebastian Eichelbaum Date: Wed, 28 Jun 2017 20:34:22 +0200 Subject: [PATCH] [ADD] adding image space tensor LIC algorithm. Complete and working implementation. --- .../WMImageSpaceTensorLIC.cpp | 637 ++++++++++++++++++ .../WMImageSpaceTensorLIC.h | 203 ++++++ src/modules/imageSpaceTensorLIC/WToolkit.cpp | 49 ++ .../WTuringTextureCreator.cpp | 260 +++++++ .../WTuringTextureCreator.h | 107 +++ .../imageSpaceTensorLIC/resources/META | 59 ++ .../resources/WMImageSpaceTensorLIC.png | Bin 0 -> 893 bytes ...mageSpaceTensorLIC-Advection-fragment.glsl | 217 ++++++ ...MImageSpaceTensorLIC-Advection-vertex.glsl | 39 ++ ...mageSpaceTensorLIC-ClipBlend-fragment.glsl | 118 ++++ ...MImageSpaceTensorLIC-ClipBlend-vertex.glsl | 39 ++ .../WMImageSpaceTensorLIC-Edge-fragment.glsl | 94 +++ .../WMImageSpaceTensorLIC-Edge-vertex.glsl | 39 ++ ...paceTensorLIC-Postprocessing-fragment.glsl | 140 ++++ ...eSpaceTensorLIC-Postprocessing-vertex.glsl | 43 ++ ...paceTensorLIC-Transformation-fragment.glsl | 362 ++++++++++ ...paceTensorLIC-Transformation-varyings.glsl | 59 ++ ...eSpaceTensorLIC-Transformation-vertex.glsl | 130 ++++ src/modules/modules-others.toolbox | 1 + 19 files changed, 2596 insertions(+) create mode 100644 src/modules/imageSpaceTensorLIC/WMImageSpaceTensorLIC.cpp create mode 100644 src/modules/imageSpaceTensorLIC/WMImageSpaceTensorLIC.h create mode 100644 src/modules/imageSpaceTensorLIC/WToolkit.cpp create mode 100644 src/modules/imageSpaceTensorLIC/WTuringTextureCreator.cpp create mode 100644 src/modules/imageSpaceTensorLIC/WTuringTextureCreator.h create mode 100644 src/modules/imageSpaceTensorLIC/resources/META create mode 100644 src/modules/imageSpaceTensorLIC/resources/WMImageSpaceTensorLIC.png create mode 100644 src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Advection-fragment.glsl create mode 100644 src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Advection-vertex.glsl create mode 100644 src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-ClipBlend-fragment.glsl create mode 100644 src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-ClipBlend-vertex.glsl create mode 100644 src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Edge-fragment.glsl create mode 100644 src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Edge-vertex.glsl create mode 100644 src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Postprocessing-fragment.glsl create mode 100644 src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Postprocessing-vertex.glsl create mode 100644 src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Transformation-fragment.glsl create mode 100644 src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Transformation-varyings.glsl create mode 100644 src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Transformation-vertex.glsl diff --git a/src/modules/imageSpaceTensorLIC/WMImageSpaceTensorLIC.cpp b/src/modules/imageSpaceTensorLIC/WMImageSpaceTensorLIC.cpp new file mode 100644 index 000000000..5ce2e8fa3 --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/WMImageSpaceTensorLIC.cpp @@ -0,0 +1,637 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "core/common/WPropertyHelper.h" +#include "core/common/math/WMath.h" +#include "core/dataHandler/WDataHandler.h" +#include "core/dataHandler/WDataTexture3D.h" +#include "core/dataHandler/WGridRegular3D.h" +#include "core/graphicsEngine/WGEColormapping.h" +#include "core/graphicsEngine/WGEGeodeUtils.h" +#include "core/graphicsEngine/WGEUtils.h" +#include "core/graphicsEngine/WGETextureUtils.h" +#include "core/graphicsEngine/callbacks/WGELinearTranslationCallback.h" +#include "core/graphicsEngine/callbacks/WGENodeMaskCallback.h" +#include "core/graphicsEngine/offscreen/WGEOffscreenRenderNode.h" +#include "core/graphicsEngine/offscreen/WGEOffscreenRenderPass.h" +#include "core/graphicsEngine/shaders/WGEPropertyUniform.h" +#include "core/graphicsEngine/shaders/WGEShader.h" +#include "core/graphicsEngine/shaders/WGEShaderDefineOptions.h" +#include "core/graphicsEngine/shaders/WGEShaderPropertyDefineOptions.h" +#include "core/graphicsEngine/callbacks/WGEShaderAnimationCallback.h" +#include "core/kernel/WKernel.h" + +#include "WTuringTextureCreator.h" +#include "WMImageSpaceTensorLIC.h" + + + /** + * @brief Calculates a reaction diffusion texture using turings method. + * + * @param target the memory to store the texture to + * @param tileWidth the width of one tile + * @param tileHeight the height of one tile + * @param width the width of the target mem + * @param height the height of the target mem. Not used. + * @param iterations the number of iterations to use + * @param spotSize the size of the spots - [0,1] + * @param spotIrregularity value specifying irregularity of the spots - [0,1] + */ +void genReactionDiffusion( unsigned char* target, + unsigned int tileWidth, unsigned int tileHeight, + unsigned int width, unsigned int /* height */, + unsigned int iterations, + float spotSize, + float spotIrregularity) +{ + ///////////////////////////////////////////////////////////////////////////////////////////// + // 1: get memory + ///////////////////////////////////////////////////////////////////////////////////////////// + + // at first create some mem + // FIXME clean up this mess. There may be a way to reduce memory cost + float grid1[tileWidth][tileHeight]; + float grid1Min= 3.0; + float grid1Max= 5.0; + float grid1Base= 4.0; + + float grid2[tileWidth][tileHeight]; + float grid2Base= 4.0; + + float delta1[tileWidth][tileHeight]; + float delta2[tileWidth][tileHeight]; + + float noise[tileWidth][tileHeight]; + + float noiseRangeMin=0.1; + float noiseRangeMax=5.0; + + float noiseRange= noiseRangeMin + ((noiseRangeMax - noiseRangeMin)*spotIrregularity); // the highter the more irregular "spots" + float noiseBase=12.0; + + ///////////////////////////////////////////////////////////////////////////////////////////// + // 2: init the grids and create random seed used during turing iteration + ///////////////////////////////////////////////////////////////////////////////////////////// + + // init grids + srand48(time(0)); + for (unsigned int y=0; y creates seamless textures + unsigned int iPrev = (i + tileWidth - 1) % tileWidth; + unsigned int iNext = (i + 1) % tileWidth; + + for (unsigned int j = 0; j < tileHeight; j++) + { + // this ensures we have an "endless" plane -> creates seamless textures + unsigned int jPrev = (j + tileHeight - 1) % tileHeight; + unsigned int jNext = (j + 1) % tileHeight; + + /* + // try the other laplacian filter + float laplacian1= grid1[iPrev][jPrev] + grid1[i][jPrev] + grid1[iNext][jPrev] + + grid1[iPrev][j] - (8.0*grid1[i][j]) + grid1[iNext][j] + + grid1[iPrev][jNext] + grid1[i][jNext] + grid1[iNext][jNext]; + + float laplacian2= grid2[iPrev][jPrev] + grid2[i][jPrev] + grid2[iNext][jPrev] + + grid2[iPrev][j] - (8.0*grid2[i][j]) + grid2[iNext][j] + + grid2[iPrev][jNext] + grid2[i][jNext] + grid2[iNext][jNext]; + */ + + // apply laplace filter around current grid point + float laplacian1=grid1[i][jPrev] + grid1[i][jNext] + grid1[iPrev][j] + grid1[iNext][j] - 4.0 * grid1[i][j]; + float laplacian2=grid2[i][jPrev] + grid2[i][jNext] + grid2[iPrev][j] + grid2[iNext][j] - 4.0 * grid2[i][j]; + + // diffusion reaction + delta1[i][j] = ka * (16 - grid1[i][j] * grid2[i][j]) + d1 * laplacian1; + delta2[i][j] = ka * (grid1[i][j] * grid2[i][j] - grid2[i][j] - noise[i][j]) + d2 * laplacian2; + } + } + + // apply delta and find min and max value + grid1Min= 1e20; + grid1Max=-1e20; + + for (unsigned int i = 0; i < tileWidth; i++) + for (unsigned int j = 0; j < tileHeight; j++) + { + grid1[i][j]+=(speed * delta1[i][j]); + grid2[i][j]+=(speed * delta2[i][j]); + if (grid2[i][j] < 0) + grid2[i][j] = 0; + + if (grid1[i][j] < grid1Min) + grid1Min=grid1[i][j]; + if (grid1[i][j] > grid1Max) + grid1Max=grid1[i][j]; + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////// + // 4: scale grid and copy to target + ///////////////////////////////////////////////////////////////////////////////////////////// + + for (unsigned int x = 0; x < tileWidth; x++) + for (unsigned int y = 0; y < tileHeight; y++) + target[(y*width) + x]=255.0*(grid1[x][y] - grid1Min) / (grid1Max - grid1Min); +} + +WMImageSpaceTensorLIC::WMImageSpaceTensorLIC(): + WModule() +{ +} + +WMImageSpaceTensorLIC::~WMImageSpaceTensorLIC() +{ + // Cleanup! +} + +boost::shared_ptr< WModule > WMImageSpaceTensorLIC::factory() const +{ + return boost::shared_ptr< WModule >( new WMImageSpaceTensorLIC() ); +} + +const std::string WMImageSpaceTensorLIC::getName() const +{ + return "Image Space Tensor LIC"; +} + +const std::string WMImageSpaceTensorLIC::getDescription() const +{ + return ""; +} + +void WMImageSpaceTensorLIC::connectors() +{ + // DTI input + m_evec1In = WModuleInputData< WDataSetVector >::createAndAdd( shared_from_this(), "evec1", "The first Eigenvectors dataset." ); + m_evec2In = WModuleInputData< WDataSetVector >::createAndAdd( shared_from_this(), "evec2", "The second Eigenvectors dataset." ); + m_evalsIn = WModuleInputData< WDataSetVector >::createAndAdd( shared_from_this(), "evals", "The Eigenvalues dataset." ); + + // mesh input + m_meshIn = WModuleInputData< WTriangleMesh >::createAndAdd( shared_from_this(), "surface", "The optional surface to use." ); + + // call WModule's initialization + WModule::connectors(); +} + +void WMImageSpaceTensorLIC::properties() +{ + m_propCondition = boost::shared_ptr< WCondition >( new WCondition() ); + + m_geometryGroup = m_properties->addPropertyGroup( "Geometry", "Selection of used geometry to apply LIC to." ); + + m_useSlices = m_geometryGroup->addProperty( "Use Slices", "Show vectors on slices.", true, m_propCondition ); + + m_sliceGroup = m_geometryGroup->addPropertyGroup( "Slices", "Slice based LIC." ); + + // enable slices + // Flags denoting whether the glyphs should be shown on the specific slice + m_showonX = m_sliceGroup->addProperty( "Show Sagittal", "Show vectors on sagittal slice.", true ); + m_showonY = m_sliceGroup->addProperty( "Show Coronal", "Show vectors on coronal slice.", true ); + m_showonZ = m_sliceGroup->addProperty( "Show Axial", "Show vectors on axial slice.", true ); + + // The slice positions. These get update externally. + // TODO(all): this should somehow be connected to the nav slices. + m_xPos = m_sliceGroup->addProperty( "Sagittal Position", "Slice X position.", 80 ); + m_yPos = m_sliceGroup->addProperty( "Coronal Position", "Slice Y position.", 100 ); + m_zPos = m_sliceGroup->addProperty( "Axial Position", "Slice Z position.", 80 ); + m_xPos->setMin( 0 ); + m_xPos->setMax( 159 ); + m_yPos->setMin( 0 ); + m_yPos->setMax( 199 ); + m_zPos->setMin( 0 ); + m_zPos->setMax( 159 ); + + m_licGroup = m_properties->addPropertyGroup( "LIC", "LIC properties." ); + + m_useLight = m_licGroup->addProperty( "Use Light", "Check to enable lightning using the Phong model.", false ); + m_lightIntensity = m_licGroup->addProperty( "Light Intensity", "Define how intense the light should be.", 1.0 ); + m_lightIntensity->setMin( 0.0 ); + m_lightIntensity->setMax( 10.0 ); + + m_useEdges = m_licGroup->addProperty( "Edges", "Check to enable blending in edges.", true ); + m_useEdgesColor = m_licGroup->addProperty( "Edge Color", "Define the color of the edges.", defaultColor::WHITE ); + m_useEdgesStep = m_licGroup->addProperty( "Edge Step", "Define the steepness of the blend function between color and edge color.", 1.0 ); + m_useEdgesStep->setMin( 0.0 ); + m_useEdgesStep->setMax( 10.0 ); + + m_cmapRatio = m_licGroup->addProperty( "Ratio Colormap to LIC", "Blending ratio between LIC and colormap.", 0.5 ); + m_cmapRatio->setMin( 0.0 ); + m_cmapRatio->setMax( 1.0 ); + + m_advancedLicGroup = m_properties->addPropertyGroup( "Advanced", "More advanced LIC properties." ); + // show hud? + m_showHUD = m_advancedLicGroup->addProperty( "Show HUD", "Check to enable the debugging texture HUD.", false ); + m_noiseRes = m_advancedLicGroup->addProperty( "Noise Resolution", "The noise is of 128^3 pixels size. This scaler allows " + "modification of this size.", 1.5 ); + m_noiseRes->setMin( 0 ); + m_noiseRes->setMax( 100 ); + + m_numIters = m_advancedLicGroup->addProperty( "Number of Iterations", "How much iterations along a streamline should be done per frame.", + 30 ); + m_numIters->setMin( 1 ); + m_numIters->setMax( 1000 ); + + m_projectionAngleThreshold = m_advancedLicGroup->addProperty( "Projection Angle Threshold", "This defines the threshold of the angle between " + "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 " + "clipped and NOT projected. Note: all vectors with an angle below this threshold are projected but linearly reduced in influence " + "depending on the angle.", 90.0 ); + m_projectionAngleThreshold->setMin( 0.0 ); + m_projectionAngleThreshold->setMax( 180.0 ); + + m_faClip = m_advancedLicGroup->addProperty( "Clip FA", "Clip by FA", 0.1 ); + m_faClip->setMin( 0.0 ); + m_faClip->setMax( 1.0 ); + + // call WModule's initialization + WModule::properties(); +} + +void WMImageSpaceTensorLIC::initOSG( boost::shared_ptr< WGridRegular3D > grid, boost::shared_ptr< WTriangleMesh > mesh ) +{ + // remove the old slices + m_output->clear(); + + if( mesh && !m_useSlices->get( true ) ) + { + // we have a mesh and want to use it + // create geometry and geode + osg::Geometry* surfaceGeometry = new osg::Geometry(); + osg::ref_ptr< osg::Geode > surfaceGeode = osg::ref_ptr< osg::Geode >( new osg::Geode ); + + surfaceGeometry->setVertexArray( mesh->getVertexArray() ); + osg::DrawElementsUInt* surfaceElement; + surfaceElement = new osg::DrawElementsUInt( osg::PrimitiveSet::TRIANGLES, 0 ); + std::vector< size_t > tris = mesh->getTriangles(); + surfaceElement->reserve( tris.size() ); + for( unsigned int vertId = 0; vertId < tris.size(); ++vertId ) + { + surfaceElement->push_back( tris[vertId] ); + } + surfaceGeometry->addPrimitiveSet( surfaceElement ); + + // normals + surfaceGeometry->setNormalArray( mesh->getVertexNormalArray() ); + surfaceGeometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX ); + + // texture coordinates + surfaceGeometry->setTexCoordArray( 0, mesh->getTextureCoordinateArray() ); + + // render + surfaceGeode->addDrawable( surfaceGeometry ); + m_output->insert( surfaceGeode ); + } + else if( !mesh && !m_useSlices->get( true ) ) + { + warnLog() << "No surface connected to input but surface render mode enabled. Nothing rendered."; + } + else + { + // create a new geode containing the slices + osg::ref_ptr< osg::Node > xSlice = wge::genFinitePlane( grid->getOrigin(), grid->getNbCoordsY() * grid->getDirectionY(), + grid->getNbCoordsZ() * grid->getDirectionZ() ); + + osg::ref_ptr< osg::Node > ySlice = wge::genFinitePlane( grid->getOrigin(), grid->getNbCoordsX() * grid->getDirectionX(), + grid->getNbCoordsZ() * grid->getDirectionZ() ); + + osg::ref_ptr< osg::Node > zSlice = wge::genFinitePlane( grid->getOrigin(), grid->getNbCoordsX() * grid->getDirectionX(), + grid->getNbCoordsY() * grid->getDirectionY() ); + + // disable picking + xSlice->setName( "_X SLice" ); + ySlice->setName( "_Y SLice" ); + zSlice->setName( "_Z SLice" ); + + // The movement of the slice is done in the shader. An alternative would be WGELinearTranslationCallback but there, the needed matrix is + // not available in the shader + osg::StateSet* ss = xSlice->getOrCreateStateSet(); + ss->addUniform( new WGEPropertyUniform< WPropInt >( "u_vertexShift", m_xPos ) ); + ss->addUniform( new osg::Uniform( "u_vertexShiftDirection", grid->getDirectionX().as< osg::Vec3f >() ) ); // the axis to move along + ss = ySlice->getOrCreateStateSet(); + ss->addUniform( new WGEPropertyUniform< WPropInt >( "u_vertexShift", m_yPos ) ); + ss->addUniform( new osg::Uniform( "u_vertexShiftDirection", grid->getDirectionY().as< osg::Vec3f >() ) ); // the axis to move along + ss = zSlice->getOrCreateStateSet(); + ss->addUniform( new WGEPropertyUniform< WPropInt >( "u_vertexShift", m_zPos ) ); + ss->addUniform( new osg::Uniform( "u_vertexShiftDirection", grid->getDirectionZ().as< osg::Vec3f >() ) ); // the axis to move along + + // set callbacks for en-/disabling the nodes + xSlice->addUpdateCallback( new WGENodeMaskCallback( m_showonX ) ); + ySlice->addUpdateCallback( new WGENodeMaskCallback( m_showonY ) ); + zSlice->addUpdateCallback( new WGENodeMaskCallback( m_showonZ ) ); + + // disable culling. + xSlice->setCullingActive( false ); + ySlice->setCullingActive( false ); + zSlice->setCullingActive( false ); + + // add the transformation nodes to the output group + m_output->insert( xSlice ); + m_output->insert( ySlice ); + m_output->insert( zSlice ); + m_output->dirtyBound(); + } +} + +void WMImageSpaceTensorLIC::moduleMain() +{ + // get notified about data changes + m_moduleState.setResetable( true, true ); + m_moduleState.add( m_evec1In->getDataChangedCondition() ); + m_moduleState.add( m_evec2In->getDataChangedCondition() ); + m_moduleState.add( m_evalsIn->getDataChangedCondition() ); + m_moduleState.add( m_meshIn->getDataChangedCondition() ); + // Remember the condition provided to some properties in properties()? The condition can now be used with this condition set. + m_moduleState.add( m_propCondition ); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + // Preparation 1: create noise texture + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + + // we need a noise texture with a sufficient resolution. Create it. + const size_t resX = 128; + float rdIrr = 0.0; + float rdSpot = 0.689; + unsigned int rdIter = 4000; + //unsigned char* rdField = new unsigned char[ resX * resX ]; + + osg::ref_ptr< osg::Image > ima = new osg::Image; + ima->allocateImage( resX, resX, 1, GL_LUMINANCE, GL_UNSIGNED_BYTE ); + genReactionDiffusion( ima->data(), resX, resX, resX, resX, rdIter, rdSpot, rdIrr ); + + WGETexture2D::SPtr randTexture( new WGETexture2D( ima ) ); + randTexture->setWrap( osg::Texture::WRAP_S, osg::Texture::REPEAT ); + randTexture->setWrap( osg::Texture::WRAP_T, osg::Texture::REPEAT ); + + // done. + ready(); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + // Preparation 2: initialize offscreen renderer and hardwire it + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + + // create the root node for all the geometry + m_root = osg::ref_ptr< WGEManagedGroupNode > ( new WGEManagedGroupNode( m_active ) ); + + // root geometry node for the offscreen path + m_output = osg::ref_ptr< WGEGroupNode > ( new WGEGroupNode() ); + + // the WGEOffscreenRenderNode manages each of the render-passes for us + osg::ref_ptr< WGEOffscreenRenderNode > offscreen = new WGEOffscreenRenderNode( + WKernel::getRunningKernel()->getGraphicsEngine()->getViewer()->getCamera() + ); + + // allow en-/disabling the HUD: + offscreen->getTextureHUD()->addUpdateCallback( new WGENodeMaskCallback( m_showHUD ) ); + + // setup all the passes needed for image space advection + osg::ref_ptr< WGEShader > transformationShader = new WGEShader( "WMImageSpaceTensorLIC-Transformation", m_localPath ); + + // This should not be needed. But somehow, the u_vertexShift uniforms does not get removed by OSG when switching to mesh. + transformationShader->addPreprocessor( WGEShaderPreprocessor::SPtr( + new WGEShaderPropertyDefineOptions< WPropBool >( m_useSlices, "VERTEXSHIFT_DISABLED", "VERTEXSHIFT_ENABLED" ) + ) ); + + osg::ref_ptr< WGEOffscreenRenderPass > transformation = offscreen->addGeometryRenderPass( + m_output, + transformationShader, + "Transformation" + ); + transformation->bind( randTexture, 3 ); + // apply colormapping to transformation + WGEColormapping::apply( transformation, transformationShader, 4 ); + + osg::ref_ptr< WGEShader > edgeShader = new WGEShader( "WMImageSpaceTensorLIC-Edge", m_localPath ); + osg::ref_ptr< WGEOffscreenRenderPass > edgeDetection = offscreen->addTextureProcessingPass( + edgeShader, + "Edge Detection" + ); + + // 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 + // produces A as output. This way we can use A as input for the next step (clipping and blending). + osg::ref_ptr< WGEOffscreenRenderPass > advection = offscreen->addTextureProcessingPass( + new WGEShader( "WMImageSpaceTensorLIC-Advection", m_localPath ), + "Advection" + ); + + // finally, put it back on screen, clip it, color it and apply depth buffer to on-screen buffer + osg::ref_ptr< WGEOffscreenRenderPass > clipBlend = offscreen->addTextureProcessingPass( + new WGEShader( "WMImageSpaceTensorLIC-ClipBlend", m_localPath ), + "Clip & Blend" + ); + + // finally, put it back on screen, clip it, color it and apply depth buffer to on-screen buffer + osg::ref_ptr< WGEOffscreenRenderPass > postprocessing = offscreen->addFinalOnScreenPass( + new WGEShader( "WMImageSpaceTensorLIC-Postprocessing", m_localPath ), + "Postprocessing" + ); + + // hardwire the textures to use for each pass: + + // Transformation Pass, needs Geometry + // * Creates 2D projected Vectors in RG and BA + // * Lighting and projected noise in out2.rg, depth in b + // * Depth + osg::ref_ptr< osg::Texture2D > transformationOut1 = transformation->attach( WGECamera::COLOR_BUFFER0 ); + osg::ref_ptr< osg::Texture2D > transformationOut2 = transformation->attach( WGECamera::COLOR_BUFFER1 ); + osg::ref_ptr< osg::Texture2D > transformationOut3 = transformation->attach( WGECamera::COLOR_BUFFER2 ); + osg::ref_ptr< osg::Texture2D > transformationColormapped = transformation->attach( WGECamera::COLOR_BUFFER3 ); + osg::ref_ptr< osg::Texture2D > transformationDepth = transformation->attach( WGECamera::DEPTH_BUFFER ); + // and some uniforms + transformation->addUniform( new WGEPropertyUniform< WPropDouble >( "u_noiseResoultuion", m_noiseRes ) ); + transformation->addUniform( new WGEPropertyUniform< WPropDouble >( "u_projectionAngleThreshold", m_projectionAngleThreshold ) ); + transformation->addUniform( new WGEPropertyUniform< WPropDouble >( "u_clipFA", m_faClip ) ); + + // Edge Detection Pass, needs Depth as input + // * Edges in R, noise in G + osg::ref_ptr< osg::Texture2D > edgeDetectionOut1 = edgeDetection->attach( WGECamera::COLOR_BUFFER0 ); + edgeDetection->bind( transformationDepth, 0 ); + edgeDetection->bind( transformationOut2, 1 ); + + // Advection Pass, needs edges and projected vectors as well as noise texture + // * Advected noise in luminance channel + osg::ref_ptr< osg::Texture2D > advectionOutA = advection->attach( WGECamera::COLOR_BUFFER0, GL_RGBA ); + advection->bind( transformationOut1, 0 ); + advection->bind( edgeDetectionOut1, 1 ); + + // advection needs some uniforms controlled by properties + osg::ref_ptr< osg::Uniform > numIters = new WGEPropertyUniform< WPropInt >( "u_numIter", m_numIters ); + advection->addUniform( numIters ); + + osg::Uniform* animationTime( new osg::Uniform( "u_animation", 0 ) ); + animationTime->setUpdateCallback( new WGEShaderAnimationCallback() ); + advection->addUniform( animationTime ); + + // provide the Gbuffer input, with several mipmap levels + advectionOutA->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR ); + edgeDetectionOut1->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR ); + transformationColormapped->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR ); + + // Final clipping and blending phase, needs Advected Noise, Edges, Depth and Light + osg::ref_ptr< osg::Texture2D > merged = clipBlend->attach( WGECamera::COLOR_BUFFER0, GL_RGBA ); + clipBlend->bind( advectionOutA, 0 ); + clipBlend->bind( edgeDetectionOut1, 1 ); + clipBlend->bind( transformationColormapped, 2 ); + clipBlend->bind( transformationOut2, 3 ); + clipBlend->bind( transformationOut3, 4 ); + + // final pass needs some uniforms controlled by properties + clipBlend->addUniform( new WGEPropertyUniform< WPropBool >( "u_useEdges", m_useEdges ) ); + clipBlend->addUniform( new WGEPropertyUniform< WPropColor >( "u_useEdgesColor", m_useEdgesColor ) ); + clipBlend->addUniform( new WGEPropertyUniform< WPropDouble >( "u_useEdgesStep", m_useEdgesStep ) ); + clipBlend->addUniform( new WGEPropertyUniform< WPropBool >( "u_useLight", m_useLight ) ); + clipBlend->addUniform( new WGEPropertyUniform< WPropDouble >( "u_lightIntensity", m_lightIntensity ) ); + clipBlend->addUniform( new WGEPropertyUniform< WPropDouble >( "u_cmapRatio", m_cmapRatio ) ); + + // The final pass should also blend properly: + postprocessing->getOrCreateStateSet()->setMode( GL_BLEND, osg::StateAttribute::ON ); + + // Final clipping and blending phase, needs Advected Noise, Edges, Depth and Light + postprocessing->bind( advectionOutA, 0 ); + postprocessing->bind( edgeDetectionOut1, 1 ); + postprocessing->bind( transformationColormapped, 2 ); + postprocessing->bind( transformationOut2, 3 ); + postprocessing->bind( transformationOut3, 4 ); + postprocessing->bind( merged, 5 ); + + // final pass needs some uniforms controlled by properties + postprocessing->addUniform( new WGEPropertyUniform< WPropBool >( "u_useEdges", m_useEdges ) ); + postprocessing->addUniform( new WGEPropertyUniform< WPropColor >( "u_useEdgesColor", m_useEdgesColor ) ); + postprocessing->addUniform( new WGEPropertyUniform< WPropDouble >( "u_useEdgesStep", m_useEdgesStep ) ); + postprocessing->addUniform( new WGEPropertyUniform< WPropBool >( "u_useLight", m_useLight ) ); + postprocessing->addUniform( new WGEPropertyUniform< WPropDouble >( "u_lightIntensity", m_lightIntensity ) ); + postprocessing->addUniform( new WGEPropertyUniform< WPropDouble >( "u_cmapRatio", m_cmapRatio ) ); + + // add everything to root node + m_root->insert( offscreen ); + + // Cull proxy. Updated on dataset change + osg::ref_ptr< osg::Node > cullProxy; + + // register scene + WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_root ); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + // Main loop + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + + // main loop + while( !m_shutdownFlag() ) + { + debugLog() << "Waiting ..."; + m_moduleState.wait(); + + // woke up since the module is requested to finish? + if( m_shutdownFlag() ) + { + break; + } + + // To query whether an input was updated, simply ask the input: + bool dataUpdated = m_evec1In->handledUpdate() || m_evec2In->handledUpdate() || m_meshIn->handledUpdate(); + bool propertyUpdated = m_useSlices->changed(); + boost::shared_ptr< WDataSetVector > dataSetEvec1 = m_evec1In->getData(); + boost::shared_ptr< WDataSetVector > dataSetEvec2 = m_evec2In->getData(); + boost::shared_ptr< WDataSetVector > dataSetEvals = m_evalsIn->getData(); + boost::shared_ptr< WTriangleMesh > mesh = m_meshIn->getData(); + + bool dataValid = ( dataSetEvals && dataSetEvec1 && dataSetEvec2 ); + + // is data valid? If not, remove graphics + if( !dataValid ) + { + debugLog() << "Resetting."; + WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( offscreen ); + continue; + } + + // something interesting for us? + if( dataValid && !dataUpdated && !propertyUpdated ) + { + continue; + } + + // prefer vector dataset if existing + boost::shared_ptr< WGridRegular3D > grid; + // get grid and prepare OSG + grid = boost::dynamic_pointer_cast< WGridRegular3D >( dataSetEvec1->getGrid() ); + m_xPos->setMax( grid->getNbCoordsX() - 1 ); + m_yPos->setMax( grid->getNbCoordsY() - 1 ); + m_zPos->setMax( grid->getNbCoordsZ() - 1 ); + initOSG( grid, mesh ); + + // prepare offscreen render chain + transformation->bind( dataSetEvec1->getTexture(), 0 ); + transformation->bind( dataSetEvec2->getTexture(), 1 ); + transformation->bind( dataSetEvals->getTexture(), 2 ); + + // Update CullProxy when we get new data + // add a cull-proxy as we modify the geometry on the GPU + WBoundingBox bbox = grid->getVoxelBoundingBox(); + m_root->remove( cullProxy ); + cullProxy = wge::generateCullProxy( bbox ); + m_root->insert( cullProxy ); + debugLog() << "Done"; + } + + // clean up + m_root->clear(); + WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_root ); +} + diff --git a/src/modules/imageSpaceTensorLIC/WMImageSpaceTensorLIC.h b/src/modules/imageSpaceTensorLIC/WMImageSpaceTensorLIC.h new file mode 100644 index 000000000..656c7e5ea --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/WMImageSpaceTensorLIC.h @@ -0,0 +1,203 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +#ifndef WMIMAGESPACETENSORLIC_H +#define WMIMAGESPACETENSORLIC_H + +#include +#include + +#include "core/dataHandler/WDataSetVector.h" + +#include "core/graphicsEngine/WTriangleMesh.h" +#include "core/graphicsEngine/WGEManagedGroupNode.h" + +#include "core/kernel/WModule.h" +#include "core/kernel/WModuleInputData.h" + +/** + * This module takes a second order symmetric tensor dataset and uses it to apply an image space based (fast) fabric-like LIC to an arbitrary + * surface. The surface can be specified as tri mesh or, if not specified, slices. + * + * \ingroup modules + */ +class WMImageSpaceTensorLIC: public WModule +{ +public: + /** + * Default constructor. + */ + WMImageSpaceTensorLIC(); + + /** + * Destructor. + */ + virtual ~WMImageSpaceTensorLIC(); + + /** + * Gives back the name of this module. + * \return the module's name. + */ + virtual const std::string getName() const; + + /** + * Gives back a description of this module. + * \return description to module. + */ + virtual const std::string getDescription() const; + + /** + * Due to the prototype design pattern used to build modules, this method returns a new instance of this method. NOTE: it + * should never be initialized or modified in some other way. A simple new instance is required. + * + * \return the prototype used to create every module in OpenWalnut. + */ + virtual boost::shared_ptr< WModule > factory() const; + +protected: + /** + * Entry point after loading the module. Runs in separate thread. + */ + virtual void moduleMain(); + + /** + * Initialize the connectors this module is using. + */ + virtual void connectors(); + + /** + * Initialize the properties for this module. + */ + virtual void properties(); + +private: + /** + * Initializes the needed geodes, transformations and vertex arrays. This needs to be done once for each new dataset. + * + * \param grid the grid to places the slices in + * \param mesh the mesh to use if not NULL and m_useSlices is false + */ + void initOSG( boost::shared_ptr< WGridRegular3D > grid, boost::shared_ptr< WTriangleMesh > mesh ); + + /** + * The input connector containing the DTI field whose derived field is used for LIC. + */ + boost::shared_ptr< WModuleInputData< WDataSetVector > > m_evec1In; + + /** + * The input connector containing the DTI field whose derived field is used for LIC. + */ + boost::shared_ptr< WModuleInputData< WDataSetVector > > m_evec2In; + + /** + * The input connector containing the DTI field whose derived field is used for LIC. + */ + boost::shared_ptr< WModuleInputData< WDataSetVector > > m_evalsIn; + + /** + * The input containing the surface on which the LIC should be applied on + */ + boost::shared_ptr< WModuleInputData< WTriangleMesh > > m_meshIn; + + /** + * A property allowing the user to select whether the slices or the mesh should be used + */ + WPropSelection m_geometrySelection; + + /** + * A list of items that can be selected using m_geometrySelection. + */ + boost::shared_ptr< WItemSelection > m_geometrySelections; + + /** + * A condition used to notify about changes in several properties. + */ + boost::shared_ptr< WCondition > m_propCondition; + + /** + * The Geode containing all the slices and the mesh + */ + osg::ref_ptr< WGEGroupNode > m_output; + + /** + * Scene root node. + */ + osg::ref_ptr< WGEManagedGroupNode > m_root; + + WPropGroup m_sliceGroup; //!< the group contains several slice properties + + WPropGroup m_geometryGroup; //!< the group contains several input geometry parameters + + WPropGroup m_licGroup; //!< the group contains several LIC properties + + WPropBool m_useSlices; //!< indicates whether the vector should be shown on slices or input geometry + + WPropInt m_xPos; //!< x position of the slice + + WPropInt m_yPos; //!< y position of the slice + + WPropInt m_zPos; //!< z position of the slice + + WPropBool m_showonX; //!< indicates whether the vector should be shown on slice X + + WPropBool m_showonY; //!< indicates whether the vector should be shown on slice Y + + WPropBool m_showonZ; //!< indicates whether the vector should be shown on slice Z + + WPropBool m_showHUD; //!< indicates whether to show the texture HUD + + WPropBool m_useEdges; //!< indicates whether to show the edges + + WPropColor m_useEdgesColor; //!< indicated whether the edges (if enabled) should be black or white or green or red or .... + + WPropDouble m_useEdgesStep; //!< define the steepness of the step function used to blend in the edge color. + + WPropBool m_useLight; //!< indicates whether to use Phong + + WPropDouble m_lightIntensity; //!< light intensity + + WPropInt m_numIters; //!< the number of iterations done per frame + + WPropDouble m_cmapRatio; //!< the ratio between colormap and LIC + + WPropDouble m_projectionAngleThreshold; //!< the angle threshold between surface and vector before clipping the vector. + + /** + * The group for more advanced LIC features + */ + WPropGroup m_advancedLicGroup; + + /** + * The resolution scaling for the noise + */ + WPropDouble m_noiseRes; + + /** + * Clipp according to FA. + */ + WPropDouble m_faClip; +}; + +#endif // WMIMAGESPACETENSORLIC_H + diff --git a/src/modules/imageSpaceTensorLIC/WToolkit.cpp b/src/modules/imageSpaceTensorLIC/WToolkit.cpp new file mode 100644 index 000000000..5b565ba4d --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/WToolkit.cpp @@ -0,0 +1,49 @@ +//--------------------------------------------------------------------------- +// +// Project: OpenWalnut ( http://www.openwalnut.org ) +// +// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-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 . +// +//--------------------------------------------------------------------------- + +// This file's purpose is to provide a list of modules and additional extensions as entry point for OpenWalnut's module loader. +// Both functAdd your modules here. If you miss this step, OpenWalnut will not be able to load your modules/extensions. + +#include + +#include + +#include "WMImageSpaceTensorLIC.h" + +/** + * This function is called by OpenWalnut, when loading your library to learn about the modules you provide. The function is called with a given + * list reference, where you add all of your modules. Modules which are not registered this way, cannot be used in OpenWalnut. As this is called + * before loading any project file or running any module, it is ensured that you can rely on the modules provided here in your project files and + * other modules. + * + * \note this function is optional. You can remove it if you do not need it. + * + * \param m the list of modules. Add you module instances into this list. + */ +extern "C" void WLoadModule( WModuleList& m ) // NOLINT +{ + // 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. + m.push_back( boost::shared_ptr< WModule >( new WMImageSpaceTensorLIC ) ); +} + diff --git a/src/modules/imageSpaceTensorLIC/WTuringTextureCreator.cpp b/src/modules/imageSpaceTensorLIC/WTuringTextureCreator.cpp new file mode 100644 index 000000000..3a5fb8c4a --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/WTuringTextureCreator.cpp @@ -0,0 +1,260 @@ +//--------------------------------------------------------------------------- +// +// Project: OpenWalnut ( http://www.openwalnut.org ) +// +// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-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 . +// +//--------------------------------------------------------------------------- + +#include +#include + +#include + +#include + +#include "WTuringTextureCreator.h" + +WTuringTextureCreator::WTuringTextureCreator( std::size_t numThreads ) + : m_numIterations( 100 ), + m_spotIrregularity( 0.1 ), + m_spotSize( 0.1 ) +{ + WPrecond( numThreads > 0, "" ); + + for( std::size_t k = 0; k < numThreads; ++k ) + { + m_threads.push_back( boost::shared_ptr< TextureThread >( new TextureThread( k, numThreads ) ) ); + } +} + +WTuringTextureCreator::~WTuringTextureCreator() +{ +} + +void WTuringTextureCreator::setNumIterations( std::size_t iter ) +{ + WPrecond( iter > 0, "Invalid number of iterations!" ); + + m_numIterations = iter; +} + +void WTuringTextureCreator::setSpotIrregularity( float irr ) +{ + WPrecond( irr >= 0.0f && irr <= 1.0f, "Spot irregularity must be in [0,1]!" ); + + m_spotIrregularity = irr; +} + +void WTuringTextureCreator::setSpotSize( float size ) +{ + WPrecond( size >= 0.0f && size <= 1.0f, "Spot size must be in [0,1]!" ); + + m_spotSize = size; +} + +osg::ref_ptr< WGETexture3D > WTuringTextureCreator::create( std::size_t sizeX, std::size_t sizeY, std::size_t sizeZ ) +{ + // some constants, maybe change to parameters + float const spotFactor = ( 0.02f + 0.58f * ( 1.0f - m_spotSize ) ) / 15.0f; + float const d1 = 0.125f; + float const d2 = 0.03125f; + float const speed = 1.0f; + + std::vector< float > concentration1( sizeX * sizeY * sizeZ, 4.0f ); + std::vector< float > concentration2( sizeX * sizeY * sizeZ, 4.0f ); + std::vector< float > delta1( sizeX * sizeY * sizeZ, 0.0f ); + std::vector< float > delta2( sizeX * sizeY * sizeZ, 0.0f ); + std::vector< float > noise( sizeX * sizeY * sizeZ ); + + boost::mt19937 generator( std::time( 0 ) ); + + float noiseRange = 0.1f + 4.9f * m_spotIrregularity; + + boost::uniform_real< float > dist( 12.0f - noiseRange, 12.0f + noiseRange ); + boost::variate_generator< boost::mt19937&, boost::uniform_real< float > > rand( generator, dist ); + + // initialize noise + for( std::size_t k = 0; k < sizeX * sizeY * sizeZ; ++k ) + { + noise[ k ] = rand(); + } + + // iterate + for( std::size_t iter = 0; iter < m_numIterations; ++iter ) + { + std::cout << "iteration: " << iter << std::endl; + + // step one: calculate change in concentration across the volume + for( std::size_t k = 0; k < m_threads.size(); ++k ) + { + m_threads[ k ]->setTextureSize( sizeX, sizeY, sizeZ ); + m_threads[ k ]->setSpotFactor( spotFactor ); + m_threads[ k ]->setDiffusionConstants( d1, d2 ); + m_threads[ k ]->setBufferPointers( &concentration1, &concentration2, &noise, &delta1, &delta2 ); + m_threads[ k ]->run(); + } + + for( std::size_t k = 0; k < m_threads.size(); ++k ) + { + m_threads[ k ]->wait(); + } + + // applying the change in concentration is not too costly + for( std::size_t k = 0; k < sizeX * sizeY * sizeZ; ++k ) + { + concentration1[ k ] += speed * delta1[ k ]; + concentration2[ k ] += speed * delta2[ k ]; + } + } + + // allocate new osg::Image for the texture data + osg::ref_ptr< osg::Image > img = new osg::Image; + img->allocateImage( sizeX, sizeY, sizeZ, GL_LUMINANCE, GL_UNSIGNED_BYTE ); + + // find min and max + float c1min = *std::min_element( concentration1.begin(), concentration1.end() ); + float c1max = *std::max_element( concentration1.begin(), concentration1.end() ); + + // copy to image + for( std::size_t k = 0; k < sizeX * sizeY * sizeZ; ++k ) + { + img->data()[ k ] = 255.0f * ( concentration1[ k ] - c1min ) / ( c1max - c1min ); + } + + return osg::ref_ptr< WGETexture< osg::Texture3D > >( new WGETexture< osg::Texture3D >( img ) ); +} + +WTuringTextureCreator::TextureThread::TextureThread( std::size_t id, std::size_t max ) + : WThreadedRunner(), + m_id( id ), + m_maxThreads( max ), + m_sizeX( 2 ), + m_sizeY( 2 ), + m_sizeZ( 2 ), + m_spotFactor( 0.5 ), + m_diffusionConstant1( 0.5 ), + m_diffusionConstant2( 0.5 ) +{ +} + +WTuringTextureCreator::TextureThread::~TextureThread() +{ +} + +void WTuringTextureCreator::TextureThread::setDiffusionConstants( float d1, float d2 ) +{ + WPrecond( d1 >= 0.0 && d1 <= 1.0, "" ); + WPrecond( d2 >= 0.0 && d2 <= 1.0, "" ); + + m_diffusionConstant1 = d1; + m_diffusionConstant2 = d2; +} + +void WTuringTextureCreator::TextureThread::setSpotFactor( float spotFactor ) +{ + WPrecond( spotFactor > 0.0, "" ); + + m_spotFactor = spotFactor; +} + +void WTuringTextureCreator::TextureThread::setTextureSize( std::size_t sizeX, std::size_t sizeY, std::size_t sizeZ ) +{ + WPrecond( sizeX > 0, "" ); + WPrecond( sizeY > 0, "" ); + WPrecond( sizeZ > 0, "" ); + + m_sizeX = sizeX; + m_sizeY = sizeY; + m_sizeZ = sizeZ; +} + +void WTuringTextureCreator::TextureThread::threadMain() +{ + WPrecond( m_concentration1 != 0, "Invalid pointer!" ); + WPrecond( m_concentration2 != 0, "Invalid pointer!" ); + WPrecond( m_noise != 0, "Invalid pointer!" ); + WPrecond( m_delta1 != 0, "Invalid pointer!" ); + WPrecond( m_delta2 != 0, "Invalid pointer!" ); + + std::size_t const numVoxels = m_sizeX * m_sizeY * m_sizeZ; + + std::size_t start = m_id * ( numVoxels / m_maxThreads ); + std::size_t end = ( m_id + 1 ) * ( numVoxels / m_maxThreads ); + + if( m_id == m_maxThreads - 1 ) + { + end = numVoxels; + } + + for( std::size_t idx = start; idx < end; ++idx ) + { + std::size_t i = idx % m_sizeX; + std::size_t j = ( idx / m_sizeX ) % m_sizeY; + std::size_t k = ( idx / m_sizeX ) / m_sizeY; + + std::size_t iNext = ( i + 1 ) % m_sizeX; + std::size_t iPrev = ( i + m_sizeX - 1 ) % m_sizeX; + + std::size_t jNext = ( j + 1 ) % m_sizeY; + std::size_t jPrev = ( j + m_sizeY - 1 ) % m_sizeY; + + std::size_t kNext = ( k + 1 ) % m_sizeZ; + std::size_t kPrev = ( k + m_sizeZ - 1 ) % m_sizeZ; + + // estimate change in concentrations using 3d laplace filter + float dc1 = 0.0; + dc1 += ( *m_concentration1 )[ iPrev + j * m_sizeX + k * m_sizeX * m_sizeY ]; + dc1 += ( *m_concentration1 )[ iNext + j * m_sizeX + k * m_sizeX * m_sizeY ]; + dc1 += ( *m_concentration1 )[ i + jPrev * m_sizeX + k * m_sizeX * m_sizeY ]; + dc1 += ( *m_concentration1 )[ i + jNext * m_sizeX + k * m_sizeX * m_sizeY ]; + dc1 += ( *m_concentration1 )[ i + j * m_sizeX + kPrev * m_sizeX * m_sizeY ]; + dc1 += ( *m_concentration1 )[ i + j * m_sizeX + kNext * m_sizeX * m_sizeY ]; + dc1 -= 6.0f * ( *m_concentration1 )[ idx ]; + + float dc2 = 0.0; + dc2 += ( *m_concentration2 )[ iPrev + j * m_sizeX + k * m_sizeX * m_sizeY ]; + dc2 += ( *m_concentration2 )[ iNext + j * m_sizeX + k * m_sizeX * m_sizeY ]; + dc2 += ( *m_concentration2 )[ i + jPrev * m_sizeX + k * m_sizeX * m_sizeY ]; + dc2 += ( *m_concentration2 )[ i + jNext * m_sizeX + k * m_sizeX * m_sizeY ]; + dc2 += ( *m_concentration2 )[ i + j * m_sizeX + kPrev * m_sizeX * m_sizeY ]; + dc2 += ( *m_concentration2 )[ i + j * m_sizeX + kNext * m_sizeX * m_sizeY ]; + dc2 -= 6.0f * ( *m_concentration2 )[ idx ]; + + // diffusion + ( *m_delta1 )[ idx ] = m_spotFactor * ( 16.0f - ( *m_concentration1 )[ idx ] * ( *m_concentration2 )[ idx ] ) + m_diffusionConstant1 * dc1; + ( *m_delta2 )[ idx ] = m_spotFactor * ( ( *m_concentration1 )[ idx ] * ( *m_concentration2 )[ idx ] - ( *m_concentration2 )[ idx ] - ( *m_noise )[ idx ] ) + m_diffusionConstant2 * dc2; + } +} + +void WTuringTextureCreator::TextureThread::setBufferPointers( std::vector< float > const* concentration1, std::vector< float > const* concentration2, + std::vector< float > const* noise, std::vector< float >* delta1, std::vector< float >* delta2 ) +{ + WPrecond( concentration1 != 0, "Invalid pointer!" ); + WPrecond( concentration2 != 0, "Invalid pointer!" ); + WPrecond( noise != 0, "Invalid pointer!" ); + WPrecond( delta1 != 0, "Invalid pointer!" ); + WPrecond( delta2 != 0, "Invalid pointer!" ); + + m_concentration1 = concentration1; + m_concentration2 = concentration2; + m_noise = noise; + m_delta1 = delta1; + m_delta2 = delta2; +} diff --git a/src/modules/imageSpaceTensorLIC/WTuringTextureCreator.h b/src/modules/imageSpaceTensorLIC/WTuringTextureCreator.h new file mode 100644 index 000000000..99d6ffb95 --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/WTuringTextureCreator.h @@ -0,0 +1,107 @@ +//--------------------------------------------------------------------------- +// +// Project: OpenWalnut ( http://www.openwalnut.org ) +// +// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-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 . +// +//--------------------------------------------------------------------------- + +#ifndef WTURINGTEXTURECREATOR_H +#define WTURINGTEXTURECREATOR_H + +#include + +#include + +#include +#include + +class WTuringTextureCreator +{ +public: + + WTuringTextureCreator( std::size_t numThreads = boost::thread::hardware_concurrency() ); + + ~WTuringTextureCreator(); + + osg::ref_ptr< WGETexture3D > create( std::size_t sizeX, std::size_t sizeY, std::size_t sizeZ ); + + void setSpotSize( float size ); + + void setSpotIrregularity( float irr ); + + void setNumIterations( std::size_t iter ); + +private: + + class TextureThread : public WThreadedRunner + { + public: + + TextureThread( std::size_t id, std::size_t max ); + + ~TextureThread(); + + void setTextureSize( std::size_t sizeX, std::size_t sizeY, std::size_t sizeZ ); + + void setSpotFactor( float spotFactor ); + + void setDiffusionConstants( float d1, float d2 ); + + void setBufferPointers( std::vector< float > const* concentration1, std::vector< float > const* concentration2, + std::vector< float > const* noise, std::vector< float >* delta1, std::vector< float >* delta2 ); + + virtual void threadMain(); + + private: + + std::size_t m_id; + + std::size_t m_maxThreads; + + std::size_t m_sizeX; + + std::size_t m_sizeY; + + std::size_t m_sizeZ; + + float m_spotFactor; + + float m_diffusionConstant1; + + float m_diffusionConstant2; + + std::vector< float > const* m_concentration1; + std::vector< float > const* m_concentration2; + std::vector< float > const* m_noise; + std::vector< float >* m_delta1; + std::vector< float >* m_delta2; + }; + + float m_numIterations; + + float m_spotIrregularity; + + float m_spotSize; + + + std::vector< boost::shared_ptr< TextureThread > > m_threads; +}; + +#endif // WTURINGTEXTURECREATOR_H diff --git a/src/modules/imageSpaceTensorLIC/resources/META b/src/modules/imageSpaceTensorLIC/resources/META new file mode 100644 index 000000000..454714740 --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/resources/META @@ -0,0 +1,59 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +// This defines some properties of the module "Template". This must +// match the name specified in WMTemplate::getName(). +"Image Space Tensor LIC" +{ + // Provide an icon. If the icon exists, it overrides the one provided by your + // getXPMIcon method. This path is relative to your module's resource directory. + icon="WMImageSpaceTensorLIC.png"; + + // Where to find the module? + website = "http://www.openwalnut.org"; + + // Provide a description, If you do so, this description overrides the one + // provided by your getDescription method. + // HINT: multi-line strings are not supported. Please provide long texts in + // one line. + description = "This module takes a field of second order tensors and creates an fabric-like structure on planes/surfaces."; + + // Provide a list of authors. These authors can have further information associated with them. First, + // define the list of authors + author = "Sebastian Eichelbaum"; + + // To provide further details on one or multiple authors, just open a new block called like + // the author. + // + // * all sub-values are optional + // * Especially a contact address is very handy. + // * This associates some URL and Mail contact info to "OpenWalnut Project". + "Sebastian Eichelbaum" + { + url="http://www.sebastian-eichelbaum.de"; + email="contact@openwalnut.org"; + what="Design, Development and Bug fixing"; + }; +}; + diff --git a/src/modules/imageSpaceTensorLIC/resources/WMImageSpaceTensorLIC.png b/src/modules/imageSpaceTensorLIC/resources/WMImageSpaceTensorLIC.png new file mode 100644 index 0000000000000000000000000000000000000000..939ea1d3210f65fe8d014fc4fc7a112aef9379e6 GIT binary patch literal 893 zcmV-@1A_dCP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ige_ z2_!BE?Jy_+000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0008mNklPfOcy7{@<}ZLKj)TBFrDq3uC*Epto{Qy3`X4xUArz60?UI6V3Sym}Wp^rj*V zFPnG}PtH-%L#cmIiPjdZF;y|yMYpM~cu3ca-{bFjNIv9w^8NmVcsy=XMv0VJuIDs; z9vTARYdn7MJeWxEW^N8GnZ#w9m^C#VN24Trdr7ynI0sNjuh-W2I5~-6|D9lUI!$DG znaJ|;BUr})+Gb}FY@37jc76^IlWSCYKQHYP7E)qhfDcnsw9U-$c4mh2`g$^v2!|aV>~(fxyIiFO zNcHq!)YZ|lxJZ2>flt@*={lj+RazGo_&zqqrK*+=0N^+l<2V*Wuq=FshtzFt(K*aC6tEwsh+@@LD9r!dpPO7^bJsQOb z20;)|_x5;qYe2b%hSCCP$s}4bS$HIZz^}o<(gJ*&m>|5eLjC3@^3f5ZWsz4DPMe$A z?(Zkv+WM^L2rqH`C}i5&0NB{rcsh)V^i@<;plKSas!~~52|zxdC!5W3dV1=t5j~XG z>m?G2;C8$3olBC0BuS{MN-CAY{wKm60}w@#a5#+H?IxGYq3b%PX(9*$e!ri_#ztgW zCKwE&>$>whplKQ&j|amrNTpI-TwGw=HkM_P$z(V`~n@fJ`RC_4PHfEE5ig@p`>~oG}mx5DJA5MUiwm{k*^6&T1d3 zm_=Kb#m>$Sp->1#QBV}6AmsUj8?>WVY?>z9+uQj4eiTKay1E)s6raq3mpJ|n>hue$ T_k3@l00000NkvXXu0mjf)E. +// +//--------------------------------------------------------------------------- + +#version 120 + +#include "WGEUtils.glsl" + +// This is updated by a callback: +uniform int u_animation; + +/** + * The texture Unit for the projected vectors + */ +uniform sampler2D u_texture0Sampler; + +/** + * The texture Unit for the edges and noise + */ +uniform sampler2D u_texture1Sampler; + +/** + * Size of advection texture in pixels + */ +uniform int u_texture0SizeX; + +/** + * Size of advection texture in pixels + */ +uniform int u_texture0SizeY; + +/** + * Size of advection texture in pixels + */ +uniform int u_texture0SizeZ; + +/** + * The blending ratio between noise and advected noise + */ +uniform float u_noiseRatio = 0.00; + +/** + * Number of iterations per frame. + */ +uniform int u_numIter = 30; + +uniform float u_stepSizeFactor = 1.0; + +/** + * Returns the vector at the given point. + * + * \param pos the position to retrieve the vector for + * + * \return the unscaled vector in [-1, 1] + */ +vec2 getVec1( in vec2 pos ) +{ + return ( 2.0 * ( texture2D( u_texture0Sampler, pos ).rg - vec2( 0.5, 0.5 ) ) ); +} + +/** + * Returns the vector at the given point. + * + * \param pos the position to retrieve the vector for + * + * \return the unscaled vector in [-1, 1] + */ +vec2 getVec2( in vec2 pos ) +{ + return ( 2.0 * ( texture2D( u_texture0Sampler, pos ).ba - vec2( 0.5, 0.5 ) ) ); +} + +/** + * Returns noise for the given position. + * + * \param pos the position + * + * \return noise + */ +float getNoise( in vec2 pos ) +{ + return texture2D( u_texture1Sampler, pos ).b; +} + +float advection1() +{ + vec2 texCoord = gl_TexCoord[0].st; + + + vec2 vec = getVec1( texCoord ); + + // simply iterate along the line using the vector at each point + vec2 lastVec1 = vec; + vec2 lastPos1 = gl_TexCoord[0].st; + vec2 lastVec2 = vec; + vec2 lastPos2 = gl_TexCoord[0].st; + float sum = 0.0; + int m = 2 * u_numIter; + for( int i = 0; i < u_numIter; ++i ) + { + vec2 newPos1 = lastPos1 + u_stepSizeFactor * vec2( lastVec1.x / ( 2.0 * u_texture0SizeX ), lastVec1.y / ( 2.0 * u_texture0SizeY ) ); + vec2 newPos2 = lastPos2 - u_stepSizeFactor * vec2( lastVec2.x / ( 2.0 * u_texture0SizeX ), lastVec2.y / ( 2.0 * u_texture0SizeY ) ); + vec2 newVec1 = getVec1( newPos1 ); + vec2 newVec2 = getVec1( newPos2 ); + + // if( ( length( newVec1 ) < 0.01 ) || ( length( newVec2 ) < 0.01 ) ) + // { + // m = 2 * i; + // break; + // } + + // it is also possible to scale using a Geometric progression: float( u_numIter - i ) / u_numIter * texture2D + sum += getNoise( newPos1 ); + sum += getNoise( newPos2 ); + + lastPos1 = newPos1; + lastVec1 = newVec1; + lastPos2 = newPos2; + lastVec2 = newVec2; + } + + // the sum needs to be scaled to [0,1] again + float n = sum / float( m ); + + return n; +} + + +float advection2() +{ + vec2 texCoord = gl_TexCoord[0].st; + + + vec2 vec = getVec2( texCoord ); + + // simply iterate along the line using the vector at each point + vec2 lastVec1 = vec; + vec2 lastPos1 = gl_TexCoord[0].st; + vec2 lastVec2 = vec; + vec2 lastPos2 = gl_TexCoord[0].st; + float sum = 0.0; + int m = 2 * u_numIter; + for( int i = 0; i < u_numIter; ++i ) + { + vec2 newPos1 = lastPos1 + u_stepSizeFactor * vec2( lastVec1.x / ( 2.0 * u_texture0SizeX ), lastVec1.y / ( 2.0 * u_texture0SizeY ) ); + vec2 newPos2 = lastPos2 - u_stepSizeFactor * vec2( lastVec2.x / ( 2.0 * u_texture0SizeX ), lastVec2.y / ( 2.0 * u_texture0SizeY ) ); + vec2 newVec1 = getVec2( newPos1 ); + vec2 newVec2 = getVec2( newPos2 ); + + // if( ( length( newVec1 ) < 0.01 ) || ( length( newVec2 ) < 0.01 ) ) + // { + // m = 2 * i; + // break; + // } + + // it is also possible to scale using a Geometric progression: float( u_numIter - i ) / u_numIter * texture2D + sum += getNoise( newPos1 ); + sum += getNoise( newPos2 ); + + lastPos1 = newPos1; + lastVec1 = newVec1; + lastPos2 = newPos2; + lastVec2 = newVec2; + } + + // the sum needs to be scaled to [0,1] again + float n = sum / float( m ); + + return n; +} + + +/** + * Main. Calculates the Laplace Filter for each pixel. + */ +void main() +{ + vec2 texCoord = gl_TexCoord[0].st; + + // get some needed values + float edge = texture2D( u_texture1Sampler, texCoord ).r; + float depth = texture2D( u_texture1Sampler, texCoord ).g; + float noise = getNoise( texCoord ); + + float n1 = advection1(); + float n2 = advection2(); + + if( depth > 0.99 ) + { + n1 = noise; + n2 = noise; + } + + // finally, blend noise and old noise + gl_FragColor = vec4( n1, n2, 0.0, 1.0 ); +} + diff --git a/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Advection-vertex.glsl b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Advection-vertex.glsl new file mode 100644 index 000000000..336d9085c --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Advection-vertex.glsl @@ -0,0 +1,39 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +#version 120 + +void main() +{ + // pass the color to the fragment shader + gl_FrontColor = gl_Color; + gl_BackColor = gl_Color; + + // pass tex coordinates + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; + + // transform position + gl_Position = ftransform(); +} + diff --git a/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-ClipBlend-fragment.glsl b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-ClipBlend-fragment.glsl new file mode 100644 index 000000000..4feb4495f --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-ClipBlend-fragment.glsl @@ -0,0 +1,118 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +#version 120 + +#include "WGEUtils.glsl" +#include "WGEShadingTools.glsl" + +/** + * The texture Unit for the advection texture + */ +uniform sampler2D u_texture0Sampler; + +/** + * The texture Unit for the edge, depht texture + */ +uniform sampler2D u_texture1Sampler; + +/** + * The texture Unit for the colormapping + */ +uniform sampler2D u_texture2Sampler; + +/** + * The texture Unit for the light, depht texture + */ +uniform sampler2D u_texture3Sampler; + +/** + * The texture Unit for the light, depht texture + */ +uniform sampler2D u_texture4Sampler; + +/** + * Used to en-/disable lighting. + */ +uniform bool u_useLight; + +/** + * Define the light intensity here. + */ +uniform float u_lightIntensity; + +/** + * Used to en-/disable blending of edges. + */ +uniform bool u_useEdges; + +/** + * Edge color to use + */ +uniform vec4 u_useEdgesColor; + +/** + * Step function border for blending in the edges. + */ +uniform float u_useEdgesStep; + +/** + * If true, the depth is blended in + */ +uniform bool u_useDepthCueing; + +/** + * Ratio between colormap and advected noise + */ +uniform float u_cmapRatio; + +/** + * How intensive should contrast enhancement be? + */ +uniform bool u_useHighContrast; + +/** + * Main. Clips and Blends the final image space rendering with the previously acquired 3D information + */ +void main() +{ + vec2 texCoord = gl_TexCoord[0].st; + float edge = texture2D( u_texture1Sampler, texCoord ).r * ( u_useEdges ? 1.0 : 0.0 ); + float noise = texture2D( u_texture1Sampler, texCoord ).b; + float light = texture2D( u_texture3Sampler, texCoord ).r * ( u_useLight ? 1.0 : 0.0 ); + float depth = texture2D( u_texture3Sampler, texCoord ).b; + float occupied = texture2D( u_texture3Sampler, texCoord ).a; + float advected1 = texture2D( u_texture0Sampler, texCoord ).r; + float advected2 = texture2D( u_texture0Sampler, texCoord ).g; + vec3 cmap = texture2D( u_texture2Sampler, texCoord ).rgb; + float evDiff = texture2D( u_texture4Sampler, texCoord ).r; + float fa = texture2D( u_texture4Sampler, texCoord ).g; + + float r = 0.5; + float red = ( r * advected2 ) / ( 7.0 * pow( advected1, 2 ) ); + float green = ( ( 1.0 - r ) * advected1 ) / ( 8.0 * pow( advected2, 2 ) ); + vec3 outColor = vec3( red, green, 0.0 ); + gl_FragColor = vec4( outColor, 1.0 ); +} + diff --git a/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-ClipBlend-vertex.glsl b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-ClipBlend-vertex.glsl new file mode 100644 index 000000000..336d9085c --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-ClipBlend-vertex.glsl @@ -0,0 +1,39 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +#version 120 + +void main() +{ + // pass the color to the fragment shader + gl_FrontColor = gl_Color; + gl_BackColor = gl_Color; + + // pass tex coordinates + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; + + // transform position + gl_Position = ftransform(); +} + diff --git a/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Edge-fragment.glsl b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Edge-fragment.glsl new file mode 100644 index 000000000..98d6839ef --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Edge-fragment.glsl @@ -0,0 +1,94 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +#version 120 + +/** + * The texture Unit for the depth field + */ +uniform sampler2D u_texture0Sampler; + +/** + * The noise is stored here + */ +uniform sampler2D u_texture1Sampler; + +/** + * Size of texture in pixels + */ +uniform int u_texture0SizeX; + +/** + * Size of texture in pixels + */ +uniform int u_texture0SizeY; + +/** + * Size of texture in pixels + */ +uniform int u_texture0SizeZ; + +/** + * Main. Calculates the Laplace Filter for each pixel. + */ +void main() +{ + ///////////////////////////////////////////////////////////////////////////////////////////// + // GETTING TEXELS + // + // Get surrounding texels; needed for ALL filters + ///////////////////////////////////////////////////////////////////////////////////////////// + + // get data of surrounding textels + float offsetW = 2.0 / u_texture0SizeX; + float offsetH = 2.0 / u_texture0SizeY; + + vec2 texCoord = gl_TexCoord[0].st; + vec4 c = texture2D( u_texture0Sampler, texCoord ); + vec4 bl = texture2D( u_texture0Sampler, texCoord + vec2( -offsetW, -offsetH ) ); + vec4 l = texture2D( u_texture0Sampler, texCoord + vec2( -offsetW, 0.0 ) ); + vec4 tl = texture2D( u_texture0Sampler, texCoord + vec2( -offsetW, offsetH ) ); + vec4 t = texture2D( u_texture0Sampler, texCoord + vec2( 0.0, offsetH ) ); + vec4 tr = texture2D( u_texture0Sampler, texCoord + vec2( offsetW, offsetH ) ); + vec4 r = texture2D( u_texture0Sampler, texCoord + vec2( offsetW, 0.0 ) ); + vec4 br = texture2D( u_texture0Sampler, texCoord + vec2( offsetW, offsetH ) ); + vec4 b = texture2D( u_texture0Sampler, texCoord + vec2( 0.0, -offsetH ) ); + + ///////////////////////////////////////////////////////////////////////////////////////////// + // LAPLACE + // + // apply a standart laplace filter kernel + ///////////////////////////////////////////////////////////////////////////////////////////// + + float noise = texture2D( u_texture1Sampler, texCoord ).g; + + // laplace filter kernel + gl_FragColor = vec4( + 10.0 * abs( + 0.0 * tl + 1.0 * t + 0.0 * tr + + 1.0 * l + -4.0 * c + 1.0 * r + + 0.0 * bl + 1.0 * b + 0.0 * br + ).r, c.r, noise, 1.0 ); // also store noise in this texture +} + diff --git a/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Edge-vertex.glsl b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Edge-vertex.glsl new file mode 100644 index 000000000..336d9085c --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Edge-vertex.glsl @@ -0,0 +1,39 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +#version 120 + +void main() +{ + // pass the color to the fragment shader + gl_FrontColor = gl_Color; + gl_BackColor = gl_Color; + + // pass tex coordinates + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; + + // transform position + gl_Position = ftransform(); +} + diff --git a/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Postprocessing-fragment.glsl b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Postprocessing-fragment.glsl new file mode 100644 index 000000000..8efe673b0 --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Postprocessing-fragment.glsl @@ -0,0 +1,140 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +#version 120 + +#include "WGEUtils.glsl" +#include "WGEShadingTools.glsl" +#include "WGETextureTools.glsl" + +/** + * The texture Unit for the advection texture + */ +uniform sampler2D u_texture0Sampler; + +/** + * The texture Unit for the edge, depht texture + */ +uniform sampler2D u_texture1Sampler; + +/** + * The texture Unit for the colormapping + */ +uniform sampler2D u_texture2Sampler; + +/** + * The texture Unit for the light, depht texture + */ +uniform sampler2D u_texture3Sampler; + +/** + * The texture Unit for the light, depht texture + */ +uniform sampler2D u_texture4Sampler; + +/** + * The texture Unit for the light, depht texture + */ +uniform sampler2D u_texture5Sampler; + +uniform int u_texture5SizeX; +uniform int u_texture5SizeY; + +/** + * Used to en-/disable lighting. + */ +uniform bool u_useLight; + +/** + * Define the light intensity here. + */ +uniform float u_lightIntensity; + +/** + * Used to en-/disable blending of edges. + */ +uniform bool u_useEdges; + +/** + * Edge color to use + */ +uniform vec4 u_useEdgesColor; + +/** + * Step function border for blending in the edges. + */ +uniform float u_useEdgesStep; + +/** + * If true, the depth is blended in + */ +uniform bool u_useDepthCueing; + +/** + * Ratio between colormap and advected noise + */ +uniform float u_cmapRatio; + +/** + * How intensive should contrast enhancement be? + */ +uniform bool u_useHighContrast; + +varying vec3 v_normalizedVertex; + +/** + * Main. Clips and Blends the final image space rendering with the previously acquired 3D information + */ +void main() +{ + vec2 texCoord = gl_TexCoord[0].st; + float edge = texture2D( u_texture1Sampler, texCoord ).r * ( u_useEdges ? 1.0 : 0.0 ); + float noise = texture2D( u_texture1Sampler, texCoord ).b; + float light = texture2D( u_texture3Sampler, texCoord ).r * ( u_useLight ? 1.0 : 0.0 ); + float depth = texture2D( u_texture3Sampler, texCoord ).b; + float occupied = texture2D( u_texture3Sampler, texCoord ).a; + float advected1 = texture2D( u_texture0Sampler, texCoord ).r; + float advected2 = texture2D( u_texture0Sampler, texCoord ).g; + vec3 cmap = texture2D( u_texture2Sampler, texCoord ).rgb; + float evDiff = texture2D( u_texture4Sampler, texCoord ).r; + float fa = texture2D( u_texture4Sampler, texCoord ).g; + vec3 mesh = texture2D( u_texture5Sampler, texCoord ).rgb; + + + vec2 grad = getGradient( u_texture5Sampler, v_normalizedVertex.xy, 1.0 / u_texture5SizeX * 2 ); + vec3 normal = gl_NormalMatrix * vec3( grad, -1.0 ); + float phongBumplight = blinnPhongIlluminationIntensity( normalize( viewAlign( normal ) ) ); + vec3 outColorBump = vec3( phongBumplight * mesh ); + vec3 outColorRibbon = ( mesh.r + mesh.g ) * vec3( mesh.r * phongBumplight, mesh.g * phongBumplight, 0.0 ); + + // trimmings for beautifying image + //gl_FragColor *= 2.0*light; + + vec3 outColor = outColorRibbon; + float alpha = 1.0; + //outColor.r *= 0.05; + + gl_FragColor = vec4( outColor, alpha * occupied ); +} + diff --git a/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Postprocessing-vertex.glsl b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Postprocessing-vertex.glsl new file mode 100644 index 000000000..f2c4f5219 --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Postprocessing-vertex.glsl @@ -0,0 +1,43 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +#version 120 + +varying vec3 v_normalizedVertex; + +void main() +{ + // pass the color to the fragment shader + gl_FrontColor = gl_Color; + gl_BackColor = gl_Color; + + // pass tex coordinates + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; + + v_normalizedVertex = gl_TexCoord[0].xyz; + + // transform position + gl_Position = ftransform(); +} + diff --git a/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Transformation-fragment.glsl b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Transformation-fragment.glsl new file mode 100644 index 000000000..4f36b5ef1 --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Transformation-fragment.glsl @@ -0,0 +1,362 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +#version 120 + +#include "WGEColormapping-fragment.glsl" + +#include "WGEShadingTools.glsl" +#include "WGETextureTools.glsl" +#include "WGETransformationTools.glsl" +#include "WGEUtils.glsl" + +#include "WMImageSpaceTensorLIC-Transformation-varyings.glsl" + +/** + * The texture unit sampler: evec1 + */ +uniform sampler3D u_texture0Sampler; + +/** + * The texture unit sampler: evec2 + */ +uniform sampler3D u_texture1Sampler; + +/** + * The texture unit sampler: evals + */ +uniform sampler3D u_texture2Sampler; + +/** + * The texture unit sampler for the noise texture + */ +uniform sampler2D u_texture3Sampler; + +/** + * Scaling factor to unscale the texture + */ +uniform float u_texture0Scale = 1.0; + +/** + * Smallest possible value in the texture + */ +uniform float u_texture0Min = 0.0; + +/** + * Scaling factor to unscale the texture + */ +uniform float u_texture1Scale = 1.0; + +/** + * Smallest possible value in the texture + */ +uniform float u_texture1Min = 0.0; +/** + * Scaling factor to unscale the texture + */ +uniform float u_texture2Scale = 1.0; + +/** + * Smallest possible value in the texture + */ +uniform float u_texture2Min = 0.0; + +/** + * Size of input texture in pixels + */ +uniform int u_texture0SizeX = 255; + +/** + * Size of input texture in pixels + */ +uniform int u_texture0SizeY = 255; + +/** + * Size of input texture in pixels + */ +uniform int u_texture0SizeZ = 255; + +/** + * Size of input texture in pixels + */ +uniform int u_texture3SizeX = 255; + +/** + * Size of input texture in pixels + */ +uniform int u_texture3SizeY = 255; + +/** + * Projection angle cutoff + */ +uniform float u_projectionAngleThreshold; + +/** + * The "virtual" resolution of the noise texture in u_texture1Sampler + */ +uniform float u_noiseResoultuion = 3.0; + +/** + * Clip by FA + */ +uniform float u_clipFA = 0.01; + +// FA as used everywhere (Kondratieva et al 2005) +// computes FA from eigenvalues +float getFA( vec3 evalues ) +{ + float sqrt32 = sqrt(3./2.); // would make this const, if compiler let me + float I1 = evalues.x+evalues.y+evalues.z; + float mu = I1/3.; + vec3 deriv; + deriv.x = (evalues.x-mu); + deriv.y = (evalues.y-mu); + deriv.z = (evalues.z-mu); + float FA = sqrt32 * length(deriv)/length(evalues); + return FA; +} + +/** + * Transforms each vector on each pixel to image space. + */ +void main() +{ + vec2 noiseTexCoords = vec2( 0.0 ); + +#define CUBETEXTUREMAPPING_VARIANT2 +//#define CUBETEXTUREMAPPING_VARIANT1_A +#define CUBETEXTUREMAPPING_VARIANT1_B + +#ifdef CUBETEXTUREMAPPING_VARIANT1 + vec3 v = ( v_vertex.xyz ) - floor( v_vertex.xyz ); + vec3 normal = vec3( isZero( v_normalObject.x, 0.00001 ) ? 0.00001 : v_normalObject.x, + isZero( v_normalObject.y, 0.00001 ) ? 0.00001 : v_normalObject.y, + isZero( v_normalObject.z, 0.00001 ) ? 0.00001 : v_normalObject.z ); + + // find nearest cube planes in direction of the normal + int nearestPlane = 0; + float smallestD = 1e10; + vec3 cubeBase = vec3( 0.0 );//cubeBaseX, cubeBaseY, cubeBaseZ); + +#ifdef CUBETEXTUREMAPPING_VARIANT1_A + // try each of the 6 planes and find nearest (positive) hit + for( int axis=0; axis<3; axis++ ) + { + // search the n in : vertex[axis]+n*_normal[axis] = 1.0 | 0.0 + float n1 = ( 1.0 - v[axis] ) / v_normalObject[axis]; + float n2 = ( - v[axis] ) / v_normalObject[axis]; + + // NOTE this should also handle the case where the vertex is directly on the cube -> n1=n2=~0 + + // smaller than currently found one? + if( abs( n1 ) < abs( smallestD ) ) + { + smallestD = n1; + nearestPlane = axis; + } + else if( abs( n2 ) < abs( smallestD ) ) + { + smallestD = n2; + nearestPlane = axis; + } + } +#endif + +#ifdef CUBETEXTUREMAPPING_VARIANT1_B + // try each of the 6 planes and find nearest (positive) hit + for( int axis=0; axis<3; axis++ ) + { + float d1 = v[axis]; + float d2 = 1.0 - v[axis]; + + // NOTE this should also handle the case where the vertex is directly on the cube -> d1=d2=~0 + + // just take the smaller one + float d = min( d1, d2 ); + + // smaller than currently found one? + if ( d < smallestD ) + { + smallestD = d; + nearestPlane = axis; + } + } +#endif + + // calculate hit point on cube + // NOTE the hit will be in interval [0,1] + vec3 hit = v.xyz + ( smallestD * normal.xyz ) - floor( v.xyz ); + + /* Assume the following border configuration for our cube tile set (same letters - same border) + FIXME rotate image 90 degree anti clockwise since the texture is stored this way + _______________ _______________ + | BBBBBBBBBBBBB | | CCCCCCCCCCCCC | + |A A| |A A| + |A A| |A A| + |A Tile0 A| |A Tile1 A| + |A A| |A A| + |A A| |A A| + |A A| |A A| + |_BBBBBBBBBBBBB_| |_CCCCCCCCCCCCC_| + _______________ + | BBBBBBBBBBBBB | + |C C| + |C C| + |C Tile2 C| + |C C| + |C C| + |C C| + |_BBBBBBBBBBBBB_| + */ + if( nearestPlane == 0 ) + { + noiseTexCoords = vec2( hit.y, hit.z ); + } + else if( nearestPlane == 1 ) + { + noiseTexCoords = vec2( hit.x, hit.z ); + } + else + { + noiseTexCoords = vec2( hit.x, hit.y ); + } + +#endif + +#ifdef CUBETEXTUREMAPPING_VARIANT2 + vec3 v = v_vertex.xyz;// - floor( v_vertex.xyz ); + float scaler = ( u_noiseResoultuion / 100.0 ); + v*=scaler; + if( abs( v_normalObject.x ) == max( abs( v_normalObject.x ), max( abs( v_normalObject.y ), abs( v_normalObject.z ) ) ) ) + { + noiseTexCoords = vec2( v.y, v.z ); + } + else if( abs( v_normalObject.y ) == max( abs( v_normalObject.x ), max( abs( v_normalObject.y ), abs( v_normalObject.z ) ) ) ) + { + noiseTexCoords = vec2( v.x, v.z ); + } + else if( abs( v_normalObject.z ) == max( abs( v_normalObject.x ), max( abs( v_normalObject.y ), abs ( v_normalObject.z ) ) ) ) + { + noiseTexCoords = vec2( v.x, v.y ); + } +#endif + +#ifdef CUBETEXTUREMAPPING_VARIANT3 + float scaler = 10.0 / u_noiseResoultuion ; + noiseTexCoords = vec2( scaler * gl_FragCoord.x / u_texture3SizeX, + scaler * gl_FragCoord.y / u_texture3SizeY ); +#endif + + // if we have a 3D noise texture, use it. + float noise = texture2D( u_texture3Sampler, noiseTexCoords.xy ).r; + + // get the current vector at this position + vec3 evec1 = normalize( texture3DUnscaled( u_texture0Sampler, gl_TexCoord[0].xyz, u_texture0Min, u_texture0Scale ).rgb ); + vec3 evec2 = normalize( texture3DUnscaled( u_texture1Sampler, gl_TexCoord[1].xyz, u_texture1Min, u_texture1Scale ).rgb ); + evec1 *= sign( evec1.x ); + evec2 *= sign( evec2.x ); + + vec3 evals = 1000. * texture3DUnscaled( u_texture2Sampler, gl_TexCoord[2].xyz, u_texture2Min, u_texture2Scale ).rgb; + //evec1 *= evals.r; + //evec2 *= evals.g; + float fa = getFA( evals ); + + // zero length vectors are uninteresting. discard them + if( isZero( evals.r, 0.01 ) || + isZero( evals.g, 0.01 ) ) + { + discard; + } + if( fa < u_clipFA ) + { + discard; + } + // project the vectors to image space as the input vector is in the tangent space + vec2 evec1Projected = normalize( projectVector( evec1 ).xy ); + vec2 evec2Projected = normalize( projectVector( evec2 ).xy ); + + // calculate lighting for the surface + float light = blinnPhongIlluminationIntensity( normalize( v_normal ) ); + + // MPI PAper Hack: { + // vec4 cmap = colormapping(); + // gl_FragData[1] = vec4( vec3( cmap.r ), 1.0 ); + // + // if( cmap.r < 0.15 ) + // discard; + // if( isZero( cmap.r - 0.2, 0.1 ) ) + // gl_FragData[1] = vec4( 0.25, 0.0, 0.0, 1.0 ); + // if( isZero( cmap.r - 0.3, 0.1 ) ) + // gl_FragData[1] = vec4( 0.5, 0.0, 0.0, 1.0 ); + // if( isZero( cmap.r - 1.0, 0.15 ) ) + // gl_FragData[1] = vec4( 1.0, 0.0, 0.0, 1.0 ); + // } + + vec4 cmap = colormapping(); + + // this is an example for avoiding certain pixels from beeing LIC'd + // if(( cmap.r > 0.3 ) && ( cmap.g > 0.3 ) && ( cmap.b > 0.3 ) ) + // discard; + + const float piHalf = 3.14159265 / 2.0; + const float pi = 3.14159265; + + // is the vector very orthogonal to the surface? We scale our advection according to this. We use the angle between normal and vector but use + // 1 - dot to get the angle between vector and surface which is 90 degree shifted against the dot of the normal and the vector. + float geometryVecAngle = ( acos( + abs( + dot( normalize( v_normalObject ), + normalize( evec1.xyz ) + ) + ) + ) / piHalf + ); + // we measured the angle between normal and vector, but we want the angle between surface tangent and vector, which is a shift of half PI / + // halfPi = 1 + geometryVecAngle = 1.0 - geometryVecAngle; + + // the user defines an angle in degrees used as cutoff value. Angles above this one should be clipped + float cutoffAngle = u_projectionAngleThreshold / 90.0; + + // scale down the vector -> the more it "comes out of the surface, the shorter the vector". + float dotScale = cutoffAngle - geometryVecAngle; + if( dotScale < 0 ) + { + dotScale = 0; + } + else + { + dotScale = 1.0; + } + + // scale our vector according to the above metric and output + vec2 dotScaledVector1 = dotScale * scaleMaxToOne( evec1Projected ).xy; + vec2 dotScaledVector2 = dotScale * scaleMaxToOne( evec2Projected ).xy; + gl_FragData[0] = vec4( vec2( 0.5 ) + ( 0.5 * dotScaledVector1 ), vec2( 0.5 ) + ( 0.5 * dotScaledVector2 ) ); + gl_FragData[1] = vec4( light, noise, gl_FragCoord.z, 1.0 ); + gl_FragData[2] = vec4( abs( evals.r - evals.g ), fa, 0.0, 1.0 ); + gl_FragData[3] = cmap; + +} + diff --git a/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Transformation-varyings.glsl b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Transformation-varyings.glsl new file mode 100644 index 000000000..5c604f040 --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Transformation-varyings.glsl @@ -0,0 +1,59 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +/** + * The normal interpolated + */ +varying vec3 v_normal; + +/** + * The vertex + */ +varying vec3 v_vertex; + +/** + * Normal in object space + */ +varying vec3 v_normalObject; + +/** + * The normal interpolated and projected to screenspace + */ +varying vec3 v_normalProjected; + +/** + * The light source in local coordinates + */ +varying vec3 v_lightSource; + +/** + * The light source in local coordinates + */ +varying vec3 v_viewDir; + +/** + * The factor which scales the 3d noise texture to a proper size according to screen size. + */ +varying vec3 v_noiseScaleFactor; + diff --git a/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Transformation-vertex.glsl b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Transformation-vertex.glsl new file mode 100644 index 000000000..666461ae2 --- /dev/null +++ b/src/modules/imageSpaceTensorLIC/shaders/WMImageSpaceTensorLIC-Transformation-vertex.glsl @@ -0,0 +1,130 @@ +//--------------------------------------------------------------------------- +// +// 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 . +// +//--------------------------------------------------------------------------- + +#version 120 + +#include "WGEColormapping-vertex.glsl" + +#include "WGETransformationTools.glsl" + +#include "WMImageSpaceTensorLIC-Transformation-varyings.glsl" + +/** + * How much should the slice be moved along u_vertexShiftDirection? + */ +uniform int u_vertexShift = 0; + +/** + * The direction along which the slice gets moved + */ +uniform vec3 u_vertexShiftDirection = vec3( 0.0, 0.0, 0.0 ); + +/** + * Size of input texture in pixels + */ +uniform int u_texture0SizeX = 255; + +/** + * Size of input texture in pixels + */ +uniform int u_texture0SizeY = 255; + +/** + * Size of input texture in pixels + */ +uniform int u_texture0SizeZ = 255; + +/** + * Size of input noise texture in pixels + */ +uniform int u_texture1SizeX = 255; + +/** + * Size of input noise texture in pixels + */ +uniform int u_texture1SizeY = 255; + +/** + * Size of input noise texture in pixels + */ +uniform int u_texture1SizeZ = 255; + +/** + * Vertex Main. Simply transforms the geometry. The work is done per fragment. + */ +void main() +{ + // Calculate the real vertex coordinate in openwalnut-scene-space + vec4 vertex = gl_Vertex; +#ifdef VERTEXSHIFT_ENABLED + // Calculate the real vertex coordinate in openwalnut-scene-space + vertex = ( vec4( u_vertexShiftDirection.xyz, 0.0 ) * u_vertexShift ) + gl_Vertex; +#endif + + // Allow the colormapper to do some precalculations with the real vertex coordinate in ow-scene-space + colormapping( vertex ); + + // for easy access to texture coordinates + // NOTE: The vertex is specified in ow-scene-space. The texture matrix was set by WGEDataTexture for the dataset and transforms the vertex in + // ow-scene-space to the textures space. + gl_TexCoord[0] = gl_TextureMatrix[0] * vertex; + gl_TexCoord[1] = gl_TextureMatrix[1] * vertex; + gl_TexCoord[2] = gl_TextureMatrix[2] * vertex; + gl_TexCoord[3] = gl_TextureMatrix[3] * vertex; + + // some light precalculations + v_normal = gl_NormalMatrix * gl_Normal; + v_normalObject = gl_Normal; + v_vertex = gl_Vertex.xyz; + + /* + // NOTE: we normalize the vec here although we need to normalize it again in the fragment shader since the projected vector might be very + // small and we want to avoid numerical issues when interpolating. + v_normalProjected = normalize( projectVector( vec4( v_normal, 0.0 ) ) ); + + // if we use 3d noise textures and auto resolution feature: + vec4 vec1 = vec4( float( u_texture0SizeX ) / float( u_texture1SizeX ), + float( u_texture0SizeY ) / float( u_texture1SizeY ), + float( u_texture0SizeZ ) / float( u_texture1SizeZ ), 0.0 ); + v_noiseScaleFactor = vec1.xyz * u_noiseResoultuion; +#ifdef NOISE3DAUTORES_ENABLED + vec4 vecMV = gl_ModelViewMatrix * vec4( vec3( 1.0 ), 0.0 ); // if the resolution should be modified, use the scaling info from the MV matrix + v_noiseScaleFactor *= u_noiseResoultuion * length( vecMV.xyz ); +#endif +*/ + + // also get the coordinates of the light + vec4 lpos = gl_LightSource[0].position; // this simply doesn't work well with OSG + lpos = vec4( 0.0, 0.0, 1000.0, 1.0 ); + v_lightSource = worldToLocal( lpos ).xyz; + + // transform the view direction to texture space, which equals object space + // Therefore use two points, as we transform a vector + vec4 camPos = vec4( 0.0, 0.0, -1.0, 0.0 ); + v_viewDir = worldToLocal( camPos ).xyz; + + // transform position + gl_Position = gl_ModelViewProjectionMatrix * vertex; +} + diff --git a/src/modules/modules-others.toolbox b/src/modules/modules-others.toolbox index ad913d397..74ecda0ea 100644 --- a/src/modules/modules-others.toolbox +++ b/src/modules/modules-others.toolbox @@ -28,6 +28,7 @@ ADD_MODULE( functionalMRIViewer ) ADD_MODULE( hierarchicalClustering ) ADD_MODULE( histogramView ) ADD_MODULE( imageExtractor ) +ADD_MODULE( imageSpaceTensorLIC ) ADD_MODULE( mergeComponentsToVector ) ADD_MODULE( mergePoints ) ADD_MODULE( meshToPoints ) -- GitLab