Home > Enterprise >  Transparent texture rendering in OpenGL c
Transparent texture rendering in OpenGL c

Time:05-31

I have one question. I want to render transparent texture on a black colored window in opengl c . I am able to create window, load texture and render it. But it isnt transparent when rendered. Here is my code, I cant understand what is done wrong here:

I create my window like that:

    HWND              hWnd;
    MSG               msg;
    HDC               hDC;
    HGLRC             hRC;

    WNDCLASSEX wc;
    ZeroMemory(&wc, sizeof(WNDCLASSEX));
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_DBLCLKS | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = NULL;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpszClassName = L"MainWindow";
    RegisterClassEx(&wc);

    RECT* lpRect = new RECT();
    lpRect->left = 200;
    lpRect->top = 200;
    lpRect->right = 800;
    lpRect->bottom = 800;
    hWnd = CreateWindowEx(NULL,
        L"MainWindow",
        L"Texture Rendering Practice",
        WS_POPUP | WS_VISIBLE,
        lpRect->left,
        lpRect->top,
        lpRect->right - lpRect->left,
        lpRect->bottom - lpRect->top,
        NULL,
        NULL,
        NULL,
        NULL);
    if (hWnd)
    {
        RECT rc;
        GetWindowRect(hWnd, &rc);
        app = new App(*&hWnd, rc.right - rc.left, rc.bottom - rc.top);
        InitGL(*&hWnd);

        hDC = GetDC(hWnd);
        hRC = wglCreateContext(hDC);
        wglMakeCurrent(hDC, hRC);

        ShowWindow(hWnd, SW_SHOW);
        UpdateWindow(hWnd);
    }
    else
    {
        return 0;
    }

InitGL() function looks like this(its in another class:

    int                   pf;
    HDC                   hDC;
    PIXELFORMATDESCRIPTOR pfd;

    hDC = GetDC(hWnd);

    memset(&pfd, 0, sizeof(pfd));
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 32;

    pf = ChoosePixelFormat(hDC, &pfd);

    SetPixelFormat(hDC, pf, &pfd);

    DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

    ReleaseDC(hWnd, hDC);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glShadeModel(GL_SMOOTH);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glEnable(GL_BLEND);

Then i load the texture like that:

    int w;
    int h;
    int comp;
    unsigned char* image = stbi_load("tex.png", &w, &h, &comp, STBI_rgb_alpha);

    if (image == nullptr)
        throw(std::string("Failed to load texture"));

    glGenTextures(1, &this->texName);

    glBindTexture(GL_TEXTURE_2D, this->texName);

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

    if (comp == 3)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
    else if (comp == 4)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);

    glBindTexture(GL_TEXTURE_2D, 0);

    stbi_image_free(image);

(this->texName is Gluint object holds texture address)

Then i just render the texture like that:

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_TEXTURE_2D);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
    glBindTexture(GL_TEXTURE_2D, texName);

    glBegin(GL_QUADS);

    glTexCoord2f(0.0, 0.0); glVertex3f(-0.5, 0.5, 0.1);
    glTexCoord2f(1.0, 0.0); glVertex3f(0.5, 0.5, 0.1);
    glTexCoord2f(1.0, 1.0); glVertex3f(0.5, -0.5, 0.1);
    glTexCoord2f(0.0, 1.0); glVertex3f(-0.5, -0.5, 0.1);

    glEnd();

    glDisable(GL_TEXTURE_2D);

    glFlush();

The putput looks like this:

the output

It should be just a tree on black background, because background is transparent, but it is shown white here. Btw, i checked that there is really transparent background in the image file. I would really apprecciate any help. Thank you.

CodePudding user response:

This old-style GL code is really messy to explain simply. It's based on texture stages.

Here you have a single texture stage, that takes as input the per-vertex color coming from your input. Since you don't specify actual per-vertex colors, you get the default opaque white as your incoming fragments to the texture stage 0.

GL_DECAL is for adding decals to the incoming fragments. That page has the various formulaes for each TexEnv mode, depending on the texture format.

So your output fragment color is computed with the following math:

 Cv = Cp (⁢1 - As)   Cs ⁢As
 Av = Ap

(p prefix means previous, here it's the default per-vertex color) So... With Cp = 1 and Ap = 1, You get

Cv = (1-As)   Cs As
Av = 1

Your final fragment color is actually opaque, and white where the texture is transparent, because that's what applying a decal does to an opaque input.

You really should use GL_MODULATE as your texture env mode, which is the default. That modulates the incoming white with your texture, effectively getting you, with your incoming white:

Cv = Cp Cs = Cs
Av = Ap As = As

CodePudding user response:

You need to change the mode from decal to some other mode like modulate.

//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  • Related