0
votes

I've tried to load the same texture (which represents a gear) in two different squares, but the alpha channel of the PNG image used as texture works only for the background color meanwhile the first gear alpha part (colored like the background) cover the second one:

image
here is my display func, where I draw the squares and place the texture:

    void display(void) {
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -1.6);
    glRotatef(rotateX, 0,0,1);
    glRotatef(rotateY, 0,0,1);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, 1.0 * (GLfloat) 250 / (GLfloat) 250, 1.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glColor4f(0.0f, 0.0f, 0.0f, 0.5);
  //glDisable(GL_BLEND);

    //create first square
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(-0.5, -0.5, 0.0);
    glTexCoord2f(0.0, 1.0);
    glVertex3f(-0.5, 0.5, 0.0);
    glTexCoord2f(1.0, 1.0);
    glVertex3f(0.5, 0.5, 0.0);
    glTexCoord2f(1.0, 0.0);
    glVertex3f(0.5, -0.5, 0.0);   
    glEnd();

    //create second square
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(-1.0, 0.0, 0.0);
    glTexCoord2f(0.0, 1.0);
    glVertex3f(-1.0, 1.0, 0.0);
    glTexCoord2f(1.0, 1.0);
    glVertex3f(0.0, 1.0, 0.0);
    glTexCoord2f(1.0, 0.0);
    glVertex3f(0.0, 0.0, 0.0);   
    glEnd();
    glutSwapBuffers();
  }

EDIT: Here is my init func:

    void init(void) {
    glClearColor(1.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    int width, height;
    bool hasAlpha;
    char filename[] = "/home/alberto/Scaricati/Ruota_1-ext-int-small-32.png";
    bool success = loadPngImage(filename, width, height, hasAlpha, &textureImage);
    if (!success) {
        std::cout << "Unable to load png file" << std::endl;
        return;
    }
    std::cout << "Image loaded " << width << " " << height << " alpha " << hasAlpha << std::endl;
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, hasAlpha ? 4 : 3, width,
             height, 0, hasAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE,
             textureImage);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glEnable(GL_TEXTURE_2D);
    glShadeModel(GL_FLAT);
   }

And this is the func that I use to load the png (I found this one on the net) it uses libpng:

    bool loadPngImage(char *name, int &outWidth, int &outHeight, bool &outHasAlpha, GLubyte **outData) {
    png_structp png_ptr;
    png_infop info_ptr;
    unsigned int sig_read = 0;
    int color_type, interlace_type;
    FILE *fp;

    if ((fp = fopen(name, "rb")) == NULL)
        return false;

    /* Create and initialize the png_struct
    * with the desired error handler
    * functions.  If you want to use the
    * default stderr and longjump method,
    * you can supply NULL for the last
    * three parameters.  We also supply the
    * the compiler header file version, so
    * that we know if the application
    * was compiled with a compatible version
    * of the library.  REQUIRED
    */
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                 NULL, NULL, NULL);

    if (png_ptr == NULL) {
        fclose(fp);
        return false;
    }

    /* Allocate/initialize the memory
    * for image information.  REQUIRED. */
    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        fclose(fp);
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return false;
    }

    /* Set error handling if you are
    * using the setjmp/longjmp method
    * (this is the normal method of
    * doing things with libpng).
    * REQUIRED unless you  set up
    * your own error handlers in
    * the png_create_read_struct()
    * earlier.
    */
    if (setjmp(png_jmpbuf(png_ptr))) {
    /* Free all of the memory associated
     * with the png_ptr and info_ptr */
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        fclose(fp);
    /* If we get here, we had a
     * problem reading the file */
        return false;
    }

    /* Set up the output control if
    * you are using standard C streams */
    png_init_io(png_ptr, fp);

    /* If we have already
    * read some of the signature */
    png_set_sig_bytes(png_ptr, sig_read);

    /*
    * If you have enough memory to read
    * in the entire image at once, and
    * you need to specify only
    * transforms that can be controlled
    * with one of the PNG_TRANSFORM_*
    * bits (this presently excludes
    * dithering, filling, setting
    * background, and doing gamma
    * adjustment), then you can read the
    * entire image (including pixels)
    * into the info structure with this
    * call
    *
    * PNG_TRANSFORM_STRIP_16 |
    * PNG_TRANSFORM_PACKING  forces 8 bit
    * PNG_TRANSFORM_EXPAND forces to
    *  expand a palette into RGB
    */
    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);

    png_uint_32 width, height;
    int bit_depth;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
             &interlace_type, NULL, NULL);
    outWidth = width;
    outHeight = height;

    unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr);
    *outData = (unsigned char*) malloc(row_bytes * outHeight);

    png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);

    for (int i = 0; i < outHeight; i++) {
    // note that png is ordered top to
    // bottom, but OpenGL expect it bottom to top
    // so the order or swapped
        memcpy(*outData+(row_bytes * (outHeight-1-i)), row_pointers[i], row_bytes);
    }

    /* Clean up after the read,
    * and free any memory allocated */
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    /* Close the file */
    fclose(fp);

    /* That's it */
    return true;
}
1
Can you show us the code where you set the texture environment & parameters?Drew Hall

1 Answers

1
votes

The main problem I see is that you draw both quads at the same depth, with depth testing enabled. Since the default value for the depth comparison function is GL_LESS (which is typically a good value), the depth test will eliminate the part of the second quad where it overlaps the first one.

To fix this, you will need to move the second quad closer to the viewer. In general, with the kind of blending you are using, the objects that have transparency need to be sorted, and rendered back to front.

It's not entirely clear from your code how your transformations are set up. With the most common transformation setup, the z-axis points out of the screen, which means that larger z values bring the geometry closer to the viewer. If that applies to your setup, this should work as expected if you change the rendering of the second quad to:

//create second square
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, 0.0f, 0.1f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.1f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(0.0f, 1.0f, 0.1f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.1f);   
glEnd();

If this does not work, try using -0.1f instead of 0.1f.

I wrote a more detailed explanation of various options for transparency rendering in an answer to a similar question here: OpenGL ES2 Alpha test problems.