VBO PyOpenGL Points - python

I'm working with PyOpenGL and GLUT at the moment and just want to visualize some points on the screen with VBO.
I'm pretty new to programming with PyOpenGL, so maybe the code isn't good at all. But should work in my opinion.
But I always get just one point. Anyone an idea, why?
Thanks for helping!!
import sys
import random #for random numbers
from OpenGL.GL import * #for definition of points
from OpenGL.GLU import *
from OpenGL.GLUT import * #for visualization in a window
import numpy as np
AMOUNT = 10
DIMENSION = 3
def changePoints(points):
for i in range(0, 3*AMOUNT):
x = random.uniform(-1.0, 1.0)
points[i]= points[i]*x
print(points)
return points
def displayPoints(points):
vbo=GLuint(0) # init the Buffer in Python!
glGenBuffers(1, vbo) # generate a buffer for the vertices
glBindBuffer(GL_ARRAY_BUFFER, vbo) #bind the vertex buffer
glBufferData(GL_ARRAY_BUFFER,sys.getsizeof(points), points, GL_STREAM_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, vbo) #bind the vertex buffer
glEnableClientState(GL_VERTEX_ARRAY) # enable Vertex Array
glVertexPointer(DIMENSION, GL_FLOAT,0, ctypes.cast(0, ctypes.c_void_p))
glBindBuffer(GL_ARRAY_BUFFER, vbo) #bind the vertex buffer
glDrawArrays(GL_POINTS, 0, AMOUNT)
glDisableClientState(GL_VERTEX_ARRAY) # disable the Vertex Array
glDeleteBuffers(1, vbo)
##creates Points
def Point():
points = np.arange(AMOUNT*3)
np.ascontiguousarray(points, dtype = np.float32)
points = changePoints(points)
#Visualization
displayPoints(points)
##clears the color and depth Buffer, call Point() and swap the buffers of the current window
def display():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
Point()
glutSwapBuffers()
def main():
##initials GLUT
glutInit(sys.argv)
#sets the initial display mode (selects a RGBA mode window; selects a double buffered window; selects a window with a depth buffer)
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH)
#defines the size of the Window
glutInitWindowSize(800, 1600)
#creates a window with title
glutCreateWindow(b'Points') #!string as title is causing a error, because underneath the PyOpenGL call is an old-school C function expecting ASCII text. Solution: pass the string in byte format.
glutDisplayFunc(display) #sets the display callback for the current window.
glutMainLoop() #enters the GLUT event processing loop.
main()

If you don't use any projection matrix, then you have to set up the vertex coordinates of the points in normalized device space, which is from (-1, -1, -1) to (1, 1, 1). This volume is projected to the viewport.
To solve your issue, points has to be an array of elements with data type np.float32:
def Point():
points = np.arange(AMOUNT*3, dtype = np.float32)
points = changePoints(points)
#Visualization
displayPoints(points)
and the coordinates of the points have to be in the range [-1.0, 1.0]:
def changePoints(points):
for i in range(len(points)):
points[i] = random.uniform(-1.0, 1.0)
print(points)
return points

Related

Rendering cube with pyopengl using tkinter frame

Am trying to render cube with tkinter frame opengl.
But I don't know where the problem lies the cube didn't show expect 2 lines.
Check my code
Pls can you help me write the code and do you have any PDF to teach me opengl I can't find much resources online
import tkinter as tk
from OpenGL.GL import *
from pyopengltk import
OpenGLFrame
cubeVertices =
((1,1,1),(1,1,-1),
(1,-1,-1),(1,-1,1),.
(-1,1,1),(-1,-1,-1),
(-1,-1,1),(-1,1,-1))
cubeEdges = ((0,1),.
(0,3),(0,4),(1,2),.
(1,7),(2,5),(2,3),.
(3,6),(4,6),(4,7),.
(5,6),(5,7))
classframe(OpenGLFrame):
def initgl(self):
glViewport(0,0,250,250)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0,self.width,self.height,0,-1,1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
def redraw(self):
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glPushMatrix()
glRotatef(90,0.0,1.0,0.0)
glBegin(GL_LINES)
glColor3f(0.0,1.0,0.0)
for cubeEdge in cubeEdges:
for cubeVertex in cubeEdge:
glVertex3fv(cubeVertices[cubeVertex])
glEnd()
glPopMatrix()
root = tk.Tk()
app = frame(root,width=900, height=600)
app.pack(
fill=tk.BOTH,expand=tk.YES)
app.mainloop()
You have to change the projection matrix. Since the cube has a dimension of 2x2x2 and the projection is an orthographic projection in window space, the cube will cover just 4 pixels in the window.
Change the view space and increase the distance to the near and far plane. Note, the geometry has to be in between the near and far plane, else the geometry will be clipped. For instance:
glOrtho(-10, 10, -10, 10, -10, 10)
Anyway I recommend to use Perspective projection. The projection matrix defines a 3 dimensional space (clip space) which is projected on the 2 dimensional viewport. At Perspective projection, this space is a frustum (Viewing frustum). The matrix can be set by gluPerspective. For instance:
classframe(OpenGLFrame):
def initgl(self):
glViewport(0,0,250,250)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
# glOrtho(-10, 10, -10, 10, -10, 10)
gluPerspective(90, self.width/self.height, 0.1, 10.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
The value for the near plane and the far plane have to be greater than 0.0 and the far plane has to be greater then the near plane 0 < near < far. In the above example the near plane is 0.1 and the far plane 10. When you draw the geometry, the you have to ensure, that the geometry is in between then near and the far plane (in clip space respectively in the viewing volume), else the geometry is clipped.
Use gluLookAt to define a view matrix with a point of view (0, -3, 0) that has a certain distance to the origin of the world (0, 0, 0):
classframe(OpenGLFrame):
# [...]
def redraw(self):
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
# define view matrix
glLoadIdentity()
gluLookAt(0, -3, 0, 0, 0, 0, 0, 0, 1)
glPushMatrix()
glRotatef(90,0.0,1.0,0.0)
glBegin(GL_LINES)
glColor3f(0.0,1.0,0.0)
for cubeEdge in cubeEdges:
for cubeVertex in cubeEdge:
glVertex3fv(cubeVertices[cubeVertex])
glEnd()
glPopMatrix()
What exactly are eye space coordinates?

OpenGL drawn area occupies only lower left quadrant of the available window

I only just started with OpenGL and PyOpenGL and am using tutorial code from this page https://noobtuts.com/python/opengl-introduction. However I quickly ran into the following problem: while the code successfully draws what is intended the drawing cannot occupy more than the lower left quadrant of my window. E.g. in the below I am setting the size and position of the rectangle such that it occupies the full window, as you can see in the code below I set the rectangle’s width and height to the window’s width and height and the position is 0,0 so I would expect the full window to become blue but this is not happening as you can see below. I am on Mac OS Catalina and running PyOpenGL on Python 3.
I have seen elsewhere that there is something to do with Catalina at this place: https://github.com/redeclipse/base/issues/920
and this place https://github.com/ioquake/ioq3/issues/422#issuecomment-541193050
However this is way too advanced for me to understand.
Would anyone know how that can be solved perhaps?
Thanks ahead for your help
from OpenGL import *
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
window = 0 # glut window number
width, height = 500, 400 # window size
def refresh2d(width, height):
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0.0, width, 0.0, height, 0.0, 1.0)
glMatrixMode (GL_MODELVIEW)
glLoadIdentity()
def draw_rect(x, y, width, height):
glBegin(GL_QUADS) # start drawing a rectangle
glVertex2f(x, y) # bottom left point
glVertex2f(x + width, y) # bottom right point
glVertex2f(x + width, y + height) # top right point
glVertex2f(x, y + height) # top left point
glEnd() # done drawing a rectangle
def draw(): # ondraw is called all the time
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # clear the screen
glLoadIdentity() # reset position
refresh2d(width, height) # set mode to 2d
glColor3f(0.0, 0.0, 1.0) # set color to blue
draw_rect(0, 0, 500, 400) # rect at (0, 0) with width 500, height 400
glutSwapBuffers() # important for double buffering
# initialization
glutInit() # initialize glut
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH)
glutInitWindowSize(width, height) # set window size
glutInitWindowPosition(0, 0) # set window position
window = glutCreateWindow("my first attempt") # create window with title
glutDisplayFunc(draw) # set draw function callback
glutIdleFunc(draw) # draw all the time
glutMainLoop() # start everything
However this isn't working. I am definitely getting a window where the blue rectangle occupies only the lower left quadrant.
FWIW, using glfw I'm able to get around this problem:
width = 1280
height = 1024
win = glfw.CreateWindow(width, height, "window title")
fb_width, fb_height = glfw.GetFramebufferSize(win)
glViewport(0, 0, fb_width, fb_height) # <--- this is the key line
you can install modified glut http://iihm.imag.fr/blanch/software/glut-macosx/
or you can do
glViewport(0, 0, width*2, height*2)
if you don't care about DPI

How to use multiple glViewport() and glOrtho()

I am trying to use pygame and pyopengl, in the main window i have 2 viewports
1 big map and 1 minimap (both presenting the same frame). i need both maps to rotate around a center who isnt 0,0,0 (lets say i need the center of rotation to be -130,0,60 which needs to be a constant point)
also i need 1 view to view a distance of glTranslatef(0, 0, -1000)
and the 2nd view to be glTranslatef(1, 1, -200) both distances are constant
i tried to use
gluLookAt()
glOrtho()
but it doesnt change the rotation.... around 0,0,0
or i might be using it wrong.
the code looks like this:
pygame.init()
display = (1700, 1000)
pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
gluPerspective(50, (display[0] / display[1]), 0.1, 5000)
glTranslatef(0, 0, -1000) # this is the view distance i want from map 1
while True:
##### i use this function to zoom in and out with mouse Wheel
##### also the zoom in/out zooms to 0,0,0 and i need (-130,0,60)
if move_camera_distance:
if zoom_in:
glScalef(0.8,0.8,0.8)
elif zoom_out:
glScalef(1.2, 1.2, 1.2)
move_camera_distance = False
zoom_in = False
zoom_out = False
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
###### Map 1
###### Need to rotate around (-130,0,60)
###### distance from camera need to be (0,0,-1000)
glViewport(1, 1, display[0], display[1]) # splits the screen
glCallList(obj.gl_list)
DrawBuffer(bufferObj, noPoints, noCirclePoints, noCrossPoints)
###### Map 2
###### Need to rotate around (-130,0,60)
###### distance from camera need to be (0,0,-300)
glViewport(1300, 650, 400, 400) # splits the screen
glCallList(obj.gl_list)
DrawBuffer(bufferObj, noPoints, noCirclePoints, noCrossPoints)
pygame.display.flip()
pygame.time.wait(10)
The output i get is 2 maps, both rotate around 0,0,0 both are from a distance of (0,0,-1000) and both change together if i change anything in the While loop.
thanks for help.
Note that the current matrix can be stored to the matrix stack by glPushMatrix and restored from the matrix stack by glPopMatrix. There are different matrix modes and matrix stacks (e.g. GL_MODELVIEW, GL_PROJECTION). See (glMatrixMode).
Set the projection matrix at initialization and set different modelview matrices for the different views:
glMatrxMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(50, (display[0] / display[1]), 0.1, 5000)
glMatrxMode(GL_MODELVIEW)
glLoadIdentity()
# [...]
while True:
###### Map 1
glViewport(1, 1, display[0], display[1]) # splits the screen
glPushMatrix()
glTranslatef(0, 0, -1000) # this is the view distance i want from map 1
# [...]
glPopMatrix()
###### Map 2
glViewport(1300, 650, 400, 400) # splits the screen
glPushMatrix()
glTranslatef(0, 0, -300) # this is the view distance i want from map 1
# [...]
glPopMatrix()
To rotate the model around a point, you've to:
Translate the model in that way that way, that the pivot is in the origin of the world. This is a translation by the inverse pivot vector.
Rotate the model.
Translate the rectangle in that way that the pivot is back at its original position.
In the program, this operations have t o be applied in revers order, because operations like glTranslate and glRotate define a matrix and multiply the matrix to the current matrix:
glTranslatef(-130, 0, 60);
glRotate( ... )
glTranslatef(130, 0, -60);
Do this immediately before you draw the object.

How do I read a moderngl fbo(frame buffer object) back into a numpy array?

I have one of 2 FBO's i've been using to ping pong some calculations in glsl, and I need to read the texture data (of dtype='f4') back into a numpy array for further calculations. I haven't found anything in the documentation that explains how to do this. Any help?
I create the textures with this
self.texturePing = self.ctx.texture( (width, height), 4, dtype='f4')
self.texturePong = self.ctx.texture( (width, height), 4, dtype='f4')
And I process them like this:
def render(self, time, frame_time):
self.line_texture.use(0)
self.transform['lineImg'].value = 0
for _ in range (2):
self.fbo2.use()
self.texturePing.use(1)
self.transform['prevData'].value = 1
self.process_vao.render(moderngl.TRIANGLE_STRIP)
#this rendered to texturePong
self.fbo1.use() #texture Ping
self.texturePong.use(1)
self.transform['prevData'].value = 1
self.process_vao.render(moderngl.TRIANGLE_STRIP)
#stop drawing to the fbo and draw to the screen
self.ctx.screen.use()
self.ctx.clear(1.0, 1.0, 1.0, 0.0) #might be unnecessary
#tell the canvas to use this as the final texture
self.texturePing.use(3)
self.canvas_prog['Texture'].value = 3
#bind the ping texture as the Texture in the shader
self.canvas_vao.render(moderngl.TRIANGLE_STRIP)
# this looks good but how do I read texturePong back into a numpy array??
You can read the framebuffer's content with fbo.read.
You can turn the buffer into a numpy array with np.frombuffer
Example:
raw = self.fbo1.read(components=4, dtype='f4') # RGBA, floats
buf = np.frombuffer(raw, dtype='f4')
Use glGetTexImage (or preferably glGetTextureImage) to copy the data into a buffer (from the texture you are using for your colour data).
https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetTexImage.xhtml
glGetTextureImage(textureToReadFrom, 0, GL_RGBA, GL_FLOAT, bufferSize, bufferPointer);

How to set clipping planes with opengl and pyglet

I am troubleshooting a problem with my code that if the depth value of any primitive is not zero it will not render on the screen. I suspect that it gets clipped away.
Is there an easy pythonic way to set my clipping planes in pyglet ?
This is my code so far:
import pyglet
from pyglet.gl import *
import pywavefront
from camera import FirstPersonCamera
def drawloop(win,camera):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
#glClearColor(255,255,255,255)
glLoadIdentity()
camera.draw()
pyglet.graphics.draw(2, pyglet.gl.GL_POINTS,
('v3f', (10.0, 15.0, 0.0, 30.0, 35.0, 150.0))
)
glPointSize(20.)
return pyglet.event.EVENT_HANDLED
def main():
win = pyglet.window.Window()
win.set_exclusive_mouse(True)
win.clear()
camera = FirstPersonCamera(win)
#win.event
def on_draw():
drawloop(win,camera)
def on_update(delta_time):
camera.update(delta_time)
pyglet.clock.schedule(on_update)
pyglet.app.run()
if __name__ == '__main__':
main()
I am using the FirstPersonCamera snippet from here:
https://gist.github.com/mr-linch/f6dacd2a069887a47fbc
I am troubleshooting a problem with my code that if the depth value of any primitive is not zero it will not render on the screen. I suspect that it gets clipped away.
You have to set up a projection matrix to solve the issue. Either set up an orthographic projection matrix or a perspective projection matrix.
The projection matrix describes the mapping from 3D points of the view on a scene, to 2D points on the viewport. It transforms from eye space to the clip space, and the coordinates in the clip space are transformed to the normalized device coordinates (NDC) by dividing with the w component of the clip coordinates. The NDC are in range (-1,-1,-1) to (1,1,1). Every geometry which is out of the clippspace is clipped.
At Orthographic Projection the coordinates in the view space are linearly mapped to clip space coordinates and the clip space coordinates are equal to the normalized device coordinates, because the w component is 1 (for a cartesian input coordinate).
The values for left, right, bottom, top, near and far define a box. All the geometry which is inside the volume of the box is "visible" on the viewport.
At Perspective Projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport. The eye space coordinates in the camera frustum (a truncated pyramid) are mapped to a cube (the normalized device coordinates).
To set a projection matrix the projection matrix stack has to be selected by glMatrixMode.
An orthographic projection can be set by glOrhto:
w, h = 640, 480 # default pyglet window size
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho( -w/2, w/2, -h/2, h/2, -1000.0, 1000.0) # [near, far] = [-1000, 1000]
glMatrixMode(GL_MODELVIEW)
....
An perspective projection can be set by gluPerspective:
w, h = 640, 480 # default pyglet window size
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective( 90.0, 640.0/480, 0.1, 1000.0) # fov = 90 degrees; [near, far] = [0.1, 1000]
glMatrixMode(GL_MODELVIEW)
....
I recommend to use the following coordinates, to "see" the points in both of the above cases:
e.g.:
pyglet.graphics.draw(2, pyglet.gl.GL_POINTS,
('v3f', (-50.0, -20.0, -200.0, 40.0, 20.0, -250.0)))
glPointSize(20.0)

Categories