0

I'm trying to use z-buffering to order textures according to their z values. I created a simple script to do so as written below.

import pygame
import sys
from OpenGL.GL import *
from pygame.locals import *


def load_texture(path):
    surf = pygame.image.load(path)
    s = pygame.image.tostring(surf, 'RGBA')
    texID = glGenTextures(1)
    glBindTexture(GL_TEXTURE_2D, texID)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf.get_width(), surf.get_height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, s)
    glGenerateMipmap(GL_TEXTURE_2D)
    glBindTexture(GL_TEXTURE_2D, 0)
    return texID


# set pygame screen
pygame.display.init()
pygame.display.set_mode((1000, 500), OPENGL | DOUBLEBUF)
info = pygame.display.Info()

# Set up opengl parameters
glMatrixMode(GL_PROJECTION)
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

# load textures
texID = load_texture('Player1.png')
texID2 = load_texture('spr_void.png')

# create pygame clock
MAINCLOCK = pygame.time.Clock()

while True:
    # get quit event
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

    # prepare to render screen
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glEnable(GL_DEPTH_TEST)

    # draw texture 1
    glBindTexture(GL_TEXTURE_2D, texID)
    glBegin(GL_QUADS)
    glTexCoord2f(0, 1); glVertex3f(-1, -0.5, 0.2)
    glTexCoord2f(1, 1); glVertex3f(1, -0.5, 0.2)
    glTexCoord2f(1, 0); glVertex3f(1, 0.5, 0.2)
    glTexCoord2f(0, 0); glVertex3f(-1, 0.5, 0.2)
    glEnd()

    # draw texture 2
    glBindTexture(GL_TEXTURE_2D, texID2)
    glBegin(GL_QUADS)
    glTexCoord2f(0, 1); glVertex3f(-1, -1, 0.5)
    glTexCoord2f(1, 1); glVertex3f(1, -1, 0.5)
    glTexCoord2f(1, 0); glVertex3f(1, 1, 0.5)
    glTexCoord2f(0, 0); glVertex3f(-1, 1, 0.5)
    glEnd()

    # read pixels and flush
    glReadPixels(0, 0, info.current_w, info.current_h, GL_RGBA, GL_UNSIGNED_BYTE)
    glFlush()

    pygame.display.flip()
    MAINCLOCK.tick(60)

If I run the code commenting the "glEnable(GL_DEPTH_TEST)" I get the following result:

Without z buffering

As expected the second drawn image gets over the first one, even though it has a higher z value. Now, if I uncomment that line, and re-run the code, I get:

With z buffering

Although the images are ordered as expected, the top image ends up losing it's transparency. How can I obtain the right transparency behavior with z buffering activated?

PS: You can use any images of your choice to reproduce the code above, just don't forget to change the path in the code

Pedro H. Forli
  • 332
  • 2
  • 14
  • 4
    Transparency is applied after z test so if you enable z test then any pixel loosing z test will be rejected though when blending is enabled that could be problem. Hence either sort your textures before sending the to gpu keeping depth test on or disable depth test and let the blending happen or you use shader and implement som order independent transparency algorithm. – Paritosh Kulkarni Mar 24 '18 at 20:15
  • *"the top image ends up losing it's transparency"* - since blending is enabled and the depth test is disabled (in the 2nd case), the issue probably is, that the alpha channel of the 2nd image is not proper set. – Rabbid76 Mar 09 '19 at 22:57

1 Answers1

0

Transparency basically blends the current color in the color buffer with the new color you are placing (in a way dependent on glBlendFunc).

In this example you are drawing the spaceship first. The transparent edges get blended with the current pixel (which is black since nothing else has been drawn there), so the resulting color is black. The space person will not be able to change the black pixels since they still have the same Z value as the other pixels in the spaceship which is > the space person Z value.

In order to fix this issue you need to draw your scene from back to front so that the blend function works correctly.

Theo Walton
  • 1,085
  • 9
  • 24