1

This is what I'm doing:

  • Render the first image using a color of: glColor4f(1.0, 1.0, 1.0, 1.0);
  • Render the second image, using a color of: glColor4f(1.0, 1.0, 1.0, calc);. calc is a number that goes from 0.0 to 1.0 within a second, and I can verify that it does actually do this.

What I expect it to do is to fade from one image to the other, and it does this, but halfway through, it goes into some kind of shade of grey (black is the background color, btw). You can see the issue here: http://www.youtube.com/watch?v=8dZXiYIM43s&feature=youtu.be .

I just want the basic fade, WITHOUT the greyish tone when in the middle of fading (which is the strongest at 0.5 opacity). I've tried doing this with GIMP, bottom layer is opaque, top layer is variable opacity, and it works fine, it does exactly what I want it to do, I just don't know why my code (or OpenGL) won't do the same. A video demonstrating what I mean: http://www.youtube.com/watch?v=Ym-VPu9hhjQ&feature=youtu.be

EDIT: After a bit of experimentation (changing the background color to red), at 0.5, it becomes translucent, which would normally be the effect wanted, except that BOTH texture are translucent (not just the one on top). Why does this happen??

Here is the code:

void Sprite::render_single(Image* image, Pos2D pos, Angle angle) {
        int cx = image->width / 2;
        int cy = image->height / 2;
        glPushMatrix();
        glTranslatef(pos.x + cx, pos.y + cy, 0);
        glRotatef(angle.to_degrees(), 0.0, 0.0, 1.0);
        glTranslatef(-cx, -cy, 0);
        image->bind();
        glBegin(GL_QUADS);
                glTexCoord2f(0.0, 0.0);
                glVertex2f(0.0, 0.0);
                glTexCoord2f(1.0, 0.0);
                glVertex2f(image->width, 0.0);
                glTexCoord2f(1.0, 1.0);
                glVertex2f(image->width, image->height);
                glTexCoord2f(0.0, 1.0);
                glVertex2f(0.0, image->height);
        glEnd();
        image->unbind();
        glPopMatrix();
}

void Sprite::render(Pos2D pos, Angle angle) {
        Image* img = this->get_current_frame();
        if (this->images.size() == 1) {
                this->render_single(img, pos, angle);
                return;
        }
        double calc = (((double)this->current_frame_overflow) / this->frame_length);
        std::cout << calc << std::endl;
        glPushMatrix();
        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
        this->render_single(img, pos, angle);
        img = this->get_next_frame();
        glColor4f(1.0f, 1.0f, 1.0f, calc);
        this->render_single(img, pos, angle);
        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
        glPopMatrix();
}

Blend function used: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

OpenGL initialization function:

/**
 * @brief Initializes OpenGL
 */
void Game::init_gl() {
        float width = this->display->w;
        float height = this->display->h;
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(0.0, width, height, 0.0);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glDisable(GL_DEPTH_TEST);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

Also, here is the whole source code for the main loop (which contains most of the OpenGL stuff): https://github.com/MiJyn/dbab/blob/master/src/game.cpp . And the sprite: https://github.com/MiJyn/dbab/blob/master/src/sprite.cpp .

4

2 回答 2

1

When you use the glBlendFunc function (with blending enabled) the same factors are used to calculate the alpha value of the destination fragment.

This only matters if you are rendering to a texture which has an alpha channel and subsequently using that texture with blending enabled. In this case, the alpha channel of the rendered texture ends up with values between zero and one. This causes some of the background to bleed through when the texture is drawn to the back buffer.

The solution is simply to disable blending when drawing the full-screen quad. Also, you might as well remove the channel from the texture if you're not using it (use GL_RGB instead of GL_RGBA for the internal texture format).

于 2013-05-19T20:26:04.923 回答
0

Grey fringing is a side effect of not using pre-multiplied alpha.

Try using glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); to enable pre-multiplied alpha. Look up premultiplication for more information, but basically all your textures and colors need to be premultiplied. In short you go through every pixel and color and multiply the r, g and b by a. So where you would have 50% white as (1, 1, 1, 0.5), it now becomes (0.5, 0.5, 0.5, 0.5). In this case your target color will also need to be (calc, calc, calc, calc).

于 2013-05-18T14:25:06.587 回答