How to use many 3D textures in dynamic mode in shader?

I want to use two small volume to construct a large volume. These two small volume use the same TextureCoordinates, different vertices, different 3Dtexture.How can I use two small 3DTexture in same fragment shader.I try to do this(this is a test for my design):

glBindTexture(GL_TEXTURE_3D, 1);
glBindTexture(GL_TEXTURE_3D, 2);
int NumVolume = 2;     
for(j=1; j<=NumVolume; j++)
		GLint texLoc;
		texLoc = glGetUniformLocation(p, "volume");
		glUniform1i(texLoc, j);
		texLoc = glGetUniformLocation(p, "transferfunction");
		glUniform1i(texLoc, 0);

		glBindTexture(GL_TEXTURE_3D, j);
		glBindTexture(GL_TEXTURE_1D, 0);

		for(i=0; i<10; i++)
			glTexCoord3f(0.0, 0.0, i*0.1);
			glVertex3f(0.0, 0.0, i*1+(j-1)*10);
			glTexCoord3f(0.0, 1.0, i*0.1);
			glVertex3f(5.0, 0.0, i*1+(j-1)*10);
			glTexCoord3f(1.0, 1.0, i*0.1);
			glVertex3f(5.0, 5.0, i*1+(j-1)*10);
			glTexCoord3f(1.0, 0.0, i*0.1);
			glVertex3f(0.0, 5.0, i*1+(j-1)*10);

We should use glActiveTexture() and glUnifor1i() to tell the shader where the texture is.But glActiveTexture can not use in dynamic mode. if I need to use much more 3DTexture in shader. what should I do?

Man, you really need to sit down and read manuals and example code on volume rendering.

For volume bricking you don’t just download multiple smaller textures to build up the complete volume. That would also not work for volumes which use up all texture space (just imagine multiple GB data sets). Instead you have a limited number of bricks as a working set and replace the volume data in them dynamically just in time before you need them for rendering.

The rendering in your case would be something like this, though that would require the two 3D texture objects to be downloaded.

glBindTexture(GL_TEXTURE_1D, 0); // You are aware that 0 is the default immediate texture object?
// Better use glGenTextures for all your texture objects.
// Moved outside the loop. Constant for this shader
GLint texLoc = glGetUniformLocation(p, "transferfunction");
glUniform1i(texLoc, 0);

GLint locVolumeSampler = glGetUniformLocation(p, "volume");
glUniform1i(locVolumeSampler, 1);


int NumVolume = 2;     

for(j = 1; j <= NumVolume; j++)
    glBindTexture(GL_TEXTURE_3D, j); // Goes to texture image unit 1.
    glBegin(GL_QUADS); // Moved outside the loop for longer batches.
    for (i =0; i < 10; i++)
            glTexCoord3f(0.0f, 0.0f, i*0.1f);
            glVertex3f(0.0f, 0.0f, i*1+(j-1)*10);
            glTexCoord3f(0.0f, 1.0f, i*0.1f);
            glVertex3f(5.0f, 0.0f, i*1+(j-1)*10);
            glTexCoord3f(1.0f, 1.0f, i*0.1f);
            glVertex3f(5.0f, 5.0f, i*1+(j-1)*10);
            glTexCoord3f(1.0f, 0.0f, i*0.1f);
            glVertex3f(0.0f, 5.0f, i*1+(j-1)*10);

The shader needs to have only two samplers, the 1D “transferFunction” and the 3D “volume”.

Using immediate mode is convenient, but you should try to move to vertex arrays in the future for fewer OpenGL calls.

oh, thank you Relic you help me understand the glActiveTexture well.Now I know that it just need two Texture stages.And one stage can bind many Textures, right?. You are right. I should study the basic knowledges of GL carefully. :slight_smile:

And, is it means that we will use more slice and vertices than before if we use small bricks?And if I use a small volume of 2x2x2 to build a large volume of 512x512x512.I will creatre more and more Textures of small volume, right?

2x2x2 isn’t exactly useful.

The point is to not hold the complete 3D volume in texture memory, because you can’t.
That is why I said “The rendering in your case would be something like this, though that would require the two 3D texture objects to be downloaded.”
This is not feasible for huge volumes.

Continuing with your initial example, of 1024^3 assuming medical data with 16 bit luminance per texel that would take 2GB of memory!
No standard graphics board can handle this in one single 3D texture. (There exists special graphics hardware for volume rendering which could.)

In the lowest possible case one single 3D texture brick which can be downloaded is enough to get this bricking working.
You’d just need to put a glTexImage3D per brick or better glTexSubImage3D with the brick size instead of the glBindTexture(GL_TEXTURE_3D, j) in above code. But that’s not really the performance case because doing that would stall the rendering all the time!

What I would do is:

You need to have a working set of multiple 3D volume bricks which can be rendered from, while another can be downloaded in parallel.
This can be done in a separate thread running a shared context.

The optimal bricking size is normally determined by benchmarking the sweet spot for downloading and rendering texture data of these texture sets.
Normally 32^3 or 64^3 is a good start for tests.

Since the 2GB don’t fit, you allocate lets say enough textures to take 64MB, sort your bricks the way you want to render, fill the brick(s), start the rendering thread, while it renders you exchange the data of already processed bricks with new texture data from RAM and put that texture object id into the rendering queue for that brick geometry.

And then you’ll face the rendering challenges I haven’t mentioned, yet. :wink:

Just try to find example implementations of this on the internet.

Ok, I will keep on going.More challenges, more interests.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.