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)
Related
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()
I am using PyOpenGl for the first time and watched this YouTube tutorial about it. Here is the video: https://www.youtube.com/watch?v=R4n4NyDG2hI&t=1464s
When I try the code however, pygame opens up and moves one frame and then it freezes and does not stop loading. I am not sure if this is because of the system that I am using or the version of python that I am using.
I have a 11-6 inch 2012 MacBook Air and am using python 2.7.15. The reason that I am using python 2 instead of python 3 is because when I try and pip3 install PyOpenGl, it gives me an error.
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
verticies = (
(1, -1, -1),
(1, 1, -1),
(-1, 1, -1),
(-1, -1, -1),
(1, -1, 1),
(1, 1, 1),
(-1, -1, 1),
(-1, 1, 1),
)
edges = (
(0,1),
(0,3),
(0,4),
(2,1),
(2,3),
(2,7),
(6,3),
(6,4),
(6,7),
(5,1),
(5,4),
(5,7),
)
def Cube():
global edges
glBegin(GL_LINES)
for edges in edges:
for vertex in edges:
glVertex3fv(verticies[vertex])
glEnd()
def main():
pygame.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(0.0, 0.0, -5)
glRotatef(20, 3, 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()
pygame.display.flip()
pygame.time.wait(10)
main()
Another thing that happens is that when I run the program, IDLE gives me this error message:
Traceback (most recent call last):
File "/Users/SplatM4n/Desktop/First3DGraphics.py", line 73, in <module>
main()
File "/Users/SplatM4n/Desktop/First3DGraphics.py", line 66, in main
Cube()
File "/Users/SplatM4n/Desktop/First3DGraphics.py", line 44, in Cube
for vertex in edges:
TypeError: 'int' object is not iterable
I also have a feeling that this is part of the problem so please any kind of help is appriciated.
Thanks, SplatM4n
As shown in the tutorial video, the rotation matrix has to be applied inside the main loop.
glTranslatef(0.0, 0.0, -5)
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glRotatef(1, 3, 1, 1)
Note, glRotatef does not only generate a rotation matrix. It also multiplies the current matrix by the new rotation matrix. This causes that the cube is continuously and progressively rotated by 1 degree in every frame.
If the glRotatef is done outside the loop, then only a single rotation is applied to the cube. After that the scene appears to be frozen.
See the example, where I applied the changes to your original application:
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
verticies = ((1, -1, -1), (1, 1, -1), (-1, 1, -1), (-1, -1, -1),
(1, -1, 1), (1, 1, 1), (-1, -1, 1), (-1, 1, 1))
edges = ((0,1), (0,3), (0,4), (2,1),(2,3), (2,7), (6,3), (6,4),(6,7), (5,1), (5,4), (5,7))
def Cube():
global edges
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(verticies[vertex])
glEnd()
def main():
pygame.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(0.0, 0.0, -5)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glRotatef(1, 3, 1, 1) # <--------------- rotate inside the main loop
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
Cube()
pygame.display.flip()
pygame.time.wait(10)
main()
Looks like this error is caused by some minor typos; your Cube() function should be as follows:
def Cube():
global edges
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(verticies[vertex])
glEnd()
Note also that the line global edges isn't required here.
Further, if the line global edges is commented out in the original code, then the function generates an exception:
UnboundLocalError: local variable 'edges' referenced before assignment
So I suspect global edges was added to suppress this error, which it does, but does not fix the root cause.
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()
I'm trying to draw some simple triangles in OpenGL.
The problem is that my triangle is always white, wheras I put some color with the glColor3f function:
def OnDraw(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glClearColor(.1, 0.1, 0.1, 1.0)
glBegin (GL_TRIANGLES)
glColor3f (1.0, 0.0, 0.0)
glVertex2f (0.25, 0.25)
glColor3f (0.0, 1.0, 0.0)
glVertex2f (0.12, 0.25)
glColor3f (0.0, 0.0, 1.0)
glVertex2f (0.25, 0.4)
glEnd()
and here is my initialization:
def InitGL(self):
# set viewing projection
glMatrixMode(GL_PROJECTION)
glFrustum(-0.5, 0.5, -0.5, 0.5, 1.0, 3.0)
# position viewer
glMatrixMode(GL_MODELVIEW)
glTranslatef(0.0, 0.0, -2.0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
Any idea?
With lighting enabled vertex colors are no longer considered for the calculations. Instead you have to set material properties. However vertex colors are quite convenient so there's a method to use vertex colors to set material properties.
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
However note that for lighting to work you must provide vertex normals otherwise things will look strange. It might be best to disable lighting for the time being.
On a different note: Please stop using old and dusted immediate mode, fixed function pipeline OpenGL. Instead learn about modern OpenGL. I recommend http://arcsynthesis.org/gltut for a start.
I solved the problem my removing:
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
Can somebody explained me why is it working now?
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.