Commit c76f5856 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[CHANGE] - improved raycasting of isosurfaces and its lighting.

parent 0c9bcbaf
......@@ -99,6 +99,11 @@ void WMDirectVolumeRendering::properties()
50 );
m_isoColor = m_properties2->addProperty( "Iso Color", "The color to blend the isosurface with.", WColor( 1.0, 1.0, 1.0, 1.0 ),
m_propCondition );
m_stepCount = m_properties2->addProperty( "Step Count", "The number of steps to walk along the ray during raycasting. A low value"
"may cause artifacts whilst a high value slows down rendering.", 250 );
m_stepCount->setMin( 1 );
m_stepCount->setMax( 1000 );
}
void WMDirectVolumeRendering::moduleMain()
......@@ -185,8 +190,12 @@ void WMDirectVolumeRendering::moduleMain()
osg::ref_ptr< osg::Uniform > isosurface = new osg::Uniform( "u_isosurface", m_isoSurface->get() );
isosurface->setUpdateCallback( new SafeUniformCallback( this ) );
osg::ref_ptr< osg::Uniform > steps = new osg::Uniform( "u_steps", m_stepCount->get() );
steps->setUpdateCallback( new SafeUniformCallback( this ) );
rootState->addUniform( isovalue );
rootState->addUniform( isosurface );
rootState->addUniform( steps );
// update node
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
......@@ -217,6 +226,11 @@ void WMDirectVolumeRendering::SafeUniformCallback::operator()( osg::Uniform* uni
{
uniform->set( m_module->m_isoSurface->get( true ) );
}
if ( m_module->m_stepCount->changed() && ( uniform->getName() == "u_steps" ) )
{
uniform->set( m_module->m_stepCount->get( true ) );
}
}
void WMDirectVolumeRendering::activate()
......
......@@ -132,6 +132,11 @@ private:
*/
WPropColor m_isoColor;
/**
* The number of steps to walk along the ray.
*/
WPropInt m_stepCount;
/**
* A condition used to notify about changes in several properties.
*/
......
......@@ -43,6 +43,9 @@ uniform float u_isovalue;
// Should the shader create some kind of isosurface instead of a volume rendering?
uniform bool u_isosurface;
// The number of steps to use.
uniform int u_steps;
/////////////////////////////////////////////////////////////////////////////
// Attributes
/////////////////////////////////////////////////////////////////////////////
......@@ -55,6 +58,34 @@ uniform bool u_isosurface;
// Functions
/////////////////////////////////////////////////////////////////////////////
vec3 findRayEnd( out float d )
{
vec3 r = v_ray + vec3( 0.0000001 );
vec3 p = v_rayStart;
// we need to ensure the vector components are not exactly 0.0
// v_ray in cube coordinates is used to check against the unit cube borders
// when will v_ray reach the front face?
float tFront = - p.z / r.z; // (x,x,0) = v_rayStart + t * v_ray
float tBack = ( 1.0 - p.z ) / r.z; // (x,x,1) = v_rayStart + t * v_ray
float tLeft = - p.x / r.x; // (0,x,x) = v_rayStart + t * v_ray
float tRight = ( 1.0 - p.x ) / r.x; // (1,x,x) = v_rayStart + t * v_ray
float tBottom = - p.y / r.y; // (x,0,x) = v_rayStart + t * v_ray
float tTop = ( 1.0 - p.y ) / r.y; // (x,1,x) = v_rayStart + t * v_ray
// get the nearest hit
d = min( min( max( tFront, tBack ), max( tLeft, tRight ) ), max ( tBottom, tTop ) );
return p + ( r * d );
}
float pointDistance( vec3 p1, vec3 p2 )
{
return length( p1 - p2 );
}
/**
* Main entry point of the fragment shader.
*/
......@@ -62,35 +93,96 @@ void main()
{
// please do not laugh, it is a very very very simple "isosurface" shader
gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
gl_FragDepth = gl_FragCoord.z;
// First, find the rayEnd point. We need to do it in the fragment shader as the ray end point may be interpolated wrong
// when done for each vertex.
float totalDistance = 0.0;
vec3 rayEnd = findRayEnd( totalDistance );
// Isosurface Mode
if ( u_isosurface )
{
// the point along the ray in cube coordinates
vec3 curPoint = v_rayStart;
// the current value inside the data
float value;
// the step counter
int i = 0;
while ( i < 250 )
float stepDistance = totalDistance / float( u_steps );
while ( i < u_steps ) // we do not need to ch
{
i++;
// get current value
value = texture3D( tex0, curPoint ).r;
if ( value >= u_isovalue )
// is it the isovalue?
if ( abs( value - u_isovalue ) < 0.1 )
{
// we need to know the depth value of the current point inside the cube
// Therefore, the complete standard pipeline is reproduced here:
// 1: transfer to world space and right after it, to eye space
vec4 curPointProjected = gl_ModelViewProjectionMatrix * vec4( curPoint, 1.0 );
// 2: scale to screen space and [0,1]
// -> x and y is not needed
// curPointProjected.x /= curPointProjected.w;
// curPointProjected.x = curPointProjected.x * 0.5 + 0.5 ;
// curPointProjected.y /= curPointProjected.w;
// curPointProjected.y = curPointProjected.y * 0.5 + 0.5 ;
curPointProjected.z /= curPointProjected.w;
curPointProjected.z = curPointProjected.z * 0.5 + 0.5 ;
// 3: set depth value
gl_FragDepth = curPointProjected.z;
// 4: set color
// NOTE: these are a lot of weird experiments ;-)
float d = 1.0 - curPointProjected.z;
d = 1.5*pointDistance( curPoint, vec3( 0.5 ) );
gl_FragColor =( gl_Color * vec4( vec3( 7.0*d*d*d*d*d ), 1.0 ) );
float w = dot( normalize( vec3( 0.5 ) - curPoint ), normalize( v_ray ) );
w = ( w + 0.25 );
if ( w > 0.8 ) w = 0.8;
float d2 = w*d*d*d*d*d;
gl_FragColor = gl_Color * 11.0 * d2;
//gl_FragColor = vec4( vec3( w ), 1.0 );
/*
for ( float i = 0.0; i < 1.0; i+=0.05 )
{
if ( i <= d && i+0.05 > d )
{
d = i;
break;
}
}*/
break;
}
else
{
curPoint += 0.005 * v_ray;
// no it is not the iso value
// -> continue along the ray
curPoint += stepDistance * v_ray;
}
// do not miss to count the steps already done
i++;
}
if ( i >= 250 )
// the ray did never hit the surface --> discard the pixel
if ( i == u_steps )
{
discard;
}
gl_FragColor = 0.5 * ( gl_Color + vec4( vec3( 1.0 - i / 250.0 ), 1.0 ) );
}
}
......@@ -59,13 +59,13 @@ void main()
v_normal = gl_Normal;
// in texture space, the starting point simply is the current surface point in texture space
v_rayStart = gl_TexCoord[0].xyz;
v_rayStart = gl_TexCoord[0].xyz; // this equals gl_Vertex!
// transform the ray direction to texture space, which equals object space
// Therefore use two points, as we transform a vector
vec4 camLookAt = vec4( 0.0, 0.0, -2.0, 1.0 );
vec4 camPos = vec4( 0.0, 0.0, -1.0, 1.0 );
v_ray = normalize( ( gl_ModelViewMatrixInverse * ( camLookAt - camPos ) ) ).xyz;
vec4 camLookAt = vec4( 0.0, 0.0, -1.0, 1.0 );
vec4 camPos = vec4( 0.0, 0.0, 0.0, 1.0 );
v_ray = ( gl_ModelViewMatrixInverse * ( camLookAt - camPos ) ).xyz;
// Simply project the vertex
gl_Position = ftransform();
......
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