Search code examples
c++openglpngtextureslighting

OpenGL import PNG darker


I'm doing a game in OpenGL for a project. I tried importing a PNG and then I use a glEnable2D function to be able to draw a GUI over my 3D game. the function is

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

}

And it works. I then have a second function that is used to return to the 3D environment. Then I have this function that draws the quad with the texture and draws it to the screen (reading also 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();
}

If I run the function has a strange behaviour. It works with the alphas but keeps darken images as long as they are closer to the bottom-right corner enter image description here

If I not comment the line that sets the glTextEnvF it actually lights the things in the right way but doesn't read Alphas anymore. How can I make the function reading also the alpha channel without applying strange lighting?


Solution

  • Note, that drawing by glBegin/glEnd sequences, the fixed function pipeline matrix stack and fixed function pipeline per vertex light model, is deprecated since decades. Read about Fixed Function Pipeline and see Vertex Specification and Shader for a state of the art way of rendering.


    Anyway, the issue is that there is no proper light at your GUI. You have 2 possibilities, either you disable the light (glDisable(GL_LIGHTING)), before drawing the GUI. Or make sure the light illuminates the GUI.

    To do so you have to ensure the the light source is in front of the GUI element, this means the light position has to be nearer to the camera then the GUI or even behind the camera.

    But that is not enough, you also have to ensure that the GUI element reflects the light. Most important for the reflection of the light is the normal vector of the surface, because the standard OpenGL Blinn-Phong light model is calcualted like this:

    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;
    

    You don't set any normal vectors at all. Since OpenGL is a state engine, the normal vector which you have set last by glNormal is still valid. When the vertex coordinate is set by glVertex, then this normal vector is associated to. This may cause arbitrary results.

    Since the GUI geometry is drawn in the xy plane of the viewport and the view space z axis points out of the viewport (in a Right-handed coordinate system), I recommend to define a normal vector, which is directed to the z axis:

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

    Of course the light position has to be proper set, to make this work. Note that the light position (GL_POSITION) and and spot direction (GL_SPOT_DIRECTION) is transformed by the current model view matrix, at the time they are set.