How to get VBOs to work with Python and PyOpenGL - python

The following Python program should draw a white triangle in the upper right quadrant of the window.
import pygame
from OpenGL.GL import *
from ctypes import *
pygame.init ()
screen = pygame.display.set_mode ((800,600), pygame.OPENGL|pygame.DOUBLEBUF, 24)
glViewport (0, 0, 800, 600)
glClearColor (0.0, 0.5, 0.5, 1.0)
glEnableClientState (GL_VERTEX_ARRAY)
vertices = [ 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0 ]
vbo = glGenBuffers (1)
glBindBuffer (GL_ARRAY_BUFFER, vbo)
glBufferData (GL_ARRAY_BUFFER, len(vertices)*4, (c_float*len(vertices))(*vertices), GL_STATIC_DRAW)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
glClear (GL_COLOR_BUFFER_BIT)
glBindBuffer (GL_ARRAY_BUFFER, vbo)
glVertexPointer (3, GL_FLOAT, 0, 0)
glDrawArrays (GL_TRIANGLES, 0, 3)
pygame.display.flip ()
It won't throw any errors, but unfortunately it doesn't draw the triangle.
I also tried to submit the buffer data as a NumPy-array:
glBufferData (GL_ARRAY_BUFFER, len(vertices)*4, np.array (vertices, dtype="float32"), GL_STATIC_DRAW)
Also no triangle is drawn. PyOpenGL... Y U NO draw VBOs ?
My system: Python 2.7.3 ; OpenGL 4.2.0 ; Linux Mint Maya 64 bit

Okay, I just found it:
The 4th parameter of the glVertexPointer call must be None representing a NULL pointer
glVertexPointer (3, GL_FLOAT, 0, None)
I swear, I searched for hours last night and didn't see that.

Related

Drawing a crosshair in PyOpenGL

I have a working camera in a 3D scene in OpenGL, and I decided I want to draw a crosshair in the middle. To do that, I want to use a separate shader for the crosshair (and eventually, HUD) and the 3D scene. I managed to make something work using glDrawArrays and a VBO with the line vertices in it.
The problem with this setup is that the cross extends all the way to the borders of the window, even though I specified small coordinates so that it is just in the center of the screen.
Here are my shaders (in order, vertex shader and fragment shader):
#version 450 core
layout (location = 0) in vec2 aPos;
void main() {
gl_Position = vec4(aPos, 0, 0);
}
#version 450 core
out vec4 FragColor;
void main() {
FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
As you can see, they are extremely simple and do literally nothing with the coordinates. The drawing process looks something like this:
crosshair = np.array([
-0.02, 0,
0.02, 0,
0, -0.02,
0, 0.02], dtype = 'float32')
vbo_2d, vao_2d = glGenBuffers(1), glGenVertexArrays(1)
glBindVertexArray(vao_2d)
glBindBuffer(GL_ARRAY_BUFFER, vbo_2d)
glBufferData(GL_ARRAY_BUFFER, crosshair, GL_STATIC_DRAW)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 8, ctypes.c_void_p(0))
glEnableVertexAttribArray(0)
while not window.check_if_closed():
#render 3d stuff with another shader program and other vbos ad vaos
glBindVertexArray(0)
shader_program_2d.use()
glBindVertexArray(vao_2d)
glDrawArrays(GL_LINES, 0, 4)
#swap buffers etc.
This is what my window looks like:
Thanks in advance!
The issue is the computation of the Homogeneous clip space coordinate in the vertex shader. The normalized device space coordinate is computed by dividing the .xyz components of gl_Position by it's .w component (Perspective divide).
Since the .w component is 0, the resulting coordinates become infinite (except the coordinate itself is 0).
gl_Position = vec4(aPos, 0, 0);
gl_Position = vec4(aPos, 0, 1.0);

OPENGL Light Rotation

I am trying to set one stationary light source. In my program I have a cube which can be rotated.It seems like the light source is rotating too. But it should not
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
lightType = [-2.0, 0.0, -3.0, 1.0]
glLightfv(GL_LIGHT0, GL_POSITION, lightType)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
m = accum.get_rotation_matrix()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadMatrixf(m)
draw_cube()
UPD. Another example
def init():
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
lightType = [0, 0, 4, 1]
glLightfv(GL_LIGHT0, GL_POSITION, lightType)
glLightfv(GL_LIGHT0, GL_AMBIENT, (0, 0, 0, 0))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (0, 0, 0, 0))
glLightfv(GL_LIGHT0, GL_SPECULAR, (1, 1, 1, 1))
glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, 180)
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, (0, 0, 1, 1))
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
I expect that one part of the cube will always be lighted, but it os not: after some rotation cube is not lighted (pictures 1 and 2). I would like, for example, some part of the front face of the cube to be always lighted, regardless cube's rotation
When the light position is set, then the position is transformed by the current model view matrix (GL_MODELVIEW). See glLight and glMatrixMode.
If the position is set, before the view matrix is set (model view is the Identity matrix), then the light position is not transformed and is set in view space. Hence the light moves with the point of view and is anchored to the camera.
If you want to set the light position in world space, then you have to set the view matrix before the light position is set. Thus the the light position is transformed by the view matrix (The vie matrix transforms form world space to view space).
glMatrixMode(GL_MODELVIEW)
glLoadMatrixf(viewMatrix)
lightType = [-2.0, 0.0, -3.0, 1.0]
glLightfv(GL_LIGHT0, GL_POSITION, lightType)
glMultMatrixf(modelMatrix)
draw_cube()

pyOpenGL Far Faces Render over Close Ones

So I have a problem I have been chasing for a couple days now and I can't find anything to help. I just started to try and learn pyOpenGL and have quickly run into this issue. I hope I have included enough info, thanks for any and all help.
The Issue:
When I draw a cube it seems that some of the faces in the back are rendering over the faces in the front. This doesn't make sense to me as the back faces should be further away and would appear behind the front faces. I have a short video of the issue below. I should mention that this problem appeared to occur in the tutorial that I was following but wasn't mentioned or fixed. As I said I am a beginner at this and any help would be appreciated.
Problem Video: https://media.giphy.com/media/OT6SrDbj5NopQpD8Pt/giphy.gif
(Cube is rotating left to right)
Setup:
I am running this on Ubuntu Linux using python 2.7.15 and pyOpenGL 3.1.0 and pygame 1.9.4
Source Code:
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
colors=(
(255, 0, 0), #Red
(0, 255, 0), #Green
(0, 0, 255), #Blue
)
verts = (
(1.0, -1.0, -1.0),
(1.0, -1.0, 1.0),
(-1.0, -1.0, 1.0),
(-1.0, -1.0, -1.0),
(1.0, 1.0, -1.0),
(1.0, 1.0, 1.0),
(-1.0, 1.0, 1.0),
(-1.0, 1.0, -1.0)
)
surfaces = (
(0, 1, 2, 3),
(4, 7, 6, 5),
(0, 4, 5, 1),
(1, 5, 6, 2),
(2, 6, 7, 3),
(4, 0, 3, 7)
)
def cube_obj(faces, vertices):
glBegin(GL_QUADS)
x = 0
for face in faces:
glColor3fv(colors[x])
x += 1
if x > 2:
x = 0
for vertex in face:
glVertex3fv(vertices[vertex])
glEnd()
def main():
pygame.init()
display = (800, 600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
gluPerspective(75, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(-0.0, 0.0, -10.0)
glClearColor(1, 1, 1, 1)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
cube_obj(surfaces, verts)
glRotatef(.5, 0, 1, 0)
pygame.display.flip()
pygame.time.wait(10)
main()
You've to enable the Depth Test. The depth plane enables an test before a fragment is drawn. If the fragment doesn't pass the test ti is discarded. The default depth function (glDepthFunc) is GL_LESS. This causes that a fragment is discarded if a fragment was draw on the same place before, which has a depth which is greater or equal the depth of the new fragment. The depth is stored in the depth buffer.
To make the depth test work, you've to do 2 things:
Enable it and set the proper depth function, at the initialization of the OpenGL states:
glDepthFunc(GL_LESS) # this is default
glEnable(GL_DEPTH_TEST)
And beside the color plane, the depth plane has to be cleared too, in each frame, by (glClear) (This part you've done already):
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

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

Making a Solar System in OpenGL

I am trying to make a solar system in OpenGL but the planet is not revolving around sun. That is revolving around some other axis. How to fix this?
First, I am drawing a sun, Then, there is rotation, translation and again rotation of first planet. So it should revolve around the sun and rotate on it's own axis, but that's not happening.
I also want to make the circle on which planet will revolve. How to make the circles in XZ plane (possibly)
from __future__ import division
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
year = 0
day = 0
def init():
glClearColor (0.0, 0.0, 0.0, 0.0)
glShadeModel (GL_FLAT)
def display():
global day, year
glClear (GL_COLOR_BUFFER_BIT)
glColor3f (1.0, 1.0, 0, 1)
glPushMatrix()
glutSolidSphere(1.0, 20, 16) # draw sun
glRotatef(year, 0.0, 1.0, 0.0)
year = (year + 1) % 360
glPushMatrix()
glTranslatef(2.0, 0.0, 0.0)
glRotatef(day, 0.0, 1.0, 0.0)
day = (day + 1) % 360
glColor3f (0, 0, 1.0);
glutWireSphere(0.2, 10, 8) # draw smaller planet
glPopMatrix()
glPushMatrix()
glTranslatef(4.0, 0.0, 0.0)
glRotatef(day, 0.0, 1.0, 0.0)
glColor3f (1, 0, 0.0, 1)
glutWireSphere(0.2, 10, 8)
glPopMatrix()
glPopMatrix()
glutSwapBuffers()
# delay
for i in range(100000):
pass
def reshape(w, h):
glViewport (0, 0, w, h)
glMatrixMode (GL_PROJECTION)
glLoadIdentity ()
gluPerspective(70.0, w/h, 1.0, 20.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
glutInitWindowSize(800, 800)
glutInitWindowPosition (100, 100)
glutCreateWindow("Transformation")
init ()
glutDisplayFunc(display)
glutIdleFunc(display)
glutReshapeFunc(reshape)
glutMainLoop()
Planet should go behind the sun (invisible for some time) and then it would be visible after coming back, but that' not happening.
You have to enable the depth test and you have to clear the depth buffer.
The depth test can be enabled by glEnable(GL_DEPTH_TEST). The default depth function glDepthFunc is GL_LESS. This causes that fragments which are behind a fragment that was drawn before, are skipped:
Before every frame the depth buffer has to be cleared, by glClear(GL_DEPTH_BUFFER_BIT), to restart this process.
Add the following lines to your code, at the begin of display:
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
glEnable( GL_DEPTH_TEST )
Of coures you have to create a window with a depth buffer (glutInitDisplayMode(GLUT_DEPTH)):
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
See the preview:
Can you also tell how to make circle where the planet is revolving?
I recommend to use time for setting up the simulation. The following example shows the sun, earth and the moon (Of course it is a very very simplified simulation with completely wrong sizes and distance relations):
import time
start_time = time.time()
def display():
t = time.time() - start_time
year_period = 5.0 # 5 seconds for simulating one year
year = (t / year_period)
day = 365 * year
moon_sid = (365 / 27.3) * year
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
glEnable( GL_DEPTH_TEST )
glColor4f (1.0, 1.0, 0, 1)
glPushMatrix()
glutSolidSphere(1.0, 20, 16) # sun
glRotatef(year*360.0, 0.0, 1.0, 0.0) # earth rotation around the sun
glTranslatef(3.0, 0.0, 0.0) # earth location
glPushMatrix() # push earth system
glPushMatrix()
glRotatef(day*360.0, 0.0, 1.0, 0.0) # earth spinn
glRotatef(90-23.4, 1.0, 0.0, 0.0) # earth axis
glColor3f (0, 0, 1) # blue
glutWireSphere(0.3, 10, 8) # earth
glPopMatrix()
glPushMatrix()
glRotatef(moon_sid*360.0, 0.0, 1.0, 0.0) # moon sidereal
glTranslatef(1.0, 0.0, 0.0) # distance moon to earth
glRotatef(90, 1.0, 0.0, 0.0)
glColor4f (0.4, 0.5, 0.6, 1)
glutWireSphere(0.1, 10, 8) # moon
glPopMatrix()
glPopMatrix() # pop earth system
glPopMatrix()
glutSwapBuffers()

Categories