1

I have been, with pygame and pyopengl (oh and obviously Python), been trying to make a little tile-based 2D game, but I'm having trouble with the rendering using VBOs and glMultiDrawArray().

The program runs without errors, but I don't see any geometry drawn, so it's just a blank screen.

I've tried using glTranslate to see if maybe the geometry is being drawn, but I can't see it, as well as changing between using GluPerspective() and glOrthro2D(). No luck. I've pored over the code to see where it isn't working, but I have no clue what could be wrong. I'm still struggling to understand OpenGL and VBOs.

Here are the relevant bits of my code:

The Chunk class. Every chunk has its own VBO for vertices and textures (textures are currently unused)

class Chunk():

def __init__(self, position):
    self.Position = position

    self.VertexVBOId = _get_chunk_id()
    self.VertexVBO = glGenBuffers(self.VertexVBOId)
    self.TextureVBOId = _get_chunk_id()
    self.TextureVBO = glGenBuffers(self.TextureVBOId)
    
    Chunks[str(position)] = self

    self.__updateVertexArray()
   # glBindBuffer (GL_ARRAY_BUFFER, self.VertexVBO)
    #self.__updateVertexArray()


def __getvertices(self):
    vertices = []

    for x in range(self.Position.x, self.Position.x + 16):
        for y in range(self.Position.y, self.Position.y + 16):
            pos = Vector2(x, y)
            tile = GetTile(pos)
            if tile != "air":
                vertices.append(x+1)
                vertices.append(y)

                vertices.append(x+1)
                vertices.append(y+1)

                vertices.append(x)
                vertices.append(y+1)

                vertices.append(x)
                vertices.append(y)

    return vertices

def __updateVertexArray(self): #This will be called when a change is made the the chunk, as well as once initially
    print("UPDATING VERTEX ARRAY")
    vertices = self.__getvertices()
    glBindBuffer (GL_ARRAY_BUFFER, self.VertexVBOId)
    glBufferData (GL_ARRAY_BUFFER, len(vertices)*4, (c_float*len(vertices))(*vertices), GL_DYNAMIC_DRAW)

And here is the rendering loop:

def main():
    print("Started")
    pygame.init()
    global displaySize
    global SCREENSIZE
    global PIXELS_PER_TILE

    pygame.display.set_mode(displaySize, DOUBLEBUF|OPENGL)
    #gluOrtho2D(-SCREENSIZE[0]/2, SCREENSIZE[0]/2, -SCREENSIZE[1]/2, SCREENSIZE[1]/2)
    gluPerspective(180, 2, 0.1, 100)

    ... some other stuff ...

    while True:
        #Drawing 
        glClearColor(0.7, 0.7, 1, 0)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

       cameraTranslateX = (camera.Position.x % 1) * PIXELS_PER_TILE
        cameraTranslateY = (camera.Position.y % 1) * PIXELS_PER_TILE

        #Figure out which chunks to render
        botLeft = camera.Position - Vector2(SCREENSIZE[0]/2, SCREENSIZE[1]/2) + Vector2(cameraTranslateX, cameraTranslateY)
        topRight = camera.Position + Vector2(SCREENSIZE[0]/2, SCREENSIZE[1]/2) + Vector2(cameraTranslateX, cameraTranslateY)

        FirstChunkPos = (botLeft/16).floor()

        TotalChunksX = (topRight/16).ceil().x - FirstChunkPos.x
        TotalChunksY = (topRight/16).ceil().y - FirstChunkPos.y

        for x in range(TotalChunksX):
            for y in range(TotalChunksY):
                pos = Vector2(x + FirstChunkPos.x, y + FirstChunkPos.y)
                chunk = Chunks.get(str(pos))
                if not chunk:
                    chunk = Chunk(pos)

                VertexVBO = chunk.VertexVBOId

                glBindBuffer (GL_ARRAY_BUFFER, VertexVBO)
                glVertexPointer (2, GL_FLOAT, 0, None)

                TextureVBO = chunk.TextureVBOId

                glMultiDrawArrays (GL_POLYGON, vertexArrayThingy1, vertexArrayThingy2, 255)

               # glUnmapBuffer(GL_ARRAY_BUFFER,VertexVBO)

        pygame.display.flip ()
2
  • What are vertexArrayThingy1 and vertexArrayThingy2?
    – Rabbid76
    Commented May 26, 2022 at 6:49
  • Thingy1 and Thingy2 are constants. Thingy1 is a table like this [0, 4, 8, 12...], Thingy2 is a table like this: [4, 4, 4, 4] Commented May 26, 2022 at 14:24

1 Answer 1

1

The 2nd and 3rd arguments of glMultiDrawArrays are of type const GLint* and const GLsizei*. This function cannot draw from different buffers. There is no glDraw* command that can use multiple vertex buffers for drawing. All vertecx attributes must be in one and the same buffer. glMultiDrawArrays should draw different ranges from the buffer. Suppose you want to draw the following 3 attribute ranges [3:6], [18:27], [30:36]:

first = [3, 18, 30]
count = [3, 9, 6]
glMultiDrawArrays(GL_TRIANGLES, first, count, 3)

If you want to draw multiple lists of indices you have to use glMultiDrawElements and you have to create an array of pointers to arrays of indices:

import ctypes
ia1 = (GLuint * 6)(0, 1, 2, 0, 2, 3)
ia2 = (GLuint * 6)(12, 13, 14, 12, 14, 15)
counts = [6, 6]
indexPtr = (GLvoidp * 2)(ctypes.addressof(ia1), ctypes.addressof(ia2))
glMultiDrawElements(GL_TRIANGLES, counts, GL_UNSIGNED_INT, indexPtr, 2)
2
  • That helps and I'll have to switch to that, but I'm not even using the texture VBO right now. I'm only using the vertex one. Also, what exactly is an attribute range? Commented May 26, 2022 at 14:29
  • @redpenguiney2 The range of vertices you want to draw. If you have 100 vertices and you just want to draw the vertices from 30 to 60 then the vertex attribute range is [30:60].
    – Rabbid76
    Commented May 26, 2022 at 14:32

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.