Commit 0aca3abe authored by André Reichenbach's avatar André Reichenbach
Browse files

[ADD] first version of a 3d turing noise texture generation function

parent bd76ae76
......@@ -22,6 +22,11 @@
//
//---------------------------------------------------------------------------
#include <algorithm>
#include <vector>
#include <boost/random.hpp>
#include "../common/exceptions/WPreconditionNotMet.h"
#include "WGETexture.h"
......@@ -114,3 +119,140 @@ osg::ref_ptr< osg::Image > wge::genWhiteNoiseImage( size_t sizeX, size_t sizeY,
return randImage;
}
osg::ref_ptr< WGETexture< osg::Texture3D > > wge::genTuringNoiseTexture( std::size_t sizeX, std::size_t sizeY,
std::size_t sizeZ, std::size_t channels )
{
WPrecond( channels == 1 || channels == 3 || channels == 4, "Invalid number of channels. Valid are: 1, 3 and 4." );
// some constants, maybe change to parameters
float const spotIrregularity = 0.05f; // 0.0 - 1.0
std::size_t const iterations = 200;
float const spotSize = 0.5;
float const spotFactor = ( 0.02f + 0.58f * ( 1.0f - spotSize ) ) / 15.0f;
float const d1 = 0.125f;
float const d2 = 0.03125f;
float const speed = 1.0f;
osg::ref_ptr< osg::Image > img = new osg::Image;
GLenum type = GL_LUMINANCE;
if( channels == 3 )
{
type = GL_RGB;
}
else if( channels == 4 )
{
type = GL_RGBA;
}
std::vector< float > concentration1( sizeX * sizeY * sizeZ, 4.0 );
std::vector< float > concentration2( sizeX * sizeY * sizeZ, 4.0 );
std::vector< float > delta1( sizeX * sizeY * sizeZ, 0.0 );
std::vector< float > delta2( sizeX * sizeY * sizeZ, 0.0 );
std::vector< float > noise( sizeX * sizeY * sizeZ );
boost::mt19937 generator( std::time( 0 ) );
float noiseRange = 0.1f + 4.9f * spotIrregularity;
boost::uniform_real< float > dist( 12.0 - noiseRange, 12.0 + noiseRange );
boost::variate_generator< boost::mt19937&, boost::uniform_real< float > > rand( generator, dist );
// initialization step
for( std::size_t i = 0; i < sizeX; ++i )
{
for( std::size_t j = 0; j < sizeY; ++j )
{
for( std::size_t k = 0; k < sizeZ; ++k )
{
std::size_t idx = i + j * sizeX + k * sizeX * sizeY;
noise[ idx ] = rand();
}
}
}
// iteration
for( std::size_t iter = 0; iter < iterations; ++iter )
{
std::cout << "iterations: " << iter << std::endl;
for( std::size_t i = 0; i < sizeX; ++i )
{
std::size_t iNext = ( i + 1 ) % sizeX;
std::size_t iPrev = ( i + sizeX - 1 ) % sizeX;
for( std::size_t j = 0; j < sizeY; ++j )
{
std::size_t jNext = ( j + 1 ) % sizeY;
std::size_t jPrev = ( j + sizeY - 1 ) % sizeY;
for( std::size_t k = 0; k < sizeZ; ++k )
{
std::size_t kNext = ( k + 1 ) % sizeZ;
std::size_t kPrev = ( k + sizeZ - 1 ) % sizeZ;
std::size_t idx = i + j * sizeX + k * sizeX * sizeY;
// estimate change in concentrations
// we use a 3d laplace filter here instead of the 2d filter as in Eichelbaum et al.
float dc1 = 0.0;
dc1 += concentration1[ iPrev + j * sizeX + k * sizeX * sizeY ];
dc1 += concentration1[ iNext + j * sizeX + k * sizeX * sizeY ];
dc1 += concentration1[ i + jPrev * sizeX + k * sizeX * sizeY ];
dc1 += concentration1[ i + jNext * sizeX + k * sizeX * sizeY ];
dc1 += concentration1[ i + j * sizeX + kPrev * sizeX * sizeY ];
dc1 += concentration1[ i + j * sizeX + kNext * sizeX * sizeY ];
dc1 -= 6.0f * concentration1[ idx ];
float dc2 = 0.0;
dc2 += concentration2[ iPrev + j * sizeX + k * sizeX * sizeY ];
dc2 += concentration2[ iNext + j * sizeX + k * sizeX * sizeY ];
dc2 += concentration2[ i + jPrev * sizeX + k * sizeX * sizeY ];
dc2 += concentration2[ i + jNext * sizeX + k * sizeX * sizeY ];
dc2 += concentration2[ i + j * sizeX + kPrev * sizeX * sizeY ];
dc2 += concentration2[ i + j * sizeX + kNext * sizeX * sizeY ];
dc2 -= 6.0f * concentration2[ idx ];
// diffusion
delta1[ idx ] = spotFactor * ( 16.0f - concentration1[ idx ] * concentration2[ idx ] ) + d1 * dc1;
delta2[ idx ] = spotFactor * ( concentration1[ idx ] * concentration2[ idx ] - concentration2[ idx ] - noise[ idx ] ) + d2 * dc2;
}
}
}
for( std::size_t i = 0; i < sizeX; ++i )
{
for( std::size_t j = 0; j < sizeY; ++j )
{
for( std::size_t k = 0; k < sizeZ; ++k )
{
std::size_t idx = i + j * sizeX + k * sizeX * sizeY;
concentration1[ idx ] += speed * delta1[ idx ];
concentration2[ idx ] += speed * delta2[ idx ];
}
}
}
}
img->allocateImage( sizeX, sizeY, sizeZ, type, 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 i = 0; i < sizeX; ++i )
{
for( std::size_t j = 0; j < sizeY; ++j )
{
for( std::size_t k = 0; k < sizeZ; ++k )
{
std::size_t idx = i + j * sizeX + k * sizeX * sizeY;
img->data()[ idx ] = 255.0f * ( concentration1[ idx ] - c1min ) / ( c1max - c1min );
}
}
}
return osg::ref_ptr< WGETexture< osg::Texture3D > >( new WGETexture< osg::Texture3D >( img ) );
}
......@@ -145,6 +145,22 @@ namespace wge
* \return the generated image.
*/
osg::ref_ptr< osg::Image > genWhiteNoiseImage( size_t sizeX, size_t sizeY, size_t sizeZ, size_t channels = 1 );
/**
* Generates a 3D turing noise texture. For details, see:
*
* Eichelbaum, Sebastian, et al. "Fabric-like visualization of tensor field data on arbitrary surfaces
* in image space." New Developments in the Visualization and Processing of Tensor Fields. Springer Berlin Heidelberg, 2012. 71-92.
*
* \param sizeX The size of the textures in voxels, should be a power of 2.
* \param sizeY The size of the textures in voxels, should be a power of 2.
* \param sizeZ The size of the textures in voxels, should be a power of 2.
* \param channels The number of channels; either 1, 3 or 4.
*
* \return The texture.
*/
osg::ref_ptr< WGETexture< osg::Texture3D > > genTuringNoiseTexture( std::size_t sizeX, std::size_t sizeY,
std::size_t sizeZ, std::size_t channels = 1 );
}
template < typename T >
......
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