I am trying to store data into a 3D texture, however it doesn't seem to work. I set up the texture like this:
glGenTextures(1, &voxelTexture);
glBindTexture(GL_TEXTURE_3D, voxelTexture);
unsigned char clearData[VoxelSize* VoxelSize* VoxelSize];
memset(clearData, 5, sizeof(clearData));
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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);
glTexImage3D(GL_TEXTURE_3D, 0, GL_R8UI, VoxelSize, VoxelSize, VoxelSize, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, clearData);
Later, I write to the texture:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, VoxelSize, VoxelSize);
glUseProgram(voxelProg);
glBindTexture(GL_TEXTURE_3D, voxelTexture);
glBindImageTexture(0, voxelTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R8UI);
for(const auto & i : models){
glUniformMatrix4fv(glGetUniformLocation(voxelProg, "M"), 1, GL_FALSE, glm::value_ptr(i->getModelMatrix()));
glBindVertexArray(i->getMesh()->vao);
glDrawElements(GL_TRIANGLES, i->getMesh()->nbVertices, GL_UNSIGNED_INT, 0);
}
I know the draw operation works fine because I have used it with a shadow map in another part of the program.
Finally, I try to read the data from the texture:
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
static char data[VoxelSize * VoxelSize *VoxelSize] = {0};
glGetTexImage(GL_TEXTURE_3D, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, data);
for(auto & i : data){
if(i!=5)
std::cout << (int)i << " ";
}
endl(std::cout);
As you can see, if the data was modified then it would print to cout
. I set the data to be 5 so that you can see that glGetTexImage
actually reads the texture data (because otherwise it would be all zeroes).
The program that I use has this as the vertex buffer:
#version 430
layout(location = 0) in vec3 position;
uniform mat4 M;
void main(){
gl_Position = M* vec4(position, 1.0);
}
And this as the fragment buffer:
#version 430
layout(binding = 0, r8ui)writeonly restrict uniform uimage3D dataTexture;
void main(){
imageStore(dataTexture, ivec3(6,6,6), uvec4(30));
}
I used an arbitrary location to write to rather than one that is affected by the fragment itself so that I could at least be assured that if any fragment got passed through it would affect the texture. However, nothing seems to work. I've tried changing where the imageStore
writes to, I've tried scaling gl_Position
in the vertex buffer in various ways. Any help would be appreciated.
Edit:
After following the possible duplicates solution of changing the layered setting from false
to true
, it still doesn't work.
glUseProgram(voxelProg)
and glGetUniformLocation(mainProg, "M")
reference different shader programs. Consequently, the matrix M
isn't set, the vertices form degenerate triangles and no fragments are rasterized so imageStore
never actually gets called.
Also glBindImageTexture
handles 3D textures as "layered" 2D textures, so the layered argument must be GL_TRUE
. see this.
[EDIT] In this case, M
is not projecting the geometry correctly for other reasons too (see the comments). To change M
so that it scales and translates the mesh into a -1 to 1 cube to match the 3D image, see: How to normalize a mesh into -1 to 1, then revert from normalized mesh to original one?