簡體   English   中英

OpenGL c ++中的透明紋理渲染

[英]Transparent texture rendering in OpenGL c++

我有一個問題。 我想在 opengl c++ 中的黑色窗口上渲染透明紋理。 我能夠創建窗口、加載紋理並渲染它。 但是渲染時它不是透明的。 這是我的代碼,我無法理解這里做錯了什么:

我這樣創建我的窗口:

    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() 函數看起來像這樣(它在另一個類中:

    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);

然后我像這樣加載紋理:

    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 是 Gluint 對象保存紋理地址)

然后我只是像這樣渲染紋理:

    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();

putput 看起來像這樣:

輸出

它應該只是黑色背景上的一棵樹,因為背景是透明的,但這里顯示為白色。 順便說一句,我檢查了圖像文件中是否有真正透明的背景。

這種老式的 GL 代碼簡單解釋起來實在是太亂了。 它基於紋理階段。

在這里,您有一個紋理階段,它將來自輸入的每個頂點顏色作為輸入。 由於您沒有指定實際的每個頂點顏色,因此您將獲得默認的不透明白色作為紋理階段 0 的傳入片段。

GL_DECAL用於向傳入的片段添加貼花。 該頁面具有每種 TexEnv 模式的各種公式,具體取決於紋理格式。

因此,您的輸出片段顏色使用以下數學計算:

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

(p 前綴表示以前的,這里是默認的每個頂點顏色)所以......使用Cp = 1Ap = 1 ,你得到

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

您的最終片段顏色實際上是不透明的,而紋理透明的地方是白色的,因為這就是將貼花應用於不透明輸入的作用。

你真的應該使用 GL_MODULATE 作為你的紋理環境模式,這是默認的。 這會根據您的紋理調制傳入的白色,有效地讓您使用傳入的白色:

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

您需要將模式從貼花更改為其他模式,例如調制。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM