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.
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!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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((x–s,y–s,z)) | |
glVertex3fv((x+s,y–s,z)) | |
glVertex3fv((x+s,y+s,z)) | |
glVertex3fv((x–s,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(nt–ct) | |
if __name__ == '__main__': main() |