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()
Related
I have been chasing a problem between PyCairo and PangoCairo. The following code illustrates it:
import math
import cairo
import gi
gi.require_version('Pango', '1.0')
gi.require_version('PangoCairo', '1.0')
from gi.repository import Pango, PangoCairo
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 400, 400)
ctx = cairo.Context(surface)
# TOP LEFT CIRCLE
ctx.save()
ctx.arc(100.0, 100.0, 50, 0, 2 * math.pi)
ctx.set_source_rgba(0.0, 0.0, 1.0, 1.0)
ctx.set_line_width(2.0)
ctx.stroke()
ctx.restore()
# CENTER TEXT
ctx.save()
layout = PangoCairo.create_layout(ctx)
layout.set_font_description(Pango.font_description_from_string('Arial 10.0'))
layout.set_markup('<b>Foo Bar</b>', -1)
ctx.set_source_rgba(0.0, 1.0, 0.0, 1.0)
_, text_extents = layout.get_pixel_extents()
text_width, text_height = text_extents.width, text_extents.height
ctx.translate(200.0, 200.0)
ctx.translate(-text_width / 2, -text_height / 2)
ctx.move_to(0.0, 0.0)
PangoCairo.show_layout(ctx, layout)
# ctx.stroke() # WHY?
ctx.restore()
# BOTTOM RIGHT CIRCLE
ctx.save()
ctx.arc(300.0, 300.0, 50, 0, 2 * math.pi)
ctx.set_source_rgba(1.0, 0.0, 0.0, 1.0)
ctx.set_line_width(2.0)
ctx.stroke()
ctx.restore()
surface.write_to_png('test.png')
It results in the following picture:
My intention is to draw two circles and text. The line between the text and the bottom right circle is not intended to exist. I can make the line disappear by adding / uncommenting the ctx.stroke() call directly underneath PangoCairo.show_layout in the center text code block.
It works, but it does not feel right. The text does not require a line stroke. What is going wrong? Is the stroke actually required or have I made another mistake?
Try ctx.new_path() instead of ctx.stroke().
Showing the layout seems to set the current point and thus the following line_to that arc does implicitly at its beginning actually shows a line.
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()
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)
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.