Need help passing array buffers to GLSL program (using PyOpenGL)??

I am trying to create a first opengl project using Python but I am very new to OpenGL. I have created this simple example which dynamically sets the color, size and places vertices while updating the vertex position for each draw event.

I did manage to get things working using Uniform inputs and it looked something like this:
[ATTACH=CONFIG]1459[/ATTACH]

Now I would like to attempt using attributes and data buffers. I have looked at an example on the web (cant post any urls…) and I have tried to modify my program according to them. However now all I get is a blank screen and I can’t figure out what I’m doing wrong?

Here is my the functional example, and I think there is possibly something wrong with the way I am using glGenBuffers and glBindBuffer but I am not very sure.

#!/bin/env python

# file color_cube_actor.py

import time
from textwrap import dedent
import numpy as np

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

import pygame
from pygame.locals import *

class ColorCubeActor(object):

    array_size = 100

    def __init__(self):
        self.program = 0
        self.scale = 0

        self.indices = np.arange(self.array_size)
        self.colors = np.tile(np.array([0.0,1.0,0.0]), (self.array_size,1)) #a bunch of green vertices
        self.sizes = np.ones(self.array_size)*10
    def init_gl(self):
        glEnable(GL_VERTEX_PROGRAM_POINT_SIZE) #allow the program to specify the point size

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

            layout(location = 0) uniform mat4 Projection = mat4(1);
            layout(location = 4) uniform mat4 ModelView = mat4(1);

            in vec3 ptPosition;
            in float ptSize;
            in vec3 ptColor;

            out vec3 _color;

            void main()
            {
                _color = ptColor; //vec3(0.2, 0.5, 1.0); //light blue
                gl_Position = Projection * ModelView * vec4(ptPosition, 1.0);

                //use normalized device coordinates to calculate the PointSize of a vertex based on it's distance from the perspective camera.
                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 = ptSize*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); //just pass a color to the vertex (results in a rectangle pixel)
            }
            """), GL_FRAGMENT_SHADER)

        self.program = compileProgram(vertex_shader, fragment_shader)

        #setup the vao and bind buffers
        self.vao = glGenVertexArrays(1)
        glBindVertexArray(self.vao)

        self.ptSize = glGenBuffers(1) #bind buffer for point sizes
        glBindBuffer(GL_ARRAY_BUFFER, self.ptSize) #GL_ARRAY_BUFFER is the buffer type we use to feed attributes
        ptSize_pointer = glGetAttribLocation(self.program, "ptSize") #get the location of attribute "ptSize" from self.program
        glBufferData(GL_ARRAY_BUFFER, self.sizes.nbytes, self.sizes, GL_STREAM_DRAW) #feed the buffer, and let OpenGL know that we don't plan to
        glEnableVertexAttribArray(ptSize_pointer) #Enable the attribute at that location
        glVertexAttribPointer(ptSize_pointer, 1, GL_FLOAT, GL_FALSE, 0, 0) #Tell OpenGL what the array contains:

        self.ptColor = glGenBuffers(1) #bind buffer for point colors
        glBindBuffer(GL_ARRAY_BUFFER, self.ptColor) #GL_ARRAY_BUFFER is the buffer type we use to feed attributes
        ptColor_pointer = glGetAttribLocation(self.program, "ptColor") #get the location of attribute "ptSize" from self.program
        glBufferData(GL_ARRAY_BUFFER, self.colors.nbytes, self.colors, GL_STREAM_DRAW) #feed the buffer, and let OpenGL know that we don't plan to
        glEnableVertexAttribArray(ptColor_pointer) #Enable the attribute at that location
        glVertexAttribPointer(ptColor_pointer, 3, GL_FLOAT, GL_FALSE, 0, 0) #Tell OpenGL what the array contains:

    def setPoints(self, modelview, projection):
        self.scale += 0.0005

        #create dataset
        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)
        plot = np.dstack((x,y,z)) * self.scale

        self.ptPosition = glGenBuffers(1) #bind buffer for positions and copy data into buffer
        glBindBuffer(GL_ARRAY_BUFFER, self.ptPosition) #GL_ARRAY_BUFFER is the buffer type we use to feed attributes
        ptPosition_pointer = glGetAttribLocation(self.program, "ptPosition") #get the location of attribute "ptSize" from self.program
        glBufferData(GL_ARRAY_BUFFER, plot.nbytes, plot, 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
        glVertexAttribPointer(ptPosition_pointer, 3, GL_FLOAT, GL_FALSE, 0, 0)#Tell OpenGL what the array contains:

        glUniformMatrix4fv(0, 1, False, projection)
        glUniformMatrix4fv(4, 1, False, modelview)

        glDrawElements(GL_POINTS, self.array_size, GL_UNSIGNED_INT, self.indices)

    def display_gl(self, modelview, projection):
        glClear(GL_COLOR_BUFFER_BIT) #| GL_DEPTH_BUFFER_BIT)
        glUseProgram(self.program)
        self.setPoints(modelview, projection)

    def dispose_gl(self):
        glDeleteProgram(self.program)
        self.program = 0

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

        projection = 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 = 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.]
        ])

        start_time = time.time()
        while time.time() - start_time < 5: #5 second animation
            self.display_gl( modelview, projection)
            pygame.display.flip()

if __name__ == '__main__':
    t = ColorCubeActor()
    t.main()

I truly hope someone can help me with figuring this out. I need to render 2500 vertices (point cloud) and I have been trying to learn OpenGL for the last 3 days now but this is a part I have really gotten hung up on.

Thanks so much!!

The glVertexAttribPointer() call tells OpenGL that the buffer contains floats, but it actually contains doubles (the default dtype for np.ones() is float64). You may run into similar issues with self.indices on 64-bit systems, as the default dtype for np.arange() will be int64 (it’s whatever matches Python’s “int” type, which is either 32-bit or 64-bit depending upon the build). The Python wrapper for glDrawElements() might convert the indices to the specified type, but glBufferData() cannot perform conversion because it doesn’t know what you’re going to do with the data.

As a matter of course, you should use np.ascontiguousarray() with a specific dtype= parameter on any arrays which you’re going to be passing to OpenGL. This will force them to the correct type, and will force views to be converted to arrays (the wrappers simply pass a pointer to the underlying buffer, so operations such as slicing and transposition will effectively be undone).

[QUOTE=GClements;1286663]
As a matter of course, you should use np.ascontiguousarray() with a specific dtype= parameter on any arrays which you’re going to be passing to OpenGL.[/QUOTE]

I have made some changes and added np.ascontiguousarray() where I believe it should go. This didn’t make much difference on my 64bit Win8.1 PC and the screen is still blank.

However I have noticed that if I change my GLSL shader so that the point’s color is static defined, for example:


void main()
{
    _color = vec3(0.2, 0.5, 1.0); //light blue
    ...
}

Then I notice a small 1px dot in the center of the screen (and can only assume that all of the vertices are piled up in the same place).

Feels like even though I am buffering data and not getting errors the attributes are always just zero valued and maybe

Am I using glBindBuffer() correctly? I call it once for each pointer and continuously for the positions pointer?


#!/bin/env python

# file color_cube_actor.py

import time
from textwrap import dedent
import numpy as np

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

import pygame
from pygame.locals import *

class ColorCubeActor(object):

    array_size = 100

    def __init__(self):
        self.program = 0
        self.scale = 0

        self.indices = np.ascontiguousarray( np.arange(self.array_size), dtype=np.int)
        self.colors = np.ascontiguousarray( np.tile(np.array([0.0,1.0,0.0]), (self.array_size,1)), dtype=np.float) #a bunch of green vertices
        self.sizes = np.ascontiguousarray( np.ones(self.array_size)*10, dtype=np.float)

    def init_gl(self):
        glEnable(GL_VERTEX_PROGRAM_POINT_SIZE) #allow the program to specify the point size

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

            layout(location = 0) uniform mat4 Projection = mat4(1);
            layout(location = 4) uniform mat4 ModelView = mat4(1);

            in vec3 ptPosition;
            in float ptSize;
            in vec3 ptColor;

            out vec3 _color;

            void main()
            {
                _color = vec3(0.2, 0.5, 1.0);//light blue     //ptColor;
                gl_Position = Projection * ModelView * vec4(ptPosition, 1.0);

                //use normalized device coordinates to calculate the PointSize of a vertex based on it's distance from the perspective camera.
    
                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 = ptSize*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); //just pass a color to the vertex (results in a rectangle pixel)
            }
            """), GL_FRAGMENT_SHADER)

        self.program = compileProgram(vertex_shader, fragment_shader)

        #setup the vao and bind buffers 
        self.vao = glGenVertexArrays(1)
        glBindVertexArray(self.vao)

        self.ptSize = glGenBuffers(1) #bind buffer for point sizes
        glBindBuffer(GL_ARRAY_BUFFER, self.ptSize) #GL_ARRAY_BUFFER is the buffer type we use to feed attributes
        ptSize_pointer = glGetAttribLocation(self.program, "ptSize") #get the location of attribute "ptSize" from self.program
        glBufferData(GL_ARRAY_BUFFER, self.sizes.nbytes, self.sizes, GL_STREAM_DRAW) #feed the buffer, and let OpenGL know that we don't plan to
        ####glEnableVertexAttribArray(ptSize_pointer) #Enable the attribute at that location
        ####glVertexAttribPointer(ptSize_pointer, 1, GL_FLOAT, GL_FALSE, 0, 0) #Tell OpenGL what the array contains:

        self.ptColor = glGenBuffers(1) #bind buffer for point colors
        glBindBuffer(GL_ARRAY_BUFFER, self.ptColor) #GL_ARRAY_BUFFER is the buffer type we use to feed attributes
        ptColor_pointer = glGetAttribLocation(self.program, "ptColor") #get the location of attribute "ptSize" from self.program
        glBufferData(GL_ARRAY_BUFFER, self.colors.nbytes, self.colors, GL_STREAM_DRAW) #feed the buffer, and let OpenGL know that we don't plan to
        ####glEnableVertexAttribArray(ptColor_pointer) #Enable the attribute at that location
        ####glVertexAttribPointer(ptColor_pointer, 3, GL_FLOAT, GL_FALSE, 0, 0) #Tell OpenGL what the array contains:

    def setPoints(self, modelview, projection):
        self.scale += 0.0005

        #create dataset
        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)
        plot = np.ascontiguousarray(np.dstack((x,y,z)) * self.scale, dtype=np.float)

        self.ptPosition = glGenBuffers(1) #bind buffer for positions and copy data into buffer
        glBindBuffer(GL_ARRAY_BUFFER, self.ptPosition) #GL_ARRAY_BUFFER is the buffer type we use to feed attributes
        ptPosition_pointer = glGetAttribLocation(self.program, "ptPosition") #get the location of attribute "ptSize" from self.program
        glBufferData(GL_ARRAY_BUFFER, plot.nbytes, plot, 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
        glVertexAttribPointer(ptPosition_pointer, 3, GL_FLOAT, GL_FALSE, 0, 0)#Tell OpenGL what the array contains:

        glUniformMatrix4fv(0, 1, False, projection)
        glUniformMatrix4fv(4, 1, False, modelview)

        glDrawElements(GL_POINTS, self.array_size, GL_UNSIGNED_INT, self.indices)

    def display_gl(self, modelview, projection):
        glClear(GL_COLOR_BUFFER_BIT) #| GL_DEPTH_BUFFER_BIT)
        glUseProgram(self.program)
        self.setPoints(modelview, projection)

    def dispose_gl(self):
        glDeleteProgram(self.program)
        self.program = 0

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

        projection = 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 = 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.]
        ])

        start_time = time.time()
        while time.time() - start_time < 5: #5 second animation
            self.display_gl( modelview, projection)
            pygame.display.flip()

if __name__ == '__main__':
    t = ColorCubeActor()
    t.main()