I have a 3 dimensional dataset where each value of the dataset is normalized to [0, 1]. I want to visualize this dataset by using texture, and blending. However, it seems that I can't make it work.

Here is what I have done so far:

int main(){
    //building an image for each rectangular slice of data
    vector<Texture> myTextures;
    for (GLint rowIndex = 0; rowIndex < ROW_NUM; rowIndex++)
        auto pathToImage = "images/row" + to_string(rowIndex) + FILE_EXT;
        FIBITMAP *img = FreeImage_Allocate(SLICE_DIMENSION, SLICE_NUM, 32); //32 = RGBA

        for (GLint depthIndex = 0; depthIndex < DEPTH_NUM; depthIndex++)
            for (GLint colIndex = 0; colIndex < COL_NUM; colIndex++)
                auto value = my3DData[depthIndex][rowIndex][colIndex];

                //transform tValue to a source color
                glm::vec4 source = transformValueToColor(value);

                //note that here I am also setting the opacity. 
                RGBQUAD linRgb = { source.b, source.g, source.r, source.a }; 
                FreeImage_SetPixelColor(img, colIndex, depthIndex, &linRgb);

        //Saving images. Saved images shows transparency. 
        FreeImage_Save(FIF_PNG, img, pathToImage.c_str());
        myTextures.push_back(Texture(pathToImage.c_str(), GL_TEXTURE0));
    //create VAO, VBO, EBO for a unit quad.


    //game loop
    while (!glfwWindowShouldClose(window))
        for (int i = 0; i < myTextures.size(); i++)
            GLint index = myTextures.size() - i - 1;
            myTextures[index].bind(); //does glActiveTexture(...), and glBindTexture(...);

            glm::mat4 model;

            model = glm::translate(model, glm::vec3(0.0f, 0.0f, -index*0.003f));

            model = glm::scale(model, glm::vec3(1.2f));

            glUniformMatrix4fv(glGetUniformLocation(ourShader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));

            glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

transformValueToColorfor transforming data value in [0,1] to color value:

//All inputs >=0.6 is transformed to highly transparent white color.
glm::vec4 transformValueToColor(GLclampf tValue)
    if (tValue >= 0.6f) {
        return glm::vec4(255, 255, 255, 10);
    else {
        auto val = round(255 * tValue);
        auto valOp = round(255 * (1 - tValue));
        return glm::vec4(val, val, val, valOp);

My vertex shader:

#version 330 core

layout(location = 0) in vec3 position;
layout(location = 1) in vec2 texCoord;

out vec2 TexCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
    gl_Position = projection * view * model * vec4(position, 1.0f);
    TexCoord = vec2(texCoord.s, 1-texCoord.t);

My fragment shader:

#version 330 core

in vec2 TexCoord;

out vec4 color; 

uniform sampler2D sliceTexture;

void main()
    vec4 texColor = texture(sliceTexture, TexCoord); 
    color = texColor;

I think this is the code needed for the blending to work. The images are generated correctly, and also applied as texture on the quads correctly. However, the quads on the front appears as completely opaque, though the generated images (even the one appearing at front) shows transparent area.

I am not sure where I am going wrong. Requesting your suggestions.

Thank you.


Details of camera class. Camera::getViewMatrix() provides view matrix.

Camera::Camera(GLFWwindow* window, glm::vec3 position, glm::vec3 worldUpDirection, GLfloat yaw, GLfloat pitch)
    :mouseSensitivity(0.25f), fov(45.0f), cameraSpeed(1.0f)
    this->position = this->originalPosition = position;
    this->worldUpDirection = worldUpDirection;
    this->yaw = this->originalYaw = yaw;
    this->pitch = this->originalPitch = pitch;


void Camera::updateCameraVectors()
    glm::mat4 yawPitchRotMat;

    yawPitchRotMat = glm::rotate(yawPitchRotMat, glm::radians(yaw), glm::vec3(0.0f, 1.0f, 0.0f));       //y-ais as yaw axis
    yawPitchRotMat = glm::rotate(yawPitchRotMat, glm::radians(pitch), glm::vec3(1.0f, 0.0f, 0.0f));     //x-axis as pitch axis

    frontDirection = glm::normalize(-glm::vec3(yawPitchRotMat[2].x, yawPitchRotMat[2].y, yawPitchRotMat[2].z));

    rightDirection = glm::normalize(glm::cross(frontDirection, worldUpDirection));
    upDirection = glm::normalize(glm::cross(rightDirection, frontDirection));

glm::mat4 Camera::getViewMatrix()
    return glm::lookAt(position, position + frontDirection, upDirection);

And the projection matrix is given by: glm::perspective(glm::radians(camera.fov), Width / Height, 0.1f, 100.0f);

Update: In short, blending was working all along. I followed the advice of user1118321, tested with only 2 textures, and found that it is working. Then I understood that a good part of images appearing on front was opaque. After that it was easy. I just manipulated with the transformation function transformValueToColor, added additional threshold to make additional part of the image opaque. And that was it.


I notice that you've enabled blending and depth testing and are drawing with a non-opaque alpha channel. What's going to happen is that if you don't draw from back to front (relative to the camera), then any objects you draw that are farther away won't get drawn, so you won't see them through the nearer objects. If you turn off depth testing does it look correct?

To handle this correctly, you can also use a technique known as depth peeling.

EDIT I see how you calculate your view matrix, but I don't see any code calling it, so it's hard to say whether your camera is pointing in the right direction or not for this to work as expected.

One other thing I notice is that your projection matrix sets the near plane to 0.1, but you're translating your geometry in increments of -0.003. If your camera is at the origin (i.e. your view matrix has a translation of <0,0,0>), then you won't see any layers until you get to the 34th layer. Also, with such small increments between the layers, you may end up with Z-fighting, as well.

You might try hard-coding your loop to display just a single layer and make sure each layer is drawn correctly when drawn alone. Once you've verified that, you can figure out why drawing more than 1 layer doesn't work as expected.

| improve this answer | |
  • $\begingroup$ Thank you for your answer. I tried with disabling the depth test, it produces the same result. However, I would like to understand what do you mean by "...drawing with a non-opaque alpha channel." For opacity I am relying on alpha channel of the texture. $\endgroup$ – Sayan Pal Jul 13 '16 at 5:00
  • $\begingroup$ In setting the color of the texture in transformValueToColor(), you set the alpha value to 255 * (1 - tValue), which means that as long as tValue is not 1.0, will be somewhere between 0 and 255. An alpha value that is not 255 will produce a non-opaque (or semi-transparent) pixel - one you can see through. My point was that if the front-most geometry is semi-transparent, you must draw it after the farther away geometry or the depth test will cause the farther away geometry not to ever draw. $\endgroup$ – user1118321 Jul 13 '16 at 5:07
  • $\begingroup$ I think I am drawing the furthest quad first and the nearest one last: model = glm::translate(model, glm::vec3(0.0f, 0.0f, -index*0.003f));. I think that should have done? $\endgroup$ – Sayan Pal Jul 13 '16 at 5:25
  • $\begingroup$ It depends on the other matrices, too, though. How are your view and projection matrices set? $\endgroup$ – user1118321 Jul 13 '16 at 15:57
  • $\begingroup$ I have added the details of projection and view matrix in the question above. $\endgroup$ – Sayan Pal Jul 13 '16 at 16:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.