Search code examples
pythonpython-3.xopenglshaderpyopengl

PyOpenGL, can not draw using two different VBO


I am having a strange problem where I am trying to use two different VBOs and using glDrawArrays(). However, both glDrawArrays() draws exactly the same figure, even though the VBO data is different

import ctypes
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)

vbo2=glGenBuffers(1)

#vao=glGenVertexArrays(1)

#glBindVertexArray(vao)

glBindBuffer(GL_ARRAY_BUFFER, vbo)
vertices=[1.5, -0.5, -4.0, 0.5, -0.5, -4.0, 0.5, 0.5, -4.0]

nparray = np.array(vertices,dtype=np.dtype('<f4'))
glBufferData(GL_ARRAY_BUFFER, nparray, GL_STATIC_DRAW)

vertices=[2., -0.5, -4.0, -0.5, -0.5, -2.0, 0.5, 0.5, -1.0]
#vertices=[1.5, -0.5, -4.0, 0.5, -0.5, -4.0, 0.5, 0.5, -4.0]
nparray = np.array(vertices,dtype=np.dtype('<f4'))
glBindBuffer(GL_ARRAY_BUFFER, vbo2)
glBufferData(GL_ARRAY_BUFFER, nparray, GL_STATIC_DRAW)

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

while 1:

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


    glUseProgram(program)
    glBindBuffer(GL_ARRAY_BUFFER, vbo)
    print('vbo 1:',glGetInteger(GL_ARRAY_BUFFER_BINDING))
    print('vbo data 1:',glGetBufferSubData(GL_ARRAY_BUFFER,0,3*3*4,None))


#    glDrawArrays(GL_TRIANGLES, 0, 3)

    glBindBuffer(GL_ARRAY_BUFFER, vbo2)
    print('vbo 2:',glGetInteger(GL_ARRAY_BUFFER_BINDING))
    print('vbo data 2:',glGetBufferSubData(GL_ARRAY_BUFFER,0,3*3*4,None))

    glDrawArrays(GL_TRIANGLES, 0, 3)


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

The important parts of the code are where I upload the data with glBufferData and the draw commands glDrawArrays. If you try to comment away one or the other glDrawArrays(), you will see that the code actually draws the exact same figure. However, I have uploaded different data to the two VBOs (as can be seen by printing the data obtained with glGetBufferSubData). This is very strange. Why are the two glDrawArrays producing the same result when the VBO data is clearly different? Is this a bug in PyOpenGL or am I missing something fundamental here?


Solution

  • It is not the bound vertex buffer object, which define an array of generic vertex attribute data, but it is the state which is stored in the default vertex array object.

    When you call glVertexAttribPointer the the array of generic vertex attribute data is defined. If at this point, an array buffer is bound, then the array definition refers to the buffer object.

    This means you have to switch the array definition, before you draw the object:

    # define an array of generic vertex attribute data which refers to "vbo" 
    glBindBuffer(GL_ARRAY_BUFFER, vbo)
    glVertexAttribPointer(posAttrib, 3, GL_FLOAT, False, 0,ctypes.cast(0, ctypes.c_void_p))
    glEnableVertexAttribArray(posAttrib)
    glDrawArrays(GL_TRIANGLES, 0, 3)
    
    # define an array of generic vertex attribute data which refers to "vbo2" 
    glBindBuffer(GL_ARRAY_BUFFER, vbo2)
    glVertexAttribPointer(posAttrib, 3, GL_FLOAT, False, 0,ctypes.cast(0, ctypes.c_void_p))
    glEnableVertexAttribArray(posAttrib)
    glDrawArrays(GL_TRIANGLES, 0, 3)
    


    As an alternative you can use 2 Vertex Array Objects:

    # vertex data 1
    vertices=[1.5, -0.5, -4.0, 0.5, -0.5, -4.0, 0.5, 0.5, -4.0]
    nparray = np.array(vertices,dtype=np.dtype('<f4'))
    vbo=glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, vbo)
    glBufferData(GL_ARRAY_BUFFER, nparray, GL_STATIC_DRAW)
    
    # vertex data 2
    vertices=[2., -0.5, -4.0, -0.5, -0.5, -2.0, 0.5, 0.5, -1.0]
    nparray = np.array(vertices,dtype=np.dtype('<f4'))
    vbo2=glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, vbo2)
    glBufferData(GL_ARRAY_BUFFER, nparray, GL_STATIC_DRAW)
    
    # vertex array object 1
    vao=glGenVertexArrays(1)
    glBindVertexArray(vao)
    glBindBuffer(GL_ARRAY_BUFFER, vbo)
    glEnableVertexAttribArray(posAttrib)
    glVertexAttribPointer(posAttrib, 3, GL_FLOAT, False, 3*4,ctypes.cast(0, ctypes.c_void_p))
    
    # vertex array object 2
    vao2=glGenVertexArrays(1)
    glBindVertexArray(vao2)
    glBindBuffer(GL_ARRAY_BUFFER, vbo2)
    glEnableVertexAttribArray(posAttrib)
    glVertexAttribPointer(posAttrib, 3, GL_FLOAT, False, 3*4,ctypes.cast(0, ctypes.c_void_p))
    
    glBindBuffer(GL_ARRAY_BUFFER, 0)
    glBindVertexArray(0)
    

    # draw vertex array 1
    glBindVertexArray(vao)
    glDrawArrays(GL_TRIANGLES, 0, 3)
    
    # draw vertex array 2
    glBindVertexArray(vao2)
    glDrawArrays(GL_TRIANGLES, 0, 3)