OpenGL 导入 PNG 变暗

OpenGL import PNG darker

我正在为一个项目在 OpenGL 中制作游戏。我尝试导入 PNG,然后使用 glEnable2D 函数在我的 3D 游戏上绘制 GUI。函数是

void glEnable2D()
{
    int vPort[4];

    glGetIntegerv(GL_VIEWPORT, vPort);

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();

    glOrtho(0, vPort[2], 0, vPort[3], -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();

}

并且有效。然后我有第二个函数,用于 return 到 3D 环境。然后我有这个函数,用纹理绘制四边形并将它绘制到屏幕上(也读取 alpha)

void drawImage(GLuint file, float x, float y, float w, float h, float angle)
{
//    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
//    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND_SRC);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glPushMatrix();
    glTranslatef(x, y, 0.0);
    glRotatef(angle, 0.0, 0.0, 1.0);

    glBindTexture(GL_TEXTURE_2D, file);


    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(x, y, 0.0f);
    glTexCoord2f(0.0, 1.0); glVertex3f(x, y + h, 0.0f);
    glTexCoord2f(1.0, 1.0); glVertex3f(x + w, y + h, 0.0f);
    glTexCoord2f(1.0, 0.0); glVertex3f(x + w, y, 0.0f);
    glEnd();

    glFlush();
    glPopMatrix();
}

如果我 运行 该函数有一个奇怪的行为。它适用于 alpha,但只要图像靠近右下角,就会使图像变暗

如果我不评论设置 glTextEnvF 的行,它实际上会以正确的方式点亮事物,但不再读取 Alphas。如何在不应用奇怪光照的情况下使函数也读取 alpha 通道?

请注意,通过 glBegin/glEnd 序列绘制、固定功能管线矩阵堆栈和每个顶点光模型的固定功能管线已被弃用数十年。 阅读 Fixed Function Pipeline and see Vertex Specification and Shader 了解最先进的渲染方式。


无论如何,问题是您的 GUI 上没有合适的灯光。您有 2 种可能性,要么在绘制 GUI 之前禁用灯光 (glDisable(GL_LIGHTING))。或者确保灯光照亮 GUI。

为此,您必须确保光源位于 GUI 元素的前面,这意味着光源位置必须更靠近相机,然后是 GUI 甚至相机后面。

但这还不够,您还必须确保 GUI 元素反射光线。对于光的反射最重要的是表面的法向量,因为标准的 OpenGL Blinn-Phong 光模型是这样计算的:

Ka ... ambient material
Kd ... difusse material
Ks ... specular material

La ... ambient light
Ld ... diffuse light
Ls ... specular light
sh ... shininess

N  ... norlmal vector 
L  ... light vector (from the vertex position to the light) 
V  ... view vector (from the vertex position to the eye)

Id    = max(dot(N, L), 0.0);

H     = normalize(V + L);
NdotH = max(dot(N, H), 0.0);
Is    = (sh + 2.0) * pow(NdotH, sh) / (2.0 * 3.14159265);

fs    = Ka*La + Id*Kd*Ld + Is*Ks*Ls;

您根本没有设置任何法向量。由于OpenGL是一个状态引擎,你最后设置的法向量glNormal is still valid. When the vertex coordinate is set by glVertex,然后这个法向量被关联到。这可能会导致任意结果。

由于 GUI 几何图形是在视口的 xy 平面上绘制的,视图 space z 轴指向视口外(在 Right-handed 坐标系中),我建议定义一个指向 z 轴的法向量:

glBegin(GL_QUADS);

glNormal3f(0.0, 0.0, 1.0);

glTexCoord2f(0.0, 0.0); glVertex3f(x, y, 0.0f);
glTexCoord2f(0.0, 1.0); glVertex3f(x, y + h, 0.0f);
glTexCoord2f(1.0, 1.0); glVertex3f(x + w, y + h, 0.0f);
glTexCoord2f(1.0, 0.0); glVertex3f(x + w, y, 0.0f);
glEnd();

当然,光的位置必须正确设置,才能完成这项工作。请注意,灯光位置 (GL_POSITION) 和光斑方向 (GL_SPOT_DIRECTION) 在设置时由当前模型视图矩阵转换。