pythonopenglgraphicspygamepyopengl

Triangle is not shown in a PyGame window


I want to print out a triangle on the computer screen.I am using the PyGame library for the window the OpenGL library for rendering of the screen.

I have this code:

from OpenGL.GL import *
import pygame as pg
from pygame.locals import *
import numpy as np
import ctypes
from OpenGL.GL.shaders import compileProgram,compileShader


class Shape:
    def __init__(self,vertices:tuple,counter:int):
        self.shapeid:int = len(vertices)/6
        self.vertices = np.array(vertices,dtype=np.float32)
        self.vao = glGenVertexArrays(counter)
        glBindVertexArray(self.vao)
        self.vbo = glGenBuffers(counter)
        glBindBuffer(GL_ARRAY_BUFFER,self.vbo)
        glBufferData(GL_ARRAY_BUFFER,self.vertices.nbytes,self.vertices,GL_STATIC_DRAW)
        glEnableVertexAttribArray(0)
        glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,24,ctypes.c_void_p(0))
        glEnableVertexAttribArray(1)
        glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,24,ctypes.c_void_p(12))


class Window:
    shapes:list[Shape] = []

    def __init__(self,width:int,height:int):
        display = (width,height)
        pg.display.set_mode(display,DOUBLEBUF|OPENGL)
        glClearColor(1.0,0.0,0.0,1)
        self.shader = self.createShader("Shaders/vertex.txt","Shaders/fragment.txt")
        glUseProgram(self.shader)

    def loop(self):
        while True:
            for event in pg.event.get():
                if event.type==pg.QUIT:
                    pg.quit()
                    quit()

            glUseProgram(self.shader)

            for i in self.shapes:
                glBindVertexArray(i.vao)
                glDrawArrays(GL_LINES,0,3)

    def createShader(self,vertexShederFileName:str,fragmentShederFileName:str):
        with open(vertexShederFileName,'r') as v:
            vertex_src = v.readlines()

        with open(fragmentShederFileName,'r') as f:
            fragment_src = f.readlines()

        shader = compileProgram(compileShader(vertex_src,GL_VERTEX_SHADER),compileShader(fragment_src,GL_FRAGMENT_SHADER))
        return shader

    def addShape(self,shape:Shape):
        self.shapes  = self.shapes + [shape]


pg.init()
win = Window(720,360)

triangle = (0.0,0.0,0.0,1.0,1.0,1.0,
            1.0,0.0,0.0,1.0,1.0,1.0,
            0.0,1.0,0.0,1.0,1.0,1.0
            )

shape2 = Shape(triangle,1)
win.addShape(shape2)
win.loop()

and the shaders are available from the answer of one my last question:

https://stackoverflow.com/a/77428974/22864242

So lets analyze the code a little bit:

In the Shape class I just create the VertexBufferObject and the VertexArrayBufferObject then I bind them.

In the Window class the display is initialized from the PyGame library then we initialize the shader for the rendering of the Window and what was expectable is the screen to print out a triangle.

Lets take a closer look on the triangle:It is made of 18 points which is correct since stride = 6 and 18/6 = 3.The color of the triangle should be white because I set the last 3 floating numbers to (1.0,1.0,1.0) which is the RGB value of (255,255,255).So I dont see any reason why it shouldnt print out a white triangle.

What am I doing wrong?


Solution

    1. You're using the wrong Primitive type. Use GL_LINE_LOOP instead of GL_LINES.
    2. The display needs to be updated with pygame.dispaly.flip()
    3. As the scene is redrawn in every frame, you should also clear the display before drawing.
    while True:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                pg.quit()
                quit()
    
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    
        glUseProgram(self.shader)
        for i in self.shapes:
            glBindVertexArray(i.vao)
            glDrawArrays(GL_LINES, 0, 3)
    
        pg.display.flip()