2D Sine Wave Example Using PyOpenGL

Here is an example of a moving 2D sine wave using Python 3, PyGame, and PyOpenGL.  See a https://blog.gahooa.com/2018/02/11/pygame-and-opengl-on-windows-10/  for how to install them.

sine

This sample program is designed to have a 100×60 unit working area with a 10 unit buffer around the edges.  You can see the axis in the lower-left (0,0) where Y+ is up, and X+ is to the right.

The structure of the program was created to make it super easy to work on the “guts” of the graphics without getting it confused with the “bookkeeping” end of OpenGL or PyGame.

Note: the glOrtho() command is how 2D “parallel perspective” is setup.  It defines the left, right, bottom, top, near plane, and far plane.  Because it is parallel, there is not the notion of a “camera” per-se, but rather section of the plane that should be viewed.  Documented here:

https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml

Here is the code!

#!/usr/bin/env python
###############################################################################
# Action Happens Here 50 times per second
def tick(i):
#glRotatef(1, 0, 0, 1)
#glTranslatef(0, 0, 1)
# Draw Axis
axis(i)
# Draw sinewave
for x in range(200):
x = x/2.0
y = math.sin(math.radians(x+i) * 10) * 30 + 30
cquad((x,y,0), 1, (y/60.0,0,x/100.0)) #(center, diameter, color)
###############################################################################
# The rest of this is the bones that make it work
import time
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.arrays import vbo
import math
FPS_TARGET = 50
def axis(i):
glBegin(GL_LINES)
#x = red
#y = green
#z = blue
glColor3f(1, 0, 0)
glVertex3fv((0, 0, 0))
glVertex3fv((1, 0, 0))
glColor3f(0, 1, 0)
glVertex3fv((0, 0, 0))
glVertex3fv((0, 1, 0))
glColor3f(0, 0, 1)
glVertex3fv((0, 0, 0))
glVertex3fv((0, 0, 1))
glEnd()
def quad(points, color):
glBegin(GL_QUADS)
glColor3f(*color)
for p in points:
glVertex3fv(p)
glEnd()
def cquad(point, size, color):
glBegin(GL_QUADS)
glColor3f(*color)
x,y,z = point
s = size/2.0
glVertex3fv((xs,ys,z))
glVertex3fv((x+s,ys,z))
glVertex3fv((x+s,y+s,z))
glVertex3fv((xs,y+s,z))
glEnd()
def main():
#initialize pygame and setup an opengl display
pygame.init()
pygame.display.set_mode((1200,800), OPENGL|DOUBLEBUF)
glEnable(GL_DEPTH_TEST) #use our zbuffer
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#setup the camera
glMatrixMode(GL_PROJECTION)
#gluPerspective(45.0,1000/1000,0.1,1000.0) #setup lens
#glOrtho(-10,10,-10,10,1,20)
glOrtho(10,110,10,70,1,1)
#glTranslatef(0, 0, -100) #move back
#glRotatef(-20, 1, 0, 0) #orbit higher
nt = int(time.time() * 1000)
for i in range(2**63):
nt += 1000//FPS_TARGET
#check for quit'n events
event = pygame.event.poll()
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
break
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
tick(i)
pygame.display.flip()
ct = int(time.time() * 1000)
pygame.time.wait(max(1,nt ct))
if i % FPS_TARGET == 0:
print(ntct)
if __name__ == '__main__': main()

view raw
sinewave.py
hosted with ❤ by GitHub

PyGame and OpenGL on Windows 10

First I went to http://www.python.org and downloaded the latest version of Python for windows.  I made sure to select the option to add it to the system path.

Then I opened windows PowerShell (just a nicer term)

py -m pip install pygame --user
py -m pip install numpy --user
py -m pip install pyopengl --user

(I also installed NoteTab++, a nice text editor)

From there, I went to github and copied one of the examples from https://github.com/pygame/pygame/blob/master/examples/glcube.py and saved it on my desktop as myglcube.py.

In PowerShell, you just type:

cd Desktop
py -m myglcube

Here is my example:

zzz

(here is the code)

#!/usr/bin/env python
"""Draw a cube on the screen. every frame we orbit
the camera around by a small amount and it appears
the object is spinning. note i've setup some simple
data structures here to represent a multicolored cube,
we then go through a semi-unopimized loop to draw
the cube points onto the screen. opengl does all the
hard work for us. :]
"""
import time
import pygame
from pygame.locals import *
try:
from OpenGL.GL import *
from OpenGL.GLU import *
except ImportError:
print ('The GLCUBE example requires PyOpenGL')
raise SystemExit
#some simple data for a colored cube
#here we have the 3D point position and color
#for each corner. then we have a list of indices
#that describe each face, and a list of indieces
#that describes each edge
CUBE_POINTS = (
(0.5, 0.5, 0.5), (0.5, 0.5, 0.5),
(0.5, 0.5, 0.5), (0.5, 0.5, 0.5),
(0.5, 0.5, 0.5), (0.5, 0.5, 0.5),
(0.5, 0.5, 0.5), (0.5, 0.5, 0.5)
)
#colors are 0-1 floating values
CUBE_COLORS = (
(1, 0, 0), (1, 1, 0), (0, 1, 0), (0, 0, 0),
(1, 0, 1), (1, 1, 1), (0, 0, 1), (0, 1, 1)
)
CUBE_QUAD_VERTS = (
(0, 1, 2, 3), (3, 2, 7, 6), (6, 7, 5, 4),
(4, 5, 1, 0), (1, 5, 7, 2), (4, 0, 3, 6)
)
CUBE_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 drawcube():
"draw the cube"
allpoints = list(zip(CUBE_POINTS, CUBE_COLORS))
glBegin(GL_QUADS)
for face in CUBE_QUAD_VERTS:
for vert in face:
pos, color = allpoints[vert]
glColor3fv(color)
glVertex3fv(pos)
glEnd()
glColor3f(1.0, 1.0, 1.0)
glBegin(GL_LINES)
"""
for line in CUBE_EDGES:
for vert in line:
pos, color = allpoints[vert]
glVertex3fv(pos)
"""
for x in range(50,50):
glColor3f(x*.03%1.0, x*.04%1.0, x*.05%1.0)
glVertex3fv((x, 0, 100))
glVertex3fv((x, 0, 100))
glVertex3fv((100, 0, x))
glVertex3fv((100, 0, x))
glEnd()
def main():
"run the demo"
#initialize pygame and setup an opengl display
pygame.init()
pygame.display.set_mode((1024,768), OPENGL|DOUBLEBUF)
glEnable(GL_DEPTH_TEST) #use our zbuffer
#setup the camera
glMatrixMode(GL_PROJECTION)
gluPerspective(45.0,1024/768.0,0.1,100.0) #setup lens
glTranslatef(0.0, 0.0, 20.0) #move back
glRotatef(60, 1, 0, 0) #orbit higher
nt = int(time.time() * 1000)
for i in range(2**63):
nt += 20
glTranslatef(0.0, 0.0, .1)
#check for quit'n events
event = pygame.event.poll()
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
break
#clear screen and move camera
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
#orbit camera around by 1 degree
glRotatef(1, 0, 1, 0)
drawcube()
pygame.display.flip()
ct = int(time.time() * 1000)
pygame.time.wait(max(1,nt ct))
if i % 50 == 0:
print(ntct)
if __name__ == '__main__': main()

view raw
myglcube.py
hosted with ❤ by GitHub