PDA

View Full Version : Need help passing array buffers to GLSL program (using PyOpenGL)??



logic1
04-10-2017, 04:48 AM
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:
2359

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!!

GClements
04-10-2017, 06:18 AM
self.sizes = np.ones(self.array_size)*10
...
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:


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).

logic1
04-10-2017, 03:46 PM
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.

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()