Skip to content

Instantly share code, notes, and snippets.

@djhoese
Created September 30, 2020 13:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save djhoese/93a70d94aec69db9dd74c99673f0a2bc to your computer and use it in GitHub Desktop.
Save djhoese/93a70d94aec69db9dd74c99673f0a2bc to your computer and use it in GitHub Desktop.
Create MP4 animation of rotating cube.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vispy: gallery 50
"""
This example shows how to display 3D objects.
You should see a colored outlined spinning cube.
"""
import numpy as np
from vispy import app, gloo
from vispy.util.transforms import perspective, translate, rotate
from vispy.gloo.util import _screenshot
import imageio
vert = """
// Uniforms
// ------------------------------------
uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_projection;
uniform vec4 u_color;
// Attributes
// ------------------------------------
attribute vec3 a_position;
attribute vec4 a_color;
attribute vec3 a_normal;
// Varying
// ------------------------------------
varying vec4 v_color;
void main()
{
v_color = a_color * u_color;
gl_Position = u_projection * u_view * u_model * vec4(a_position,1.0);
}
"""
frag = """
// Varying
// ------------------------------------
varying vec4 v_color;
void main()
{
gl_FragColor = v_color;
}
"""
# -----------------------------------------------------------------------------
def cube():
"""
Build vertices for a colored cube.
V is the vertices
I1 is the indices for a filled cube (use with GL_TRIANGLES)
I2 is the indices for an outline cube (use with GL_LINES)
"""
vtype = [('a_position', np.float32, 3),
('a_normal', np.float32, 3),
('a_color', np.float32, 4)]
# Vertices positions
v = [[1, 1, 1], [-1, 1, 1], [-1, -1, 1], [1, -1, 1],
[1, -1, -1], [1, 1, -1], [-1, 1, -1], [-1, -1, -1]]
# Face Normals
n = [[0, 0, 1], [1, 0, 0], [0, 1, 0],
[-1, 0, 1], [0, -1, 0], [0, 0, -1]]
# Vertice colors
c = [[0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 1], [0, 1, 0, 1],
[1, 1, 0, 1], [1, 1, 1, 1], [1, 0, 1, 1], [1, 0, 0, 1]]
V = np.array([(v[0], n[0], c[0]), (v[1], n[0], c[1]),
(v[2], n[0], c[2]), (v[3], n[0], c[3]),
(v[0], n[1], c[0]), (v[3], n[1], c[3]),
(v[4], n[1], c[4]), (v[5], n[1], c[5]),
(v[0], n[2], c[0]), (v[5], n[2], c[5]),
(v[6], n[2], c[6]), (v[1], n[2], c[1]),
(v[1], n[3], c[1]), (v[6], n[3], c[6]),
(v[7], n[3], c[7]), (v[2], n[3], c[2]),
(v[7], n[4], c[7]), (v[4], n[4], c[4]),
(v[3], n[4], c[3]), (v[2], n[4], c[2]),
(v[4], n[5], c[4]), (v[7], n[5], c[7]),
(v[6], n[5], c[6]), (v[5], n[5], c[5])],
dtype=vtype)
I1 = np.resize(np.array([0, 1, 2, 0, 2, 3], dtype=np.uint32), 6 * (2 * 3))
I1 += np.repeat(4 * np.arange(2 * 3, dtype=np.uint32), 6)
I2 = np.resize(
np.array([0, 1, 1, 2, 2, 3, 3, 0], dtype=np.uint32), 6 * (2 * 4))
I2 += np.repeat(4 * np.arange(6, dtype=np.uint32), 8)
return V, I1, I2
# -----------------------------------------------------------------------------
class Canvas(app.Canvas):
def __init__(self):
app.Canvas.__init__(self, keys='interactive', size=(800, 600))
self.vertices, self.filled, self.outline = cube()
self.filled_buf = gloo.IndexBuffer(self.filled)
self.outline_buf = gloo.IndexBuffer(self.outline)
self.program = gloo.Program(vert, frag)
self.program.bind(gloo.VertexBuffer(self.vertices))
self.view = translate((0, 0, -5))
self.model = np.eye(4, dtype=np.float32)
gloo.set_viewport(0, 0, self.physical_size[0], self.physical_size[1])
self.projection = perspective(45.0, self.size[0] /
float(self.size[1]), 2.0, 10.0)
self.program['u_projection'] = self.projection
self.program['u_model'] = self.model
self.program['u_view'] = self.view
self.theta = 0
self.phi = 0
gloo.set_clear_color('white')
gloo.set_state('opaque')
gloo.set_polygon_offset(1, 1)
self._timer = app.Timer('auto', connect=self.on_timer, start=True)
self._animation_timer = app.Timer(0.1, connect=self.on_animation, start=True)
self._animation_writer = imageio.get_writer("rotating_cube.mp4", fps=5)
self._animation_counter = 0
self.show()
def on_animation(self, event):
frame = _screenshot()
self._animation_writer.append_data(frame)
self._animation_counter += 1
if self._animation_counter >= 25:
self._animation_timer.stop()
self._animation_writer.close()
self.close()
# ---------------------------------
def on_timer(self, event):
self.theta += .5
self.phi += .5
self.model = np.dot(rotate(self.theta, (0, 1, 0)),
rotate(self.phi, (0, 0, 1)))
self.program['u_model'] = self.model
self.update()
# ---------------------------------
def on_resize(self, event):
gloo.set_viewport(0, 0, event.physical_size[0], event.physical_size[1])
self.projection = perspective(45.0, event.size[0] /
float(event.size[1]), 2.0, 10.0)
self.program['u_projection'] = self.projection
# ---------------------------------
def on_draw(self, event):
gloo.clear()
# Filled cube
gloo.set_state(blend=False, depth_test=True, polygon_offset_fill=True)
self.program['u_color'] = 1, 1, 1, 1
self.program.draw('triangles', self.filled_buf)
# Outline
gloo.set_state(blend=True, depth_test=True, polygon_offset_fill=False)
gloo.set_depth_mask(False)
self.program['u_color'] = 0, 0, 0, 1
self.program.draw('lines', self.outline_buf)
gloo.set_depth_mask(True)
# -----------------------------------------------------------------------------
if __name__ == '__main__':
c = Canvas()
app.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment