Working with GL_TEXTURE_3D

1.1k Views Asked by At

I'm trying to read a file representing values to be mapped to colors when rendering a volume. I.e., each voxel has its color represented in the input file. Here it follows a dummy test file:

4 4 4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

It should define a value with its top black, followed by a white layer, black layer and white again.

That's how I read it:

int width, height, depth;
file >> width;
file >> height;
file >> depth;

printf("Texture data: %d, %d, %d\n", width, height, depth);

// Creating buffer
unsigned char buffer[height][width][depth];

// Reading content
int v;
for (int i = 0; i < height; i ++) {
    for (int j = 0; j < width; j ++) {
        for (int k = 0; k < depth; k ++) {
            file >> v;
            buffer[i][j][k] = v * 255;
        }
    }
}

And that's how I create my texture:

// Create one OpenGL texture
GLuint textureID;
glGenTextures(1, &textureID);

// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_3D, textureID);

// Give the image to OpenGL
glTexImage3D(GL_TEXTURE_3D, 0, GL_RED, height, width, depth, 0, GL_RED, GL_UNSIGNED_BYTE, buffer);

glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

These are the values that are going to be used to construct my VAO:

_modelCoordinates = { -1.0, -1.0,  1.0,
                       1.0, -1.0,  1.0,
                       1.0,  1.0,  1.0,
                      -1.0,  1.0,  1.0,
                      -1.0, -1.0, -1.0,
                       1.0, -1.0, -1.0,
                       1.0,  1.0, -1.0,
                      -1.0,  1.0, -1.0 };

_modelIndices = { 0, 1, 2,
                  2, 3, 0,
                  1, 5, 6,
                  6, 2, 1,
                  7, 6, 5,
                  5, 4, 7,
                  4, 0, 3,
                  3, 7, 4,
                  4, 5, 1,
                  1, 0, 4,
                  3, 2, 6,
                  6, 7, 3 };

_textureCoordinates = {  0.0, 0.0, 1.0,
                         1.0, 0.0, 1.0,
                         1.0, 1.0, 1.0,
                         0.0, 1.0, 1.0,
                         0.0, 0.0, 0.0,
                         1.0, 0.0, 0.0,
                         1.0, 1.0, 0.0,
                         0.0, 1.0, 0.0 };

Finally, this are my shaders:

  1. Vertex Shader:

.

#version 410 core

uniform mat4 mvMatrix;
uniform mat4 pMatrix;

in vec4 vPosition;
in vec3 texCoord;

// Input for the fragment shader
smooth out vec3 uv;

void main() {
    gl_Position = pMatrix * mvMatrix * vPosition;
    uv = texCoord;
}   
  1. Frag Shader:

.

#version 410 core

uniform sampler3D tex;

in vec3 uv;
out vec4 fragColor;

void main()
{ 
   vec3 color = texture(tex, uv).rrr;
   fragColor.rgb = color;
}

After loading the uniforms and attribute values, I draw the volume:

_modelView = modelView;
_projection = projection;

_succeed = Bind();
if (_succeed)
{
    glBindVertexArray(_vao);
    LoadUniformVariables();
    glDrawElements(GL_TRIANGLES, _modelIndices.size(), GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}
UnBind();

However, all that I get is a blank volume:

enter image description here

I dont't know how to proper set the texture coordinates and how to correctly implement the fragment shader for this case.

2

There are 2 best solutions below

0
On BEST ANSWER

After adding these lines:

glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

Everything worked fine.

2
On

Looks like your texture coordinates are not properly assigned to face vertices, so that should be fixed. However you seem to expect that OpenGL will "magically" perform some kind of volume rasterization for you. And no kind of texture coordinate fixing will do that.

With the fragment shader as you wrote it, only a slice through the volume data will be sampled. What you have to do instead is writing a fragment shader that actually sends a ray through the texture and samples it at each and every sample the ray crosses through. There's a whole chapter on volume rendering in GPU Gems:

http://http.developer.nvidia.com/GPUGems/gpugems_ch39.html