OpenGL导入PNG变深

时间:2018-12-05 14:52:18

标签: c++ opengl png textures lighting

我正在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();

}

它有效。然后,我还有第二个函数,用于返回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,但只要图像靠近右下角,就可以使图像变暗 enter image description here

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

1 个答案:

答案 0 :(得分:1)

请注意,自几十年来,不赞成使用glBegin / glEnd序列绘制每个顶点光模型的固定功能管线矩阵堆栈和固定功能管线。 阅读有关Fixed Function Pipeline的信息,并参阅Vertex SpecificationShader了解最新的渲染方式。


无论如何,问题在于GUI上没有适当的照明。有两种可能性,即在绘制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设置的法向矢量仍然有效。当顶点坐标由glVertex设置时,此法向矢量将与之关联。这可能会导致任意结果。

由于GUI几何图形是在视口的xy平面中绘制的,并且视空间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)在设置时会由当前模型视图矩阵进行变换。