Simplifying Computer Art

Catherine Holloway, Qubitekk

Simplifying Computer Art

Catherine Holloway (@femion, CatherineH)

0

3D Drawing Options

Processing

Processing + Python Code

angle = 0def setup():    size(640, 480, P3D)def draw():    global angle    clear()    translate(320, 240)    rotate(angle, 1, 1, 0)    fill(255, 0, 0)    box(100)    angle += PI/100.0

1

1

3D Drawing Options

  1. Processing + Python

PyOpenGL

PyOpenGL is to OpenGL as PyQt is to Qt

pyOpenGL Code

from OpenGL.GL import *from OpenGL.GLUT import *from OpenGL.GLU import *

pyOpenGL Code

def InitGL(Width, Height):    glClearColor(0.0, 0.0, 0.0, 0.0)    glClearDepth(1.0)    glDepthFunc(GL_LESS)    glEnable(GL_DEPTH_TEST)    glShadeModel(GL_SMOOTH)    glMatrixMode(GL_PROJECTION)    glLoadIdentity()    gluPerspective(45.0, Width / Height, 0.1, 100.0)    glMatrixMode(GL_MODELVIEW)

pyOpenGL Code

def DrawGLScene():    global angle    glLoadIdentity()    glRotatef(angle, 1.0, 1.0, 0.0)    glBegin(GL_QUADS)    glColor3f(1.0, 0.0, 0.0)    glVertex3f(1.0, 1.0, -1.0)    glVertex3f(-1.0, 1.0, -1.0)    glVertex3f(-1.0, 1.0, 1.0)    glVertex3f(1.0, 1.0, 1.0)    ...    glEnd()    angle += 1

pyOpenGL Code

def DrawGLScene():    global angle    glLoadIdentity()    glRotatef(angle, 1.0, 1.0, 0.0)    glBegin(GL_QUADS)        glColor3f(1.0, 0.0, 0.0)    glVertex3f(1.0, 1.0, -1.0)    glVertex3f(-1.0, 1.0, -1.0)    glVertex3f(-1.0, 1.0, 1.0)    glVertex3f(1.0, 1.0, 1.0)        glColor3f(1.0, 0.0, 0.0)    glVertex3f(1.0, -1.0, 1.0)    glVertex3f(-1.0, -1.0, 1.0)    glVertex3f(-1.0, -1.0, -1.0)    glVertex3f(1.0, -1.0, -1.0)     glColor3f(0.0, 1.0, 0.0)    glVertex3f(1.0, 1.0, 1.0)    glVertex3f(-1.0, 1.0, 1.0)    glVertex3f(-1.0, -1.0, 1.0)    glVertex3f(1.0, -1.0, 1.0) 
    glColor3f(1.0, 1.0, 0.0)    glVertex3f(1.0, -1.0, -1.0)    glVertex3f(-1.0, -1.0, -1.0)    glVertex3f(-1.0, 1.0, -1.0)    glVertex3f(1.0, 1.0, -1.0)     glColor3f(0.0, 0.0, 1.0)    glVertex3f(-1.0, 1.0, 1.0)    glVertex3f(-1.0, 1.0, -1.0)    glVertex3f(-1.0, -1.0, -1.0)    glVertex3f(-1.0, -1.0, 1.0)     glColor3f(1.0, 0.0, 1.0)    glVertex3f(1.0, 1.0, -1.0)    glVertex3f(1.0, 1.0, 1.0)    glVertex3f(1.0, -1.0, 1.0)    glVertex3f(1.0, -1.0, -1.0)     glEnd()    angle += 1

pyOpenGL Code

glutInit(sys.argv)glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH)glutInitWindowSize(Width, Height)glutCreateWindow()glutDisplayFunc(DrawGLScene)glutIdleFunc(DrawGLScene)InitGL(Width, Height)glutMainLoop()

2

3D Drawing Options

  1. Processing + Python
  2. PyOpenGL

pyglet

Also a python OpenGL binding, but simplifies windowing and multimedia

pyglet

from pyglet.gl import *from pyglet import clock, window

pyglet

def update(dt):    global angle    angle += 1win = window.Window(height=Height, width=Width) pyglet.clock.schedule(update)clock.set_fps_limit(30)pyglet.app.run()

3

pyglet

@win.eventdef on_resize(width, height):    glClearColor(0.0, 0.0, 0.0, 0.0)    glClearDepth(1.0)    glEnable(GL_DEPTH_TEST)    glShadeModel(GL_SMOOTH)    glMatrixMode(GL_PROJECTION)    glLoadIdentity()    gluPerspective(45.0, Width / Height, 0.1, 100.0)    glMatrixMode(GL_MODELVIEW)    return pyglet.event.EVENT_HANDLED

pyglet

@win.eventdef on_draw():    global angle    glLoadIdentity()    glTranslatef(0.0, 0.0, -6.0)    glRotatef(angle, 1, 1, 0)    glBegin(GL_QUADS)    glColor3f(1.0, 0.0, 0.0)    glVertex3f(1.0, 1.0, -1.0)    glVertex3f(-1.0, 1.0, -1.0)    glVertex3f(-1.0, 1.0, 1.0)    glVertex3f(1.0, 1.0, 1.0)    ...

3

3D Drawing Options

  1. Processing + Python
  2. PyOpenGL
  3. pyglet

VPython

physics example: projectile motion

ball = sphere(pos=vector(-10, 0, 0), radius=0.1,               color=color.red, make_trail=True)ball.velocity = vector(10, 10, 0)time = 0.0; time_final = 2; dt = 0.01; m = 0.15while time <= time_final and ball.pos.y > -0.1:    rate(100)    f = - m * vector(0, 9.8, 0)        ball.pos += ball.velocity * dt    ball.velocity += f * dt / m    time += dt

physics example: projectile motion with air resistance

ball = sphere(pos=vector(-10, 0, 0), radius=0.1,               color=color.red, make_trail=True)ball.velocity = vector(10, 10, 0)time = 0.0; time_final = 2; dt = 0.01; m = 0.15while time <= time_final and ball.pos.y > -0.1:    rate(100)    f = - m * vector(0, 9.8, 0)          -0.006 * ball.velocity * ball.velocity.mag    ball.pos += ball.velocity * dt    ball.velocity += f * dt / m    time += dt

VPython code

from visual import *a_box = box(width=1, height=1, length=1, color=color.red)while True:    rate(10)    a_box.rotate(angle=radians(1), axis=vector(1, 1, 0))

4

“There is no debian package for wxPython3”

4

4

Writing simple graphics libraries is hard.

An OpenGL Helper

PyOpenGL vs. pyglet

Feature PyOpenGL pyglet
GLUT yes no
GLext yes no (experimental)
3.5 support yes (not official) no

Why pyglet?

A Helper for Pyglet

Implementation

Multiple Method Declarations

explicit vector( double a = 0.0, double b = 0.0,                 double c = 0.0) throw()	: x(a), y(b), z(c) {}inline explicit vector( const double* v)	: x(v[0]), y(v[1]), z(v[2]) {}

Python version

def __init__(self, in_vector=None):    if in_vector is None:        self.zero()    elif len(in_vector) > 2:        for i in range(len(self)):            self[i] = in_vector[i]    else:        raise ValueError("in_vector must contain "                         "at least three numbers!")

PEP styling

box() became Box()vector.x became Vector.x_component, or Vector[0]

How do we make sure API changes don’t break everything?

Use Continuous Integration!

Drawing

Continous integration with no display

OpenGL requires a display to draw to, but Travis-CI runs on a headless server!

Rendering to a still image

Alternative - Mocking GL

@patch('pyglet_helper.objects.box.gl',       new=pyglet_helper.test.fake_gl)def test_box_generate_model():    from pyglet_helper.objects import Box    box = Box()    box.generate_model()

fake_gl module

def glVertex3f(x_component, y_component, z_component):    pass

pyglet_helper Functionality

  1. Objects
  2. Lights and scenes
  3. Default scene

Lights and Scenes

Drawing options

my_box = Box()my_scene = View()my_box.render(my_scene)

or

my_scene.objects.append(my_box)my_scene.setup()    

Default Scene

from pyglet_helper import *vsetup()box = objects.Box(size=(1, 1, 1), color=util.RED)def update(dt):    box.rotate(angle=radians(1),               axis=util.Vector([1, 1, 0]))vrun(update, render_images=True, max_frames=180)

What about jupyter?

vpython ecosystem

  1. Sherwood and others switched efforts from OpenGL to WebGL
    1. wxPython has no python 3 version
    2. few people familiar with C++ code base
  2. GlowScript JavaScript library written in 2012
  3. Two python routes to GlowScript

glowscript.org

  1. completely online, no local installs
  2. Python-to-JavaScript transpiler provides python interface
  3. no access to full scientific Python stack

vpython-jupyter

  1. Originally developed by John Coady as ivisual
  2. Updated to use GlowScipt Python API and released on PyPI as vpython
  3. Runs in Jupyter notebook, typically in a local installation
  4. Rendering handled through a comm channel to GlowScipt loaded in the front end

Future Work on pyglet_helper

Python version

from vispy import app, scenefrom vispy.visuals import transforms   canvas = scene.SceneCanvas(keys='interactive')view = canvas.central_widget.add_view()def update(dt):    global cube    cube.transform.rotate(1, (1, 1, 0))cube = scene.visuals.Cube(color='red', edge_color="k")cube.transform = transforms.MatrixTransform()view.add(cube)view.camera = scene.TurntableCamera()canvas.show()timer = app.Timer('auto', connect=update, start=True)canvas.app.run()

An Experiment

DEAP Logo

Scikit image logo

genetic algorithm pyglet helper

Thank you!

@femion, github: CatherineH

Fork me on Github