Rendering cube with pyopengl using tkinter frame - python

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?

Related

Render only a part of the sphere inside the cube in OpenGL using python?

I want to render only the parts where it is inside the cube to something similar that is shown in 2 figure
my current Code to render a sphere is here
def Sphere(ball):
glPushMatrix()
sphere = gluNewQuadric()
glTranslatef(ball.pos.x,ball.pos.y,ball.pos.z) #Move to the place
glColor3fv((1,0,0)) #Put color
gluSphere(sphere, ball.radius, 16, 8) #Draw sphere
glPopMatrix()
You can define clip panes with glClipPlane. e.g.:
glEnable(GL_CLIP_PLANE0)
glClipPlane(GL_CLIP_PLANE0, [1, 0, 0, distance])
glEnable(GL_CLIP_PLANE1)
glClipPlane(GL_CLIP_PLANE1, [0, 1, 0, distance])
# [...]
See also OpenGL overlapping ugly rendering

Is there a way to display a pygame window over OpenGL?

I've been meddling around with PyOpenGL and pygame, and I managed to create an FPS-style camera object. Now I want to add a crosshairs in the middle of the screen, and potentially expand to display statistics on the sides of the window.
I've already looked into this, and it seems like you have to do some weird stuff with OpenGL like disabling depth test and changing the projection matrix, and until now none of that actually renders anything, and reduces performance.
It seems to me that it should be very easy, as all I want is something that is over everything else, and doesn't ever move. Is there really no way to tell pygame to draw over OpenGL so I can just draw two lines in the middle of the screen?
No there is no specified way to do that. Do it in OpenGL it is not that complicate.
According to your previous questions, I assume you want to do it in immediate mode using glBegin - glEnd sequences.
In the following I assume that width is the width of the window and height its height. You have to disable the depth test and back up the current matrices by glPushMatrix/glPopMatrix. Load the Identity matrix for the model view matrix and setup an orthographic projection corresponding to the window size (glOrtho):
cross_size = 100
glMatrixMode(GL_MODELVIEW)
glPushMatrix()
glLoadIdentity()
glMatrixMode(GL_PROJECTION)
glPushMatrix()
glLoadIdentity()
glOrtho(0, width, height, 0, -1, 1)
glDisable(GL_DEPTH_TEST)
glColor3ub(128, 128, 128) # color of the crosshair
glBegin(GL_LINES)
glVertex2f(width/2 - cross_size/2, height/2)
glVertex2f(width/2 + cross_size/2, height/2)
glVertex2f(width/2, height/2 - cross_size/2)
glVertex2f(width/2, height/2 + cross_size/2)
glEnd()
glEnable(GL_DEPTH_TEST)
glMatrixMode(GL_PROJECTION)
glPopMatrix()
glMatrixMode(GL_MODELVIEW)
glPopMatrix()
Ensure that 2 dimensional texturing is disabled (glDisable(GL_TEXTURE_2D))

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

openGL/Pyglet texture graphics vanish when drawing sprites

My code draws a 3D world, with a 2D set of graphics on top of it. The 3D world is made out of textured quads and the textures are generated with the following code:
textures = []
image = pyglet.image.load(os.path.join(img_dir, "magic.png"))
textures.append(image.get_texture())
glEnable(textures[-1].target)
glBindTexture(textures[-1].target, textures[-1].id)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width, image.height,
0, GL_RGBA, GL_UNSIGNED_BYTE,
image.get_image_data().get_data('RGBA',
image.width * 4))
The quads are then drawn with (the other 2 just have different coords):
glBindTexture(texture.target, texture.id)
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0); glVertex3f(4.0, -2.0, 100.0+self.clock)
glTexCoord2f(1.0, 0.0); glVertex3f(4.0, -2.0, -100.0+self.clock)
glTexCoord2f(1.0, 1.0); glVertex3f(-4.0, -2.0, -100.0+self.clock)
glTexCoord2f(0.0, 1.0); glVertex3f(-4.0, -2.0, 100.0+self.clock)
glEnd()
I have set up the correct parameters when drawing the 3D and 2D graphics, and when I draw a 2D triangle on top of the 3D quad (with the following code) everything works fine:
glBegin(GL_TRIANGLES)
glVertex3f(0.0, 10, 0.0)
glVertex3f(-10, -10, 0)
glVertex3f(10, -10, 0)
glEnd()
However, I then try to draw a sprite and the 3D quads lose their texture and are drawn as white.
self.spr=pyglet.sprite.Sprite(pyglet.image.load(os.path.join(img_dir, "largebullet.png")).get_texture())
...
self.spr.draw()
Note that there's some fog in the background
I found a solution to this, by running glDisable(texture.target) on the enabled textures after they were drawn. It's not ideal because they have to be reenabled again, but for now it works ok.
I ran into a similar problem to this, and I found that the pyglet Sprite class tends to disable everything in the OpenGL state that it sets. You must reset a lot of things each time any sprite is drawn.

Categories