Yuriy Leonov
Yuriy Leonov

Reputation: 494

Pyglet. OpenGL. How to draw rect in front of other based on "z" axis

Envinronment:

Python: 3.6.6
pyglet version: 1.3.2
OS(reproduced on both): Windows 10 host, Ubuntu 14.04 guest (Virtualbox without 3d acceleration)

Code:

code in github

import pyglet


class Window(pyglet.window.Window):

    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)
        self.batch = pyglet.graphics.Batch()
        self.position = [0, 0, 300.0]
        self.vertices_list = []

        # BLUE rect
        self.add_rect("blue.png", x=0, y=0, z=0)
        # RED rect
        self.add_rect("red.png", x=10, y=10, z=10)
        # Expects RED will be in front of BLUE, but it isn't
        # BLUE on top regardless of z value. I tried -10/10, etc.

        pyglet.clock.schedule_interval(self.move_red_forward, 1 / 60)

    def add_rect(self, file_name, x, y, z):
        image = pyglet.image.load(file_name)
        image_grid = pyglet.image.ImageGrid(image, 1, 1)
        texture_grid = image_grid.get_texture_sequence()
        texture_group = pyglet.graphics.TextureGroup(texture_grid)
        x_ = (texture_group.texture.width + x)
        y_ = (texture_group.texture.height + y)
        tex_coords = ('t3f', texture_grid[0].texture.tex_coords)

        vert_list = self.batch.add(
            4, pyglet.gl.GL_QUADS,
            texture_group,
            ('v3f', (x, y, z,
                     x_, y, z,
                     x_, y_, z,
                     x, y_, z)),
            tex_coords)
        self.vertices_list.append(vert_list)

    def move_red_forward(self, dt):
        # move z += 1 for all corners
        red_vertices = self.vertices_list[1].vertices
        red_vertices[2] += 1
        red_vertices[5] += 1
        red_vertices[8] += 1
        red_vertices[11] += 1

    def set_3d(self):
        width, height = self.get_size()
        pyglet.graphics.glEnable(pyglet.graphics.GL_BLEND)
        pyglet.graphics.glBlendFunc(
            pyglet.graphics.GL_SRC_ALPHA,
            pyglet.graphics.GL_ONE_MINUS_SRC_ALPHA)
        pyglet.graphics.glViewport(0, 0, width, height)
        pyglet.graphics.glMatrixMode(pyglet.graphics.GL_PROJECTION)
        pyglet.graphics.glLoadIdentity()
        pyglet.graphics.gluPerspective(90, width / height, 0.1, 6000.0)
        pyglet.graphics.glMatrixMode(pyglet.graphics.GL_MODELVIEW)
        pyglet.graphics.glLoadIdentity()
        x, y, z = self.position
        pyglet.graphics.glTranslatef(x, y, -z)

    def on_draw(self):
        self.clear()
        self.set_3d()
        self.batch.draw()


if __name__ == '__main__':
    window = Window(width=1400, height=800, caption='Pyglet', resizable=True)
    pyglet.app.run()

Issue:

part of screenshot
The blue rect is drawn in front of the red. I expect that the z axis is responsible for defining which object should be drawn in front.

Question:

How I can achieve that?
Or did I miss something in the understanding of such process?

Upvotes: 1

Views: 811

Answers (1)

Rabbid76
Rabbid76

Reputation: 210877

You have to enable the Depth Test

pyglet.graphics.glEnable(pyglet.graphics.GL_DEPTH_TEST)

Note, the default depth function is GL_LESS, this cause that a fragment is discarded, if a fragment has been drawn at the same place, and the new fragment has a depth which is greater or equal than the depth of the former fragment.

If the depth test is not enabled, then the later geometry is always drawn on top of the former.


If you want to blend the red image over the blue one, then the depth test has to be disabled and the red image has to be drawn after the blue image. For Blending the drawing order is crucial.The later object is blended to the former by the blending function (glBlendFunc) and blend equation (glBlendEquation).
Change the order of the images:

 self.add_rect("red.png", x=10, y=10, z=10) 
 self.add_rect("blue.png", x=0, y=0, z=0)

Upvotes: 2

Related Questions