5

What can I try to solve this problem? In this example (see a screenshot below) I am using OpenGL 1.1 with deprecated functions like: glEnableClientState, glMatrixMode, glTexCoordPointer, and so on. Thanks in advance.

You can see the whole example code in this thread: https://community.khronos.org/t/window-background-visible-through-textures/109061

I draw with DEPTH_TEST:

glEnable(GL_DEPTH_TEST);

/* ... */

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Player
glBindTexture(GL_TEXTURE_2D, spriteTexture);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(playerBody->GetPosition().x * WORLD_SCALE,
                playerBody->GetPosition().y * WORLD_SCALE, 10.f);
glScalef(16.f, 16.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, drawingIndex, 4);

// Coin
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(178.f, 120.f, 10.f);
glScalef(16.f, 16.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 24, 4);

// Enemy
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(194.f, 184.f, 10.f);
glScalef(16.f, 16.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);

// Background
glBindTexture(GL_TEXTURE_2D, backgroundTexture);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.f, 0.f, 0.f);
glScalef(256.f, 216.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);

glfwSwapBuffers(window);

Texture:

enter image description here

enter image description here

Various window background values to show that I have an alpha channel:

For glClearColor(1.f, 0.f, 0.f, 1.f);

enter image description here

For glClearColor(0.2f, 0.5f, 0.3f, 1.f);

enter image description here

My Settings:

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_TEXTURE_2D);
GLuint createTexture(char *path)
{
    int h_image, w_image, cnt;

    unsigned char *data = stbi_load(path, &w_image, &h_image, &cnt, 0);

    if (data == NULL)
    {
        cout << "Failed to load an image" << endl;
        glfwTerminate();
        exit(-1);
    }

    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    {
        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_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w_image, h_image, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    }
    glBindTexture(GL_TEXTURE_2D, 0);

    stbi_image_free(data);

    return texture;
}
8Observer8
  • 868
  • 10
  • 17
  • Do not add the "solution" to the question. This makes the answer useless. – Rabbid76 Sep 11 '22 at 08:55
  • I've added some useful information that z-order matters – 8Observer8 Sep 11 '22 at 09:08
  • 1
    No. You must add solutions to an answer, but not in the question. You can add an additional answer to your own question. I already pointed out in my answer that the depth check discards fragments before they can be blended. – Rabbid76 Sep 11 '22 at 09:22

3 Answers3

6

Transparency is achieved with the alpha channel and Blending only works when the textures have an alpha channel. When the alpha channel of the transparent background is 0.0 and the alpha channel of the object is 1.0 then you can use the following blending function:

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

How can the objects be blended with the background if there is no background? You have to draw the background before you draw the objects and you don't nee the depth test at all. You must draw the object after the background. Using the depth test, fragments are discarded before they can be blended. You have to disable the depth test and draw the objects backt to front.

To render the scene you have to

  1. disable blending and disable the depth test

    glDisable(GL_DEPTH_TEST);
    glDisable(GL_BLEND);
    
  2. draw the background

  3. enable blending

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
  4. draw the objects in the scene

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • I've added screenshots to show that the texture has an alpha channel. – 8Observer8 Sep 11 '22 at 08:12
  • What is the drawing order? You need to draw the background and after the background you need to draw the objects and blend them with the background. – Rabbid76 Sep 11 '22 at 08:15
  • I've added a code to show that I draw with DEPTH_TEST. – 8Observer8 Sep 11 '22 at 08:20
  • Okay, I will try now – 8Observer8 Sep 11 '22 at 08:20
  • 1
    @8Observer8 How can the objects be blended with the background if there is no background? You have to draw the background before you draw the objects and you don't nee the depth test at all. I've added the suggestions to the answer. – Rabbid76 Sep 11 '22 at 08:23
  • Thank you very much! You solved my problem. The location on the z-axis also matters (see glTranslatef for Coin, Player and Enemy). I have added the code in the "solution" section – 8Observer8 Sep 11 '22 at 08:49
  • 1
    `you don't nee the depth test at all` - Yes, I deleted the depth test and it still works without it. And it is better because I do not need to think about Z-axis – 8Observer8 Sep 11 '22 at 14:27
0

you don't nee the depth test at all

Yes, I removed the depth test and it still works without it. And it's better because I don't have to think about the z-axis for all sprites. I can just set the Z position for all objects to 0.

Just additional information to Rabbid76's solution about the depth test. Not only the drawing order plays a role, but also the location along the z-axis. For example, this is the correct location on the z-axis: z = 0 for background, z = 5 for coin, z = 10 for enemy and z = 15 for player:

// Background
glBindTexture(GL_TEXTURE_2D, backgroundTexture);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.f, 0.f, 0.f);
glScalef(256.f, 216.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_2D, spriteTexture);

// Coin
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(178.f, 120.f, 5.f);
glScalef(16.f, 16.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 24, 4);

// Enemy
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(194.f, 184.f, 10.f);
glScalef(16.f, 16.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);

// Player
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(playerBody->GetPosition().x * WORLD_SCALE,
                playerBody->GetPosition().y * WORLD_SCALE, 15.f);
glScalef(16.f, 16.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, drawingIndex, 4);

glfwSwapBuffers(window);

enter image description here

enter image description here

Wrong order on z-axis, for example: z = 15 for coin, z = 10 for enemy and z = 5 for player:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Background
glBindTexture(GL_TEXTURE_2D, backgroundTexture);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.f, 0.f, 0.f);
glScalef(256.f, 216.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_2D, spriteTexture);

// Coin
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(178.f, 120.f, 15.f);
glScalef(16.f, 16.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 24, 4);

// Enemy
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(194.f, 184.f, 10.f);
glScalef(16.f, 16.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);

// Player
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(playerBody->GetPosition().x * WORLD_SCALE,
                playerBody->GetPosition().y * WORLD_SCALE, 5.f);
glScalef(16.f, 16.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, drawingIndex, 4);

glfwSwapBuffers(window);

enter image description here

enter image description here

8Observer8
  • 868
  • 10
  • 17
-1

I don't see where the background is visible through a texture? If you are talking about the greenish background behind the coin and mario, just use vertices that actually create the shape of the sprite. However, one issue I might see with your code is that you aren't generating a mipmap for your texture. Before you run glTexImage2D(), make sure you generate a mipmap:

glGenerateMipmap(GL_TEXTURE_2D)

Either way, I recommend not using OpenGL 1.1 - it is very deprecated and modern OpenGL is much better.

Zyfo
  • 1