c++openglalphablendingvolume-rendering

Volume Rendering alpha blending


I found this tutorial http://www.codeproject.com/Articles/352270/Getting-started-with-Volume-Rendering about Volume Rendering and tried to implement my own renderer. I got to the point when I can draw all slices at once with alpha testing, which gives me more or less such result as in tutorial. Now, I want to move step forward and apply alpha blending, but after that there is no change (and even if there is, it doesn't look such nice as in tutorial).

Here is my rendering code:

glClear(GL_COLOR_BUFFER_BIT  | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);

for (int i = 0; i < z; ++i)
{
    glBindTexture(GL_TEXTURE_2D, texturesObjects[i]);

    glBegin(GL_QUADS);

    glTexCoord2f(0.0f, 0.0f);
    glVertex3f(-1.0, -1.0, 2 * i / z - 1);
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f(1.0, -1.0, 2 * i / z - 1);
    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(1.0, 1.0, 2 * i / z - 1);
    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(-1.0, 1.0, 2 * i / z - 1);

    glEnd();
    glBindTexture(GL_TEXTURE_2D, 0);
}

glutSwapBuffers();

where z is number of slices. Texture generation code looks like that:

GLuint* loadXZslices(const VR::DataAccessor& accessor, int& x, int& y, int& z)
{
    x = accessor.getX();
    y = accessor.getY();
    z = accessor.getZ();

    GLuint* texturesObjects = new GLuint[accessor.getZ()];

    for (size_t i = 0; i < accessor.getZ(); ++i)
    {
        char* luminanceBuffer = accessor.getXYslice(i);
        char* rgbaBuffer = new char[accessor.getX() * accessor.getY() * 4];

        for (size_t j = 0; j < accessor.getX() * accessor.getY(); ++j)
        {
            rgbaBuffer[j * 4] = luminanceBuffer[j];
            rgbaBuffer[j * 4 + 1] = luminanceBuffer[j];
            rgbaBuffer[j * 4 + 2] = luminanceBuffer[j];
            rgbaBuffer[j * 4 + 3] = 255;

            if (luminanceBuffer[j] < 20)
            {
                rgbaBuffer[j * 4 + 3] = 0;
            }
        }

        glActiveTexture(GL_TEXTURE0);
        glGenTextures(1, &texturesObjects[i]);
        glBindTexture(GL_TEXTURE_2D, texturesObjects[i]);
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, accessor.getX(), accessor.getY(), 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)rgbaBuffer);

        delete[] luminanceBuffer;
        delete[] rgbaBuffer;
    }

    return texturesObjects;
}

DataAccessor is of course class that gives access to raw texture data.

Did I forget about setting something in my window or is there something wrong with my code?


Solution

  • A couple of things look questionable in your code:

    1. You're not setting up your textures to have partial transparency. Where you build your textures, you're setting the alpha component to either 255, or 0 if the original luminance is less than 20. To get actual blended values, you'll need to use the luminance value for the alpha component:

      rgbaBuffer[j * 4 + 3] = luminanceBuffer[j];
      

      To fine tune the results, you might have to use some other mapping from the original intensity to alpha. But it will probably still be some kind of ramp, and not a step function.

    2. While the code does not show the declaration for z, this code looks suspicious:

      glVertex3f(-1.0, -1.0, 2 * i / z - 1);
      

      From the context, it looks like z is probably an integer. If that's true, this will be an integer division, which will produce 0 while 2 * i is less than z, and 1 for the remaining loop values. At least one of the values will have to be cast to a float to make it a float division.