Commit 09ca7b89 authored by Mario Hlawitschka's avatar Mario Hlawitschka
Browse files

[CHANGE] removed code that is no longer needed that referred to the old way...

[CHANGE] removed code that is no longer needed that referred to the old way transfer functions are handled and did not work anymore due to the new transfer function infrastructure.
parent 2f0f6fd4
......@@ -50,233 +50,180 @@
#include "WMDirectVolumeRendering.xpm"
#include "WMDirectVolumeRendering.h"
// This line is needed by the module loader to actually find your module.
W_LOADABLE_MODULE( WMDirectVolumeRendering )
WMDirectVolumeRendering::WMDirectVolumeRendering():
WModule()
{
// Initialize members
}
WMDirectVolumeRendering::~WMDirectVolumeRendering()
{
// Cleanup!
}
boost::shared_ptr< WModule > WMDirectVolumeRendering::factory() const
{
return boost::shared_ptr< WModule >( new WMDirectVolumeRendering() );
}
const char** WMDirectVolumeRendering::getXPMIcon() const
{
return WMDirectVolumeRendering_xpm;
}
const std::string WMDirectVolumeRendering::getName() const
{
// Specify your module name here. This name must be UNIQUE!
return "Direct Volume Rendering";
}
const std::string WMDirectVolumeRendering::getDescription() const
{
// Specify your module description here. Be detailed. This text is read by the user.
return "Direct volume rendering of regular volumetric data.";
}
void WMDirectVolumeRendering::connectors()
{
// The transfer function for our DVR
m_transferFunction = WModuleInputData< WDataSetSingle >::createAndAdd( shared_from_this(), "transfer function", "The 1D transfer function." );
// DVR needs one input: the scalar dataset
m_input = WModuleInputData< WDataSetScalar >::createAndAdd( shared_from_this(), "in", "The scalar dataset." );
// Optional: the gradient field
m_gradients = WModuleInputData< WDataSetVector >::createAndAdd( shared_from_this(),
"gradients", "The gradient field of the dataset to display" );
// call WModules initialization
WModule::connectors();
}
void WMDirectVolumeRendering::properties()
{
// Initialize the properties
m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );
m_samples = m_properties->addProperty( "Sample count", "The number of samples to walk along the ray during raycasting. A low value "
"may cause artifacts whilst a high value slows down rendering.", 256 );
m_samples->setMin( 1 );
m_samples->setMax( 5000 );
// illumination model
m_localIlluminationSelections = boost::shared_ptr< WItemSelection >( new WItemSelection() );
m_localIlluminationSelections->addItem( "No Local Illumination", "Volume Renderer only uses the classified voxel color." );
m_localIlluminationSelections->addItem( "Blinn-Phong", "Blinn-Phong lighting is used for shading each classified voxel." );
m_localIlluminationAlgo = m_properties->addProperty( "Local illumination model", "The illumination algorithm to use.",
m_localIlluminationSelections->getSelectorFirst(), m_propCondition );
WPropertyHelper::PC_SELECTONLYONE::addTo( m_localIlluminationAlgo );
WPropertyHelper::PC_NOTEMPTY::addTo( m_localIlluminationAlgo );
// transfer functions
m_tfLoaderGroup = m_properties->addPropertyGroup( "Transfer function", "Transfer function loading." );
m_tfLoaderEnabled = m_tfLoaderGroup->addProperty( "Enable", "Enable TF loading from file.", false, m_propCondition );
m_tfLoaderFile = m_tfLoaderGroup->addProperty( "File", "The 1D image containing the transfer function.",
WPathHelper::getAppPath(), m_propCondition );
WPropertyHelper::PC_PATHEXISTS::addTo( m_tfLoaderFile );
m_tfLoaderTrigger = m_tfLoaderGroup->addProperty( "Load", "Triggers loading.", WPVBaseTypes::PV_TRIGGER_READY, m_propCondition );
// additional artifact removal methods
m_improvementGroup = m_properties->addPropertyGroup( "Improvements", "Methods for improving image quality. Most of these methods imply "
"additional calculation/texture overhead and therefore slow down rendering." );
m_stochasticJitterEnabled = m_improvementGroup->addProperty( "Stochastic jitter", "With stochastic jitter, wood-grain artifacts can be "
"removed with the cost of possible noise artifacts.", true,
m_propCondition );
m_opacityCorrectionEnabled = m_improvementGroup->addProperty( "Opacity correction", "If enabled, opacities are assumed to be relative to the "
"sample count. If disabled, changing the sample count "
"varies brightness of the image.", true,
m_propCondition );
m_maximumIntensityProjectionEnabled = m_improvementGroup->addProperty( "MIP", "If enabled, MIP is used.", true,
m_propCondition );
m_depthProjectionEnabled = m_improvementGroup->addProperty( "Depth Projection", "If enabled, depth projection mode is used", true,
m_propCondition );
WModule::properties();
}
void WMDirectVolumeRendering::requirements()
{
m_requirements.push_back( new WGERequirement() );
}
/**
* Generates a white noise texture with given resolution.
*
* \param resX the resolution
*
* \return a image with resX*resX resolution.
*/
osg::ref_ptr< osg::Image > genWhiteNoise( size_t resX )
{
std::srand( time( 0 ) );
osg::ref_ptr< osg::Image > randImage = new osg::Image();
randImage->allocateImage( resX, resX, 1, GL_LUMINANCE, GL_UNSIGNED_BYTE );
unsigned char *randomLuminance = randImage->data(); // should be 4 megs
for( unsigned int x = 0; x < resX; x++ )
{
for( unsigned int y = 0; y < resX; y++ )
{
// - stylechecker says "use rand_r" but I am not sure about portability.
unsigned char r = ( unsigned char )( std::rand() % 255 ); // NOLINT
randomLuminance[ ( y * resX ) + x ] = r;
}
}
return randImage;
}
/**
* Example TF generator. This will be extended with some strategy-pattern later.
*
* \return TF as image.
*/
osg::ref_ptr< osg::Image > genTF()
{
const size_t resX = 256;
osg::ref_ptr< osg::Image > tfImage = new osg::Image();
tfImage->allocateImage( resX, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE );
unsigned char *tf = tfImage->data();
for( size_t x = 0; x < resX; ++x )
{
if( x > 127 )
{
double i = ( static_cast< double >( x - 128 ) / 128.0 ) * 2.0 * 15.0;
size_t imod = fmod( i, 2 );
std::cout << imod << std::endl;
if( imod == 0 )
{
tf[ 4 * x + 0 ] = 255;
tf[ 4 * x + 1 ] = 86;
tf[ 4 * x + 2 ] = 86;
tf[ 4 * x + 3 ] = 127;
}
else
{
tf[ 4 * x + 0 ] = 255;
tf[ 4 * x + 1 ] = 191;
tf[ 4 * x + 2 ] = 0;
tf[ 4 * x + 3 ] = 64;
}
}
if( x <= 127 )
{
tf[ 4 * x + 0 ] = 0;
tf[ 4 * x + 1 ] = 94;
tf[ 4 * x + 2 ] = 255;
tf[ 4 * x + 3 ] = 2 * ( 127 - x );
}
}
return tfImage;
}
void WMDirectVolumeRendering::moduleMain()
{
m_shader = osg::ref_ptr< WGEShader > ( new WGEShader( "WMDirectVolumeRendering", m_localPath ) );
// setup all the defines needed
// local illumination model
WGEShaderDefineOptions::SPtr illuminationAlgoDefines = WGEShaderDefineOptions::SPtr(
new WGEShaderDefineOptions( "LOCALILLUMINATION_NONE", "LOCALILLUMINATION_PHONG" )
);
m_shader->addPreprocessor( illuminationAlgoDefines );
// gradient texture settings
WGEShaderDefine< std::string >::SPtr gradTexSamplerDefine = m_shader->setDefine( "GRADIENTTEXTURE_SAMPLER", std::string( "tex1" ) );
WGEShaderDefineSwitch::SPtr gradTexEnableDefine = m_shader->setDefine( "GRADIENTTEXTURE_ENABLED" );
// transfer function texture settings
WGEShaderDefine< std::string >::SPtr tfTexSamplerDefine = m_shader->setDefine( "TRANSFERFUNCTION_SAMPLER", std::string( "tex2" ) );
WGEShaderDefineSwitch::SPtr tfTexEnableDefine = m_shader->setDefine( "TRANSFERFUNCTION_ENABLED" );
// jitter
WGEShaderDefine< std::string >::SPtr jitterSamplerDefine = m_shader->setDefine( "JITTERTEXTURE_SAMPLER", std::string( "tex3" ) );
WGEShaderDefine< int >::SPtr jitterSizeXDefine = m_shader->setDefine( "JITTERTEXTURE_SIZEX", 0 );
WGEShaderDefineSwitch::SPtr jitterEnableDefine = m_shader->setDefine( "JITTERTEXTURE_ENABLED" );
// opacity correction enabled?
WGEShaderDefineSwitch::SPtr opacityCorrectionEnableDefine = m_shader->setDefine( "OPACITYCORRECTION_ENABLED" );
WGEShaderDefineSwitch::SPtr maximumIntensityProjectionEnabledDefine = m_shader->setDefine( "MIP_ENABLED" );
WGEShaderDefineSwitch::SPtr depthProjectionEnabledDefine = m_shader->setDefine( "DEPTH_PROJECTION_ENABLED" );
// let the main loop awake if the data changes or the properties changed.
m_moduleState.setResetable( true, true );
m_moduleState.add( m_transferFunction->getDataChangedCondition() );
m_moduleState.add( m_input->getDataChangedCondition() );
m_moduleState.add( m_gradients->getDataChangedCondition() );
m_moduleState.add( m_propCondition );
// Signal ready state.
ready();
debugLog() << "Module is now ready.";
osg::ref_ptr< WGEManagedGroupNode > rootNode = new WGEManagedGroupNode( m_active );
bool rootInserted = false;
// Normally, you will have a loop which runs as long as the module should not shutdown. In this loop you can react on changing data on input
// connectors or on changed in your properties.
// This line is needed by the module loader to actually find your module.
W_LOADABLE_MODULE( WMDirectVolumeRendering )
WMDirectVolumeRendering::WMDirectVolumeRendering():
WModule()
{
// Initialize members
}
WMDirectVolumeRendering::~WMDirectVolumeRendering()
{
// Cleanup!
}
boost::shared_ptr< WModule > WMDirectVolumeRendering::factory() const
{
return boost::shared_ptr< WModule >( new WMDirectVolumeRendering() );
}
const char** WMDirectVolumeRendering::getXPMIcon() const
{
return WMDirectVolumeRendering_xpm;
}
const std::string WMDirectVolumeRendering::getName() const
{
// Specify your module name here. This name must be UNIQUE!
return "Direct Volume Rendering";
}
const std::string WMDirectVolumeRendering::getDescription() const
{
// Specify your module description here. Be detailed. This text is read by the user.
return "Direct volume rendering of regular volumetric data.";
}
void WMDirectVolumeRendering::connectors()
{
// The transfer function for our DVR
m_transferFunction = WModuleInputData< WDataSetSingle >::createAndAdd( shared_from_this(), "transfer function", "The 1D transfer function." );
// DVR needs one input: the scalar dataset
m_input = WModuleInputData< WDataSetScalar >::createAndAdd( shared_from_this(), "in", "The scalar dataset." );
// Optional: the gradient field
m_gradients = WModuleInputData< WDataSetVector >::createAndAdd( shared_from_this(),
"gradients", "The gradient field of the dataset to display" );
// call WModules initialization
WModule::connectors();
}
void WMDirectVolumeRendering::properties()
{
// Initialize the properties
m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );
m_samples = m_properties->addProperty( "Sample count", "The number of samples to walk along the ray during raycasting. A low value "
"may cause artifacts whilst a high value slows down rendering.", 256 );
m_samples->setMin( 1 );
m_samples->setMax( 5000 );
// illumination model
m_localIlluminationSelections = boost::shared_ptr< WItemSelection >( new WItemSelection() );
m_localIlluminationSelections->addItem( "No Local Illumination", "Volume Renderer only uses the classified voxel color." );
m_localIlluminationSelections->addItem( "Blinn-Phong", "Blinn-Phong lighting is used for shading each classified voxel." );
m_localIlluminationAlgo = m_properties->addProperty( "Local illumination model", "The illumination algorithm to use.",
m_localIlluminationSelections->getSelectorFirst(), m_propCondition );
WPropertyHelper::PC_SELECTONLYONE::addTo( m_localIlluminationAlgo );
WPropertyHelper::PC_NOTEMPTY::addTo( m_localIlluminationAlgo );
// additional artifact removal methods
m_improvementGroup = m_properties->addPropertyGroup( "Improvements", "Methods for improving image quality. Most of these methods imply "
"additional calculation/texture overhead and therefore slow down rendering." );
m_stochasticJitterEnabled = m_improvementGroup->addProperty( "Stochastic jitter", "With stochastic jitter, wood-grain artifacts can be "
"removed with the cost of possible noise artifacts.", true,
m_propCondition );
m_opacityCorrectionEnabled = m_improvementGroup->addProperty( "Opacity correction", "If enabled, opacities are assumed to be relative to the "
"sample count. If disabled, changing the sample count "
"varies brightness of the image.", true,
m_propCondition );
m_maximumIntensityProjectionEnabled = m_improvementGroup->addProperty( "MIP", "If enabled, MIP is used.", false,
m_propCondition );
m_depthProjectionEnabled = m_improvementGroup->addProperty( "Depth Projection", "If enabled, depth projection mode is used", false,
m_propCondition );
WModule::properties();
}
void WMDirectVolumeRendering::requirements()
{
m_requirements.push_back( new WGERequirement() );
}
/**
* Generates a white noise texture with given resolution.
*
* \param resX the resolution
*
* \return a image with resX*resX resolution.
*/
osg::ref_ptr< osg::Image > genWhiteNoise( size_t resX )
{
std::srand( time( 0 ) );
osg::ref_ptr< osg::Image > randImage = new osg::Image();
randImage->allocateImage( resX, resX, 1, GL_LUMINANCE, GL_UNSIGNED_BYTE );
unsigned char *randomLuminance = randImage->data(); // should be 4 megs
for( unsigned int x = 0; x < resX; x++ )
{
for( unsigned int y = 0; y < resX; y++ )
{
// - stylechecker says "use rand_r" but I am not sure about portability.
unsigned char r = ( unsigned char )( std::rand() % 255 ); // NOLINT
randomLuminance[ ( y * resX ) + x ] = r;
}
}
return randImage;
}
void WMDirectVolumeRendering::moduleMain()
{
m_shader = osg::ref_ptr< WGEShader > ( new WGEShader( "WMDirectVolumeRendering", m_localPath ) );
// setup all the defines needed
// local illumination model
WGEShaderDefineOptions::SPtr illuminationAlgoDefines = WGEShaderDefineOptions::SPtr(
new WGEShaderDefineOptions( "LOCALILLUMINATION_NONE", "LOCALILLUMINATION_PHONG" )
);
m_shader->addPreprocessor( illuminationAlgoDefines );
// gradient texture settings
WGEShaderDefine< std::string >::SPtr gradTexSamplerDefine = m_shader->setDefine( "GRADIENTTEXTURE_SAMPLER", std::string( "tex1" ) );
WGEShaderDefineSwitch::SPtr gradTexEnableDefine = m_shader->setDefine( "GRADIENTTEXTURE_ENABLED" );
// transfer function texture settings
WGEShaderDefine< std::string >::SPtr tfTexSamplerDefine = m_shader->setDefine( "TRANSFERFUNCTION_SAMPLER", std::string( "tex2" ) );
WGEShaderDefineSwitch::SPtr tfTexEnableDefine = m_shader->setDefine( "TRANSFERFUNCTION_ENABLED" );
// jitter
WGEShaderDefine< std::string >::SPtr jitterSamplerDefine = m_shader->setDefine( "JITTERTEXTURE_SAMPLER", std::string( "tex3" ) );
WGEShaderDefine< int >::SPtr jitterSizeXDefine = m_shader->setDefine( "JITTERTEXTURE_SIZEX", 0 );
WGEShaderDefineSwitch::SPtr jitterEnableDefine = m_shader->setDefine( "JITTERTEXTURE_ENABLED" );
// opacity correction enabled?
WGEShaderDefineSwitch::SPtr opacityCorrectionEnableDefine = m_shader->setDefine( "OPACITYCORRECTION_ENABLED" );
WGEShaderDefineSwitch::SPtr maximumIntensityProjectionEnabledDefine = m_shader->setDefine( "MIP_ENABLED" );
WGEShaderDefineSwitch::SPtr depthProjectionEnabledDefine = m_shader->setDefine( "DEPTH_PROJECTION_ENABLED" );
// let the main loop awake if the data changes or the properties changed.
m_moduleState.setResetable( true, true );
m_moduleState.add( m_transferFunction->getDataChangedCondition() );
m_moduleState.add( m_input->getDataChangedCondition() );
m_moduleState.add( m_gradients->getDataChangedCondition() );
m_moduleState.add( m_propCondition );
// Signal ready state.
ready();
debugLog() << "Module is now ready.";
osg::ref_ptr< WGEManagedGroupNode > rootNode = new WGEManagedGroupNode( m_active );
bool rootInserted = false;
// Normally, you will have a loop which runs as long as the module should not shutdown. In this loop you can react on changing data on input
// connectors or on changed in your properties.
debugLog() << "Entering main loop";
while( !m_shutdownFlag() )
{
......@@ -295,9 +242,8 @@
bool dataUpdated = m_input->updated() || m_gradients->updated();
boost::shared_ptr< WDataSetScalar > dataSet = m_input->getData();
bool dataValid = ( dataSet );
bool propUpdated = m_localIlluminationAlgo->changed() || m_tfLoaderEnabled || m_tfLoaderFile->changed() || m_tfLoaderTrigger->changed() ||
m_stochasticJitterEnabled->changed() || m_opacityCorrectionEnabled->changed() ||
m_maximumIntensityProjectionEnabled->changed() || m_depthProjectionEnabled->changed();
bool propUpdated = m_localIlluminationAlgo->changed() || m_stochasticJitterEnabled->changed() || m_opacityCorrectionEnabled->changed() ||
m_maximumIntensityProjectionEnabled->changed() || m_depthProjectionEnabled->changed();
// reset module in case of invalid data. This accounts only for the scalar field input
......@@ -329,7 +275,7 @@
WPosition( grid->getNbCoordsX() - 1, grid->getNbCoordsY() - 1, grid->getNbCoordsZ() - 1 ) );
osg::ref_ptr< osg::Node > cube = wge::generateSolidBoundingBoxNode( bb, WColor( 1.0, 1.0, 1.0, 1.0 ) );
cube->asTransform()->getChild( 0 )->setName( "_DVR Proxy Cube" ); // Be aware that this name is used in the pick handler.
// because of the underscore in front it won't be picked
// because of the underscore in front it won't be picked
// we also set the grid's transformation here
rootNode->setMatrix( static_cast< WMatrix4d >( grid->getTransform() ) );
......@@ -407,7 +353,7 @@
osg::ref_ptr< osg::Image > tfImg( new osg::Image() );
//debugLog() << "set image";
tfImg->setImage( tfsize/4, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE,
data, osg::Image::USE_NEW_DELETE ); // FIXME: check allocation mode
data, osg::Image::USE_NEW_DELETE ); // FIXME: check allocation mode
//debugLog() << "activate";
tfTexEnableDefine->setActive( false );
osg::ref_ptr< osg::Texture1D > tfTexture = new osg::Texture1D();
......@@ -420,28 +366,6 @@
}
debugLog() << "end updated transfer function";
}
// // Disabled for debugging transfer function code. (mario)
// // try to load the tf from file if existent
// tfTexEnableDefine->setActive( false );
// if( m_tfLoaderEnabled->get( true ) )
// {
// osg::ref_ptr< osg::Image > tfImg = osgDB::readImageFile( m_tfLoaderFile->get( true ).file_string() );
// if( tfImg )
// {
// // bind it as a texture
// osg::ref_ptr< osg::Texture1D > tfTexture = new osg::Texture1D();
// tfTexture->setImage( tfImg );
// // apply it
// wge::bindTexture( cube, tfTexture, 2, "u_transferFunction" );
// tfTexEnableDefine->setActive( true ); // enable it
// }
// else
// {
// warnLog() << "Transfer function texture could not be loaded from " << m_tfLoaderFile->get( true ).file_string() << ".";
// }
// m_tfLoaderTrigger->get( true );
// }
////////////////////////////////////////////////////////////////////////////////////////////////////
// stochastic jittering texture
......@@ -502,8 +426,6 @@
depthProjectionEnabledDefine->setActive( false );
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// setup all those uniforms
////////////////////////////////////////////////////////////////////////////////////////////////////
......@@ -524,9 +446,6 @@
rootInserted = true;
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( rootNode );
}
// finally, reset the load trigger
m_tfLoaderTrigger->set( WPVBaseTypes::PV_TRIGGER_READY );
}
}
......
......@@ -141,26 +141,6 @@ private:
*/
WPropSelection m_localIlluminationAlgo;
/**
* The group containing the tf loader path and trigger.
*/
WPropGroup m_tfLoaderGroup;
/**
* If true, the texture is used for transfer functions.
*/
WPropBool m_tfLoaderEnabled;
/**
* The path to the file to load.
*/
WPropFilename m_tfLoaderFile;
/**
* Triggered to actually do loading
*/
WPropTrigger m_tfLoaderTrigger;
/**
* All properties for those nice improvement methods.
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment