I am attempting to create an empty 3D texture, the dimensions and format of which are loaded in at runtime. I then want to modify the values of this texture, which I am then volume rendering with a ray tracer. I know my rendering function works fine, as I can render the volume that the dimensions and format comes from without a problem. The empty volume also renders, but I am unable to write any data to it, and so it is just white all the way through.
//My function that creates the blank texture initially
//Its part of a larger class that reads in a populated volume and a transfer function,
//I'm just initialising it in this way so it is identical to the other volume, but empty
GLuint Texture3D::GenerateBlankTexture(VolumeDataset volume)
{
GLuint tex;
glEnable(GL_TEXTURE_3D);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_3D, tex);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
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);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Reverses endianness in copy
if (!volume.littleEndian)
glPixelStoref(GL_UNPACK_SWAP_BYTES, true);
if (volume.elementType == "MET_UCHAR")
{
// texture format, ?, channels, dimensions, ?, pixel format, data type, data
glTexImage3D(GL_TEXTURE_3D, 0, GL_R8, volume.xRes, volume.yRes, volume.zRes, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
glBindImageTexture(0, tex, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R8);
}
else if (volume.elementType == "SHORT")
{
glTexImage3D(GL_TEXTURE_3D, 0, GL_R16F, volume.xRes, volume.yRes, volume.zRes, 0, GL_RED, GL_UNSIGNED_SHORT, NULL);
glBindImageTexture(0, tex, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R16F);
}
else if (volume.elementType == "FLOAT")
{
glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, volume.xRes, volume.yRes, volume.zRes, 0, GL_RED, GL_FLOAT, NULL);
glBindImageTexture(0, tex, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
}
glPixelStoref(GL_UNPACK_SWAP_BYTES, false);
GLenum err = glGetError();
glBindTexture(GL_TEXTURE_3D, 0);
return tex;
}
With the volume created, I then read it into a compute shader in my display function:
glUseProgram(Compute3DShaderID);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, tex_output);
glDispatchCompute((GLuint)volume.xRes/4, (GLuint)volume.yRes/4, (GLuint)volume.zRes/4);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
Within my shader, all I'm trying to do is change the colour based on its position in the volume:
#version 430
layout (local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
layout (r8, binding = 0) uniform image3D tex_output;
void main()
{
ivec3 dims = imageSize (tex_output);
ivec3 pixel_coords = ivec3(gl_GlobalInvocationID.xyz);
vec4 pixel = vec4(pixel_coords.x/dims.x, pixel_coords.y/dims.y, pixel_coords.y/dims.y, 1.0);
imageStore (tex_output, pixel_coords, pixel);
}
I'm sure the error is something to do with access to writing being denied, but I can't pinpoint exactly what it is.
Note: I'm using GL_RED and such because this is volume data, and this is how I have it in the rest of my volume renderer and it seems to work fine.
So, stupid mistake. Turns out my shaders were working fine. What I hadn't anticipated was that the values I was attempting to write to the volume mapped to a white colour on my transfer function. Once I pulled up the schematic for the transfer function, and tested with values that should work fine, I got actual colours.
Anyone seeing this question in the future, if your code isn't working, it should be as follows:
Create your texture, and set it as an image texture using glTexImage3D
. Then, when you wish to use it, call glBindImageTexture
and draw, making sure you set layered to GL_TRUE
since its a 3D texture. Also make sure that you bind to the correct binding (In my code above I bind to 0, but I've since added a second texture thats bound to 1) and unbind if you're going to use a second set of textures and shaders.
If you're having trouble, set it so that every iteration in your compute adds 0.01 to the final value, so you can see the colour change in real time.