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.
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//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;
//translate
model = glm::translate(model, glm::vec3(0.0f, 0.0f, -index*0.003f));
//scale
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);
}
}
}
transformValueToColor
for 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.
Edit
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;
updateCameraVectors();
}
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.