• Advertisement
Sign in to follow this  

volume rendering, empty space leaping

This topic is 2753 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello there,
I have a problem and need some help from you. I have implemented
raycasting for volume rendering. Now I'm implementing empty space leaping
to skip areas of the volume that not contribute to the final image.
Therefor I create a octree like texture and sample the volume data on
cpu side and get the min and max value of each area. Let's assume I have
a volume file loaded that is 256x256x256 and I my octree like structure
is 16x16x16. So each cell's dimension is 16 in every direction. Each cell
contains the min and max value from the original volume data. Furthermore I created a min/max field that contains combinations of min/max pairs. It's just
a simple 2d array with length 256 and width 256.

The octree like structure and the min max array are uploaded to the gpu as uniform
parameters in my shader.The octree texture is a sampler3D and the minmax array is
a sampler2D.

Without emptyspace leaping, every ray runs through the volume and composed the
colors. With empty space leaping I want to skip empty areas.

First, here is some shader code

ray aabb intersection

float rayaabb(vec3 samplePos, vec3 raydir)
vec3 cellMin = floor(samplePos/ cellSize) * cellSize;
vec3 cellMax = cellMin + vec3(cellSize);

vec3 tmin = (cellMin - samplePos)/raydir;
vec3 tmax = (cellMax - samplePos)/raydir;

vec3 rmin = min(tmin, tmax);
vec3 rmax = max(tmin, tmax);

return min(min(rmax.x, rmax.y), rmax.z);

raycasting shader

float t = 0.0;
float tIncr = 0.0;
float steps = 0.0;
float tEnd = 1.0;

vec3 cellMin,cellMax,rayDir, rayIncr;
vec4 result = vec4(0.0,0.0,0.0,0.0);

raySetup(first, last, rayDir, rayIncr, tIncr, tEnd);
vec3 samplePos = first;

for(int i = 0; i <= samplings; i++)
float visible = texture(texMinMax, texture(texOctree, samplePos).rg).r;
if(visible > 0)
// get voxel
vec4 voxel;
voxel.a = getVoxel(texVolume, samplePos).a;
// apply transfer function
vec4 color = texture(texTransfer1d, voxel.a);

voxel.xyz = calcGradientCd(samplePos, t, rayDir, texcoord);
// apply shading
color.rgb = phongShading(voxel.xyz, samplePos, color.rgb, color.rgb, vec3(1.0, 1.0, 1.0)) ;
// compose
color.a = 1.0 - pow(1.0 - color.a, opacityFactor);
result.rgb = result.rgb + (1.0 - result.a) * color.a * color.rgb;
result.a = result.a + (1.0 -result.a) * color.a;

t += tIncr;
cellMin = floor(samplePos / cellSize) * cellSize;
cellMax = cellMin + vec3(cellSize);

float distance = rayaabb(samplePos, rayDir);
t = t + tIncr * (distance / tIncr);
samplePos = r0 + t * rayDir;

if(result.a >= 0.95) { result.a = 1.0; break; }
if(t >= tEnd) { break; }

First, I setup the ray with start position. In this raycasting the ray never starts outside the volume. Because the entrypoints are generated from a color coded cube with colors from 0,0,0 to 1,1,1. So the ray can never start outside.

The first step in the main loop is a look up to decide wether the area at the current sample position is empty. texOctree contains the 16x16x16 cells generated on cpu side. It's a RGB texture that holds the min and max for this cell. Min and max can be from 0 up to 255 (voluem data is 8bit). With the min max value I look up in the min max texture to get a value that indicates this cell is visible or not. When changing the transfer function I only update the minmax texture.

When data is visible I render as usual => get color from 1d transfer function
and apply shading.
If it's not visible I calculate the current cell the ray is in.

cellMin = floor(samplePos / cellSize) * cellSize;
cellMax = cellMin + vec3(cellSize)

cellSize is 1/octree dim. That means, here the cellSize is 1/16, because my octree cell is 16x16x16.

With the current cell the ray is in, I calculate the intersection point with the
current rayposition (samplePos) and the above calculated cell. Therefor I use
the rayaabb function. It's based on a slab test. Because the ray position is
always in a cell or on a cell edge I only need tmax from this intersection function.

Dividing this distance by the sample length (tIncr) I get the amount of samples
I can skip.

In theory it works ;) but pracitcally it doesnt work correct. It seems that sometimes tmax is wether 0 or too large. Then I see just nothing. It only "works" when I move the camera to a certain position. If I move the camera further the object starts disappearing and the framerate drops down.

Here are some pictures

The first two picture show the movement to the certain camera position where
my empty space leaping "works"
This is the camera origin point of view. position is 0,0,5 and view vector is 0,0,-1.


At this picture I reached that point. The object is visible
This picture shows the same object but I changed the transfer function
This last picture show, when I move the object. You can see that it starts
disappearing. At this point the framerate also drops down massivley.

The dropdown of the framerate makes me think that the calculated distance is too short, because the ray is wether terminated when accumulated alpha values are near to 1.0 or when the t is greater than tEnd. tEnd is the maximal length a ray can traverse the volume til it leaves it.

I dont know else what to do. I checked the intersection function on cpu side with some values and it seems to work properly. I mean, actually it souldnt be so difficult. Check if the area is visible or not. Calculate new t and advance the ray.

I really hope there is someone who can help me out.


Edit: In general, this empty space leaping works. When I set the skip distance to a fixed value, for instance 10, than visible parts are rendered with normal sampling wide and non visible areas are skipped with 10times the sampling wide.

[Edited by - c-mos on September 2, 2010 6:03:49 AM]

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement