Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL blending creates white border around textures

I'm trying to use OpenGL (C++) to render two textures onto a rectangle. I'm having some trouble blending the two of them though.

The first image comes from a .jpg file (https://learnopengl.com/img/textures/container.jpg). This image has no alpha channel.

The second image comes from a .png file (https://learnopengl.com/img/textures/awesomeface.png) and does have an alpha channel.

The problem is when I try to blend the two images, it creates a white border around the transparent image.

I've tried a few different blending modes (as recommended by the OP in this question: Alpha blending with multiple textures leaves colored border) but none of them seem to work.

My fragment shader looks like this:

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;

// texture samplers
uniform sampler2D texture1;
uniform sampler2D texture2;

void main()
{
    // linearly interpolate between both textures
    FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.5);
}

I have depth testing enabled (doesn't seem to have any effect) and I'm using the following code for setting up my blending:

glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

This is my main render loop:

Rendering::Pipeline pipeline = Rendering::Pipeline("src/GLSL/vertex.glsl", "src/GLSL/fragment.glsl");
pipeline.load();

//                     Position,               Color,                   Texture Coord.
//                     (X Y Z)                 (R G B)                  (S T)
float vertices [32] = { 0.5f,   0.5f,   0.0f,   1.0f,   0.0f,   0.0f,   1.0f, 1.0f, // top right
                        0.5f,   -0.5f,  0.0f,   0.0f,   1.0f,   0.0f,   1.0f, 0.0f, // bottom right
                        -0.5f,  -0.5f,  0.0f,   0.0f,   0.0f,   1.0f,   0.0f, 0.0f, // bottom left
                        -0.5f,  0.5f,   0.0f,   1.0f,   1.0f,   0.0f,   0.0f, 1.0f  };// top left

unsigned int vertexIndices [6] = {  3,  2,  0,
                                    2,  1,  0   };


unsigned int vbo;
unsigned int vao;
unsigned int ebo;

glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);

glBindVertexArray(vao);

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vertexIndices), vertexIndices, GL_STATIC_DRAW);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) 0);
glEnableVertexAttribArray(0);

glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) (3 * sizeof(float)));
glEnableVertexAttribArray(1);

glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) (6 * sizeof(float)));
glEnableVertexAttribArray(2);

unsigned int texture1;
unsigned int texture2;
int width;
int height;
int numChannels;
unsigned char* data;

glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

data = stbi_load("res/jpg/container.jpg", &width, &height, &numChannels, STBI_rgb);

if (data)
{
    lTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D);
}

stbi_image_free(data);

glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

stbi_set_flip_vertically_on_load(true);

data = stbi_load("res/png/awesomeface.png", &width, &height, &numChannels, STBI_rgb_alpha);

if (data)
{
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D);
}

stbi_image_free(data);

glUseProgram(pipeline.getProgramId());
glUniform1i(glGetUniformLocation(pipeline.getProgramId(), "texture1"), 0);
glUniform1i(glGetUniformLocation(pipeline.getProgramId(), "texture2"), 1);

while (!this->mQuit)
{
    this->counter.start();

    InputProcessor::getInstance().processInputs();

    if (this->debugOverlay)
    {
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    }
    else
    {
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    }

    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture1);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, texture2);

    pipeline.use();
    glBindVertexArray(vao);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    SDL_GL_SwapWindow(this->sdlWindow);

    this->counter.stop();
    this->deltaTime = this->counter.getDelta();
}

    this->quit();

The issue is most easily observed when passing 0.5 as parameter to the mix() function in the fragment shader. When using 0.0 or 1.0 I get (as expected) only one of the textures.

like image 396
shmoo6000 Avatar asked Aug 17 '17 18:08

shmoo6000


People also ask

What is blending in OpenGL?

Blending. Blending in OpenGL is also commonly known as the technique to implement transparency within objects. Transparency is all about objects (or parts of them) not having a solid color, but having a combination of colors from the object itself and any other object behind it with varying intensity.

How to render images with different levels of transparency using OpenGL?

To render images with different levels of transparency we have to enable blending. Like most of OpenGL's functionality we can enable blending by enabling GL_BLEND : Now that we've enabled blending we need to tell OpenGL how it should actually blend.

What happens when sampling textures at their borders in OpenGL?

Note that when sampling textures at their borders, OpenGL interpolates the border values with the next repeated value of the texture (because we set its wrapping parameters to GL_REPEAT by default).

How to blend images with different levels of transparency?

To render images with different levels of transparency we have to enable blending. Like most of OpenGL's functionality we can enable blending by enabling GL_BLEND: glEnable (GL_BLEND); Now that we've enabled blending we need to tell OpenGL how it should actually blend. Blending in OpenGL happens with the following equation:


2 Answers

The problem might be with texture itself. if you probe the semitransparent texture at pixel that got cancelled by alpha near border, what RGB values are? Some editors (Photoshop profoundly) fill the transparent area with white color (or with default color) , which may cause those border during blending.

Antialising or interpolation would cause that white to creep into visible area.

I dealt not with this problem from software developer point of view, but had been ground by it more than once as content creator (it's a novice's scourge in SecondLife, for example).

like image 198
Swift - Friday Pie Avatar answered Sep 22 '22 21:09

Swift - Friday Pie


This fixed the issue for me:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);

like image 43
Paul Avatar answered Sep 19 '22 21:09

Paul