Search code examples
openglglsl

Applying mix() to textures with an alpha channel results in artifacts


I have two textures: a cat and a wall, both images are loaded using QImage, have the same size(512x512), and are loaded in PNG format (QImage::Format_ARGB32).

//Load texture image
QImage imgWallTexture(":Scenes/Sc5Texture/textures/wall512x512.png");
if(imgWallTexture.isNull()) {
    qInfo("[ERROR] initScene: image texture load failed!");
    return;
}
imgWallTexture = QGLWidget::convertToGLFormat(imgWallTexture);


//Load texture image
QImage imgCatTexture(":Scenes/Sc5Texture/textures/cat512x512.png");
if(imgCatTexture.isNull()) {
    qInfo("[ERROR] initScene: image texture load failed!");
    return;
}
imgCatTexture = QGLWidget::convertToGLFormat(imgCatTexture);

//Texture ID(name)
unsigned int wallTexture = 0;
unsigned int catTexture = 0;
//Allocate 1 buffer for textures
glFunctions->glGenTextures(1, &wallTexture);
glFunctions->glGenTextures(1, &catTexture);
//Select wall texture
glFunctions->glBindTexture(GL_TEXTURE_2D, wallTexture);
//Load data to texture
glFunctions->glTexImage2D(GL_TEXTURE_2D, //selected texture type
             0, //mipmap level(we generate him using OpenGL)
             GL_RGBA, //texture data format
             imgWallTexture.width(),
             imgWallTexture.height(),
             0, //always zero
             GL_RGBA, //image format
             GL_UNSIGNED_BYTE, //image data format
             imgWallTexture.bits() //image data
            );

if(glFunctions->glGetError() != GL_NO_ERROR) {
    qInfo("[ERROR] initScene: glTexImage2D failed!");
    return;
}

//Generate mipmap for texture
glFunctions->glGenerateMipmap(GL_TEXTURE_2D);

//Setting up texture
//Texture draw
glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//Texture filtration
glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

//Select cat texture
glFunctions->glBindTexture(GL_TEXTURE_2D, catTexture);



//Select wall texture
glFunctions->glBindTexture(GL_TEXTURE_2D, catTexture);
//Load data to texture
glFunctions->glTexImage2D(GL_TEXTURE_2D, //selected texture type
             0, //mipmap level(we generate him using OpenGL)
             GL_RGBA, //texture data format
             imgCatTexture.width(),
             imgCatTexture.height(),
             0, //always zero
             GL_RGBA, //image format
             GL_UNSIGNED_BYTE, //image data format
             imgCatTexture.bits() //image data
            );

if(glFunctions->glGetError() != GL_NO_ERROR) {
    qInfo("[ERROR] initScene: glTexImage2D failed!");
    return;
}

//Generate mipmap for texture
glFunctions->glGenerateMipmap(GL_TEXTURE_2D);

//Setting up texture
//Texture draw
glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//Texture filtration
glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

//Unselect texture
glFunctions->glBindTexture(GL_TEXTURE_2D, 0);

In my fragment shader code, I use the mix() function to mix the texture.

#version 450 core
out vec4 FragColor;
in vec2 wallTexCoord;
in vec2 catTexCoord;

uniform float mixValue;

//for texture
uniform sampler2D wallTexture;
uniform sampler2D catTexture;

void main()
{
    FragColor = mix(texture(wallTexture, wallTexCoord), texture(catTexture, catTexCoord), mixValue);
}

If mixValue = 0, then I see a normal wall.

Scr when mixValue = 0

If mixValue = 1, then I see a normal cat with no artifacts.

Scr when mixValue = 1

But if the mixValue is closer to 1, then I get artifacts:

Scr when mixValue closer to 1

I thought that there were some artifacts in the pictures, but I ran both images through Photoshop to avoid internal artifacts in the image.

How do I fix this?


Solution

  • The artefacts are caused by unexpected colour data in transparent texels. An easy fix is to use premultiplied alpha.