octree texture and volume rendering, maybe problem

Started by
3 comments, last by Benzino 12 years, 8 months ago
Hello,
I need some professionel help. For empty space leaping in
volume raycasting I store the octree in a 3d texture. To be
more precisely, I store only the max depth of the tree. For
instance a depth of 5 results in 8^5 (32768) boxes). So the
desired 3d texture (format: GL_RGB) is 2^5 32x32x32.

I create the octree on the cpu and every node of the octree
samples the volume with respect to it's current size. For example the box of a node has a size of
[0.5,0.0,0.0] - [0.75,0.25,0.25]. The volume may 256x256x256.
The space this node samples then is from
256*0.5, 256*0.0, 256*0.0 till 256*0.75,256*0.25,256*0.25
I sample one extra voxel at the borders of each node to avoid
interpolation errors (later on GPU side).
with the coordinates of the box I can calculate the
To create the 3d texture for storing the octree, I first create an array on the cpu side. for this example it's size
is 32*32*32*3 because of depth 5. I take the size threetimes because I create a RGB texture. While creating the octree
I write the min and the max value that have been calculated by
sampling the node. And I only write those values at the lowest
depth off course, here at depth 5. Additionally to the octree
I create a min-max texture. This texture is as wide and as heights as there are values. That means, a 8bit data set has values from 0 to 255. so the texture size is 256*256. In this
texture I write for every min max pair if the data is visible or not.

Before continuing with the problem, here is some code


node sampling
if(currDepth == maxDepth){/* max depth has been reached, incr. count*/childrenCount++;/* aabb boundaries*/glm::vec3 llf = aabb.getLowerLeft();glm::vec3 ur  = aabb.getUpperRight();/* vol size*/glm::vec3 vecSize = volume->getDimension();/**/ valMin = 255.0f; valMax = 0; unsigned char val = 0; unsigned char* pvoxels = static_cast<unsigned char*(Node::volume->getVoxels()); float tmpX0 = vecSize.x * llf.x; float tmpX1 = vecSize.x * ur.x; float tmpY0 = vecSize.y * llf.y; float tmpY1 = vecSize.y * ur.y; float tmpZ0 = vecSize.z * llf.z; float tmpZ1 = vecSize.z * ur.z;/* calc start and end points with one additional sample to avoid interpolating artifacts*/int x0 = static_cast<int>(floor(tmpX0));-1;int x1 = static_cast<int>(floor(tmpX1));+1;int y0 = static_cast<int>(floor(tmpY0));-1;int y1 = static_cast<int>(floor(tmpY1));+1;int z0 = static_cast<int>(floor(tmpZ0));-1;int z1 = static_cast<int>(floor(tmpZ1));+1;if(x0 < 0) { x0 = 0; }if(x1 > static_cast<int>(floor(vecSize.x))) { x1 = static_cast<int>(floor(vecSize.x)); }if(y0 < 0) { y0 = 0; }if(y1 > static_cast<int>(floor(vecSize.y))) { y1 = static_cast<int>(floor(vecSize.y)); }		if(z0 < 0) { z0 = 0; }if(z1 > static_cast<int>(floor(vecSize.z))) { z1 = static_cast<int>(floor(vecSize.z)); }int xy = vecSize.x * vecSize.y;/* sample sub volume for min/max values*/for(int z = z0; z < z1; z++){ for(int y = y0; y < y1; y++) {  for(int x = x0; x < x1; x++)  {   val = pvoxels[z * xy + y * static_cast<int>(vecSize.x) + x];   if(val < valMin) { valMin = val; }   if(val > valMax) { valMax = val; }  } }}		/* calc coordinates to get correct index for writing the min/max values at the correct position of the octree data array*/ float u = static_cast<int>((ur.x * sideLength) - 1.0f); float v = static_cast<int>((ur.y * sideLength) - 1.0f); float w = static_cast<int>((ur.z * sideLength) - 1.0f); int sl = static_cast<int>(sideLength); int suv = sl * sl; int idxMin = w * suv * 3 + v * sl * 3 + u * 3; int idxMax = w * suv * 3 + v * sl * 3 + u * 3 + 1; octreeData[idxMin] = valMin; octreeData[idxMax] = valMax;}


creation of minmax data for the 2d texture
for(int max = 0; max < 256; max++){  for(int min = 0; min < 256; min++)  {    for(int i = min; i <= max; i++)    {      mm[max * 256 + min] = opacities > 0 ? 255 : 0;    }  }}


Then I update both textures (the 2d minmax tex and the 3d octree tex). As filter I set for both texture GL_NEAREST.

So far so good. You may have look at the two pictures.
Nothing suspicious for the moment, right ? :D
These pictures are taken without any octree. Just simple
volume raycasting

rcesl1.jpg
rcesl2.png

The following pictures shows the result with octree texture.

So, in the picture below you can see a lot of artifacts cause by non visible boxes. But at this position there should be visible boxes because these areas contain data and according to the min max texture they are visible.

rcesl3.jpg

In the picture below I draw nonvisible data blue and depth is
set to 1, (2 boxes on each axis).

Actually there shoudnlt be any non blue boxes. because each of the 8 big boxes contain
data with respect to the min max texture.

Here is some shader code to show you how I access the textures.
The function esl() is not complete. It actually contains calculations
to step icnrease tCurr by a value so that sampelPos skips empty regions
completely. But to keep it simple and for testing it only return's if there
is visible data or not.

int esl(vec3 samplePos, vec3 rayIncr, float stepWide, float tCurr){	vec3 mm = texture(texOctree, samplePos).rgb;	float val = texture(texMinMax, mm.rg).r;        return int(val);}samplePos = first + t * rayDirection;if(esl(samplePos, rayIncr, tIncr, t) == 1){ sample volume}



Hope there is someone who gives me a good advice.

regards,
c-mos
Advertisement
I am so stupid.
Problem is solved.

regards,
c-mos
Hey,

Just wondering, what was the problem after all do you remember?
Hello,
yes I remember the problem. There was some mistake in creating the importance map for the octree texture. Some mixed-up if/else statements.
After fixing that, the problems disappeared.

regards,
c-mos
Hey again,

Can I ask you about your implementation? As I am trying to implement a similar approach based on the GPU Gems 2 chapter 37, but I'm not having much success and I am considering changing approach. I have read your description and your code, but I'm a bit confused as to what you are doing.

The approach you take is to only store the leaf nodes in the 3d texture. In this texture, you store the min and max volume scalar (or opacity) values within the current node. So each pixel in the 3D texture represents a node, and the r component of each pixel stores the min value for that node, and the g component stores the max value for that node.

Then you create another texture to store 0 if the corresponding node in the 3D Texture is empty, or 255 if it has data (I'm sure you could store this value in the blue component of each pixel in the 3D Texture instead, yeah? ).

Am I understanding your approach correctly?

Thanks for your help and your post, it has been helpful to me to understand this method.

This topic is closed to new replies.

Advertisement