[英]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 = 1
和Ap = 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.