Jump to content
  • Advertisement
Sign in to follow this  

octree texture and volume rendering, maybe problem

This topic is 2692 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

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
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


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.


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.


Share this post

Link to post
Share on other sites
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.


Share this post

Link to post
Share on other sites
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.

Share this post

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

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!