OpenVR's qt_pyside demo fails to run my GLSL program, but QT and PyGame run fine?

I recently started down the path to learning how to write OpenGL GLSL programs. I have been focused on writing a program that will run using PyOpenVR (using my HTC Vive).

What I am attempting to do is draw a pointclound in 3D(VR) space with more than 2500 verts. And I have been successful at using OpenVR and creating a small number of verts by using Uniform variables in my GLSL that had explicit locations (but that was a bad idea as I couldn’t address more than 300 vertices and ran out locations quickly). However it did work in OpenVR and I could see up to ~300 verts in 3D through my Vive HMD (which was really cool!!).

Now I want to use a VBO and increase the number of verts that I can animate.

Using OpenVR’s hello_qt_controllers.py example and calling my script from it I have hit a stopping point (which is only a problem when using OpenVR’s example) where I can not figure out why my GLSL program refuses to accept input for a VBO and gives a 1282 error when

glVertexAttribPointer()

is called:


OpenGL.error.GLError: GLError(
    err = 1282,
    description = 'invalid operation',
    baseOperation = glVertexAttribPointer,
    pyArgs = (
        0,
        3,
        GL_FLOAT,
        GL_FALSE,
        0,
        c_void_p(None),
    ),

However I have verified that my GLSL program is working and that I am updating the VBO data. I accomplished this by simply rendering everything to different Python modules (eg. PyGame and PyQt4). Both work perfectly (without OpenVR).

Here are those examples:

Using PyGame:
[ATTACH=CONFIG]1462[/ATTACH]

color_cube_actor.py


#!/bin/env python
# coding: utf-8

import time
import numpy as np
from textwrap import dedent

from OpenGL.GL import *
from OpenGL.GL.shaders import compileShader, compileProgram

import pygame
from pygame.locals import *

projection_default = np.array([#the matrix generated captured while using HTC Vive
    [ 0.75752085,  0.        ,  0.        ,  0.],
    [ 0.        ,  0.68160856,  0.        ,  0.],
    [ 0.05516453, -0.00299519, -1.00040019, -1.],
    [ 0.        ,  0.        , -0.20008004,  0.]
])
modelview_default = np.array([#the matrix generated captured while using HTC Vive
    [ 0.99030989,  0.04490654,  0.13141415,  0.],
    [-0.01430531,  0.9742285 , -0.22510922,  0.],
    [-0.13813627,  0.22104797,  0.9654305 ,  0.],
    [-0.12975544, -0.9294402 , -1.06236947,  1.]
])

class ColorCubeActor(object):
    array_size = 100

    def __init__(self):
        self.buffers=None
        self.shader=None

        self.vertices = self.get_vertices().astype(np.float32)
        self.colors = np.tile(np.array([0.0, 1.0, 0.0]), (self.array_size,1)).astype(np.float32) #a bunch of green vertices
        self.indices = np.arange(self.array_size).astype(np.uint32)

    def init_gl2(self):
        ##############################################################################
        # OpenGL funcs
        ##############################################################################

        glEnable(GL_VERTEX_PROGRAM_POINT_SIZE) #allow the program to specify the point size

        vertex_shader = compileShader(dedent('''
            #version 450 core

            uniform mat4 Projection = mat4(1);
            uniform mat4 ModelView = mat4(1);

            layout(location = 0) in vec3 ptPosition; //How do I get Numpy data into this array???

            out vec3 _color;

            void main() {
                _color = vec3(0,1,0);
                gl_Position = Projection * ModelView * vec4(ptPosition,1.0);

                vec3 ndc = gl_Position.xyz / gl_Position.w ; // perspective divide.
                float zDist = 1.0-ndc.z ; // 1 is close (right up in your face,)
                // 0 is far (at the far plane)
                gl_PointSize = 25*zDist ; // between 0 and 50 now.
            }
            '''), GL_VERTEX_SHADER)
        fragment_shader = compileShader(dedent('''
            #version 450 core

            in vec3 _color;
            out vec4 FragColor;

            void main() {
                FragColor = vec4(_color, 1.0);
            }
            '''), GL_FRAGMENT_SHADER)
        self.shader = compileProgram(vertex_shader, fragment_shader)

        self.create_vbo()


    def init_gl(self):
        ##############################################################################
        # OpenGL funcs
        ##############################################################################

        glEnable(GL_VERTEX_PROGRAM_POINT_SIZE) #allow the program to specify the point size

        vertex_shader = compileShader(dedent('''
            #version 120

            uniform mat4 Projection = mat4(1);
            uniform mat4 ModelView = mat4(1);

            varying out vec4 _color;

            void main() {
                _color = gl_Color;
                gl_Position =  Projection * ModelView * gl_ModelViewProjectionMatrix * gl_Vertex;

                vec3 ndc = gl_Position.xyz / gl_Position.w ; // perspective divide.
                float zDist = 1.0-ndc.z ; // 1 is close (right up in your face,)
                // 0 is far (at the far plane)
                gl_PointSize = 25*zDist ; // between 0 and 50 now.
            }
            '''), GL_VERTEX_SHADER)
        fragment_shader = compileShader(dedent('''
            #version 120

            in vec4 _color;

            void main() {
                gl_FragColor = _color;
            }
            '''), GL_FRAGMENT_SHADER)
        self.shader = compileProgram(vertex_shader, fragment_shader)

        self.create_vbo()

    def display_gl(self, modelview=modelview_default, projection=projection_default):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        self.setPoints(modelview, projection)
        glFlush()

    def get_vertices(self):
        ##############################################################################
        # vertices
        ##############################################################################
        scale = 0.15
        theta = np.linspace(-4 * np.pi, 4 * np.pi, self.array_size)
        z = np.linspace(-2, 2, self.array_size)
        r = z**2 + 1
        x = r * np.sin(theta)
        y = r * np.cos(theta)
        return np.dstack((x,y,z)) * scale

    def create_vbo(self):
        self.buffers = glGenBuffers(3)

        glBindBuffer(GL_ARRAY_BUFFER, self.buffers[0])
        assert self.vertices.dtype == np.float32
        glBufferData(GL_ARRAY_BUFFER,
                self.vertices.nbytes,  # byte size
                (ctypes.c_float*len(self.vertices.flat))(*self.vertices.flat),
                GL_STREAM_DRAW)

        glBindBuffer(GL_ARRAY_BUFFER, self.buffers[1])
        assert self.colors.dtype == np.float32
        glBufferData(GL_ARRAY_BUFFER,
                self.colors.nbytes, # byte size
                (ctypes.c_float*len(self.colors.flat))(*self.colors.flat),
                GL_STATIC_DRAW)

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.buffers[2])
        assert self.indices.dtype == np.uint32
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                self.indices.nbytes, # byte size
                (ctypes.c_uint*len(self.indices.flat))(*self.indices.flat),
                GL_STATIC_DRAW)

    def draw_vbo(self):#ONLY WORKS WITH PyGame - QT CRAHES HERE
        glBindBuffer(GL_ARRAY_BUFFER, self.buffers[0]) #GL_ARRAY_BUFFER is the buffer type we use to feed attributes
        ptPosition_pointer = 0#glGetAttribLocation(self.shader, "ptPosition") #get the location of attribute "ptSize" from self.program

        glVertexAttribPointer(ptPosition_pointer, 3, GL_FLOAT, GL_FALSE, 0, None)#Tell OpenGL what the array contains:
        assert self.vertices.dtype == np.float32
        glBufferData(GL_ARRAY_BUFFER, self.vertices.nbytes, (ctypes.c_float*len(self.vertices.flat))(*self.vertices.flat), GL_STREAM_DRAW) #feed the buffer, and let OpenGL know that we don't plan to
        glEnableVertexAttribArray(ptPosition_pointer) #Enable the attribute at that location

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.buffers[2])
        glDrawElements(GL_POINTS, len(self.indices), GL_UNSIGNED_INT, None)

    def draw_vbo2(self):#ONLY WORKS WITH PyGame - QT CRAHES HERE
        glEnableClientState(GL_VERTEX_ARRAY)
        glEnableClientState(GL_COLOR_ARRAY)

        glBindBuffer(GL_ARRAY_BUFFER, self.buffers[0])
        glVertexPointer(3, GL_FLOAT, 0, None)

        glBindBuffer(GL_ARRAY_BUFFER, self.buffers[1])
        glColorPointer(3, GL_FLOAT, 0, None)

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.buffers[2])
        glDrawElements(GL_POINTS, self.indices.size, GL_UNSIGNED_INT, None)

        glDisableClientState(GL_COLOR_ARRAY)
        glDisableClientState(GL_VERTEX_ARRAY)

    def setPoints(self, modelview, projection):
        glUseProgram(self.shader)

        self.draw_vbo()

        glUniformMatrix4fv(glGetUniformLocation(self.shader, "Projection"), 1, False, projection)
        glUniformMatrix4fv(glGetUniformLocation(self.shader, "ModelView"), 1, False, modelview)

        glUseProgram(0)

    def main(self):
        pygame.init()
        pygame.display.set_mode((800, 600), HWSURFACE|OPENGL|DOUBLEBUF)
        self.init_gl()

        yaw=0
        pitch=0
        start_time = time.time()
        while time.time() - start_time < 5: #5 second animation

            glClear(GL_COLOR_BUFFER_BIT)# | GL_DEPTH_BUFFER_BIT)

            glMatrixMode(GL_MODELVIEW)
            glLoadIdentity()

            yaw+=0.39
            pitch+=0.27
            glTranslatef(0.0, 0.0, 0.0)
            glRotatef(yaw, 0, 1, 0)
            glRotatef(pitch, 1, 0, 0)

            self.display_gl()
            pygame.display.flip()

##############################################################################
if __name__ == '__main__':#Use PyGame Window To Render OpenGL
    t = ColorCubeActor()
    t.main()

Using PyQt4:
[ATTACH=CONFIG]1463[/ATTACH]

qt_app.py


from PyQt4 import QtGui
from PyQt4.QtOpenGL import *

from color_cube_actor import ColorCubeActor

class MainWindow(QtGui.QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.widget = glWidget(self)
        self.button = QtGui.QPushButton('HELP!', self)

        mainLayout = QtGui.QHBoxLayout()
        mainLayout.addWidget(self.widget)
        mainLayout.addWidget(self.button)

        self.setLayout(mainLayout)

class glWidget(QGLWidget):

    def __init__(self, parent):
        QGLWidget.__init__(self, parent)
        self.setMinimumSize(640, 480)
        self.actor = ColorCubeActor()

    def paintGL(self):
        self.actor.display_gl()
    def initializeGL(self):
        self.actor.init_gl2()

if __name__ == '__main__':
    app = QtGui.QApplication(['OpenGL Test'])
    window = MainWindow()
    window.show()
    app.exec_()

Both of which seem to produce output and they don’t crash.

But as soon as I run hello_qt_controllers.py with my script it just crashes. Why would this be occurring? Is it possible that somewhere in OpenVR’s example app they have changed something in the gl setting which is causing a problem?

Are there other ways to buffer vertex, color, size data in OpenGL 4.5?

Also please note that I have included two GLSL programs (init_gl(), init_gl2()) in my color_cube_actor.py file. Reason is because I think in OpenVR’s example they specified

#version 450 core

for some reason, so that’s what I used. But I also wanted to try using the built-in array gl_Vertex which was depreciated in 4.5, so I created a second legacy shader which is very similar. Long story short neither worked in OpenVR.

Even though I have learned a ton about OpenGL (and I am very glad I had some time to do so) this OpenVR issue is really holding me up and I need to figure out why I can’t simply just feed a Numpy array into my GLSL program to change vertex coordinates??!!

Again I have only been writing OpenGL going on 5 days now, so I’m still a beginner. But thanks for any suggestions or help here!

[QUOTE=logic1;1286672]where I can not figure out why my GLSL program refuses to accept input for a VBO and gives a 1282 error when

glVertexAttribPointer()

is called:


OpenGL.error.GLError: GLError(
    err = 1282,
    description = 'invalid operation',
    baseOperation = glVertexAttribPointer,
    pyArgs = (
        0,
        3,
        GL_FLOAT,
        GL_FALSE,
        0,
        c_void_p(None),
    ),

[/QUOTE]

As the translation of the error here says, this is an GL_INVALID_OPERATION error. If you look up this function in the spec or a man page (e.g. glVertexAttribPointer), you’ll see the potential causes of a GL_INVALID_OPERATION error. My guess is that one of the last two is what matches your scenario:

Note that neither of these is an error if you’re using an OpenGL compatibility profile (the first is how you define client arrays – aka vertex arrays sourced from application memory, and the second – having a VAO bound at all times – is not required).