Python – Pass data to glBufferData in PyOpenGL, blank screen

Pass data to glBufferData in PyOpenGL, blank screen… here is a solution to the problem.

Pass data to glBufferData in PyOpenGL, blank screen

I’m drawing a simple triangle using PyOpenGL. However, I only get a blank screen. I think the problem is that I am not passing the data correctly to glBufferData. I’m trying to follow this stackoverflow question The answer in the operation, but no result. Since drawing is done with glBegin() and glVertex(), shaders compile and work normally. However, drawing with glDrawElements or glDrawArrays does not work. Here is my code (I use pygame in an OpenGL window):

import numpy as np
import pygame as pg
from pygame.locals import *
from array import array
SCREEN_SIZE = (800, 600)

from OpenGL.GL import *
from OpenGL.GLU import *

def resize(width, height):

glViewport(0, 0, width, height)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(60.0, float(width)/height, .1, 1000.)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

def create_shader(shader_type,source):
    shader = glCreateShader(shader_type)
    glShaderSource(shader,source)
    glCompileShader(shader)
    print(glGetShaderiv(shader, GL_COMPILE_STATUS, None))
    return shader

pg.init()
screen = pg.display.set_mode(SCREEN_SIZE, HWSURFACE| OPENGL| DOUBLEBUF)

resize(*SCREEN_SIZE)

#creating and compiling fragment shader
fragment = create_shader(GL_FRAGMENT_SHADER,"""

#version 130

out vec4 finalColor; 

void main()
{
    finalColor = vec4(.0,0.0,1.0,1.0);
}
""")

#creating and compiling vertex shader
vertex = create_shader(GL_VERTEX_SHADER,"""

#version 130

in vec3 pos;

void main()
{   

gl_Position=gl_ProjectionMatrix*gl_ModelViewMatrix *vec4(pos,1.0);

}
""")

#create and link program
program = glCreateProgram()
glAttachShader(program, fragment)
glAttachShader(program, vertex)
glLinkProgram(program)
#get location of the position variable in vertex shader
posAttrib = glGetAttribLocation(program, "pos")

vbo=glGenBuffers(1)
ebo=glGenBuffers(1)
vao=glGenVertexArrays(1)

#specify the integer and float types to use in the glGenBuffer function
dtypei=np.dtype('<u4')
dtypef=np.dtype('<f4')

glBindVertexArray(vao)

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, np.array([0,1,2],dtype=dtypei), GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, vbo)

vert=[-1.5, -0.5, -4.0, -0.5, -0.5, -4.0, -0.5, 0.5, -4.0]
nparray = np.array(vert,dtype=dtypef)
glBufferData(GL_ARRAY_BUFFER, nparray, GL_STATIC_DRAW)

#can also try using the array library
#ar = array("f",vert)
#glBufferData(GL_ARRAY_BUFFER, ar.tostring(), GL_STATIC_DRAW)

#specify how the variable pos gets data from the buffer data
glEnableVertexAttribArray(posAttrib)
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, False, 3*4,0)

while 1:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(1.0, 1.0, 1.0, 0.0)

glUseProgram(program)
    glBindVertexArray(vao)
    #this draw function produces NOTHING
    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0)
    #can also try using glDrawArrays
    #glDrawArrays(GL_TRIANGLES, 0, 3)

#this drawing produces a triangle
    #glBegin(GL_TRIANGLES)
    #glColor3f( 0,1,0 )
    #glVertex3f( -1.5, -0.5, -4.0 )
    #glColor3f( 0,1,1 )
    #glVertex3f( -0.5, -0.5, -4.0 )
    #glColor3f( 1,1,0 )
    #glVertex3f( -0.5, 0.5, -4.0 )    
    #glEnd()

pg.display.flip()
    pg.time.delay(10)

You can uncomment glBegin()… glEnd() section, you can see that a blue triangle will be drawn so the shader works fine.

I have tried changing the variables dtypei and dtypef (corresponding to the int type and float type of the numpy array passed to glGenBuffers, respectively), but without success. The different types that can be tried are

dtypei=np.dtype('<i4')
dtypei=np.dtype('>i4')
dtypei=np.dtype('=i4')
dtypei=np.int32

dtypei=np.dtype('<u4')
dtypei=np.dtype('>u4')
dtypei=np.dtype('=u4')
dtypei=np.uint32

dtypef=np.dtype('>f4')
dtypef=np.dtype('<f4')
dtypef=np.dtype('=f4')
dtypef=np.float32

Corresponds to integer/float with different byte order (uint32, int32, and float32 may be redundant). Look at this < a href="https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.dtypes.html#arrays-dtypes-constructing" rel="noreferrer noopener nofollow">documentation I’ve also tried using array objects from the array library, and as suggested in other stackoverflow posts, nothing came of it either

I was really lost.

Solution

The problem is not with numpy data type objects, but with calling glVertexAttribPointer and glDrawElements:

glVertexAttribPointer The data type of the sixth parameter must be ctypes.c_void_p

This means that you must use ctypes.cast:

glVertexAttribPointer(posAttrib, 3, GL_FLOAT, False, 3*4, ctypes.cast(0, ctypes.c_void_p))

or none:

glVertexAttribPointer(posAttrib, 3, GL_FLOAT, False, 3*4, None)

the same goes for the 4th parameter of glDrawElements

Or

glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, ctypes.cast(0, ctypes.c_void_p))

or

glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, None)

Related Problems and Solutions