Skip to content

Instantly share code, notes, and snippets.

@Zulko
Last active August 14, 2019 09:37
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Zulko/4dcaf3e38fdc118f22a3 to your computer and use it in GitHub Desktop.
Save Zulko/4dcaf3e38fdc118f22a3 to your computer and use it in GitHub Desktop.
Animated brain (Vispy) turned into a video/GIF (MoviePy)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vispy: gallery 2
# Copyright (c) 2014, Vispy Development Team.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
#
# Modified for animation with MoviePy by Zulko
# See result here: http://i.imgur.com/sSCBkFd.gif
#
"""
3D brain mesh viewer.
"""
from timeit import default_timer
import numpy as np
from vispy import gloo
from vispy import app
from vispy.util.transforms import perspective, translate, rotate
from vispy.io import load_data_file
from vispy.gloo.util import _screenshot
brain = np.load(load_data_file('brain/brain.npz', force_download='2014-09-04'))
data = brain['vertex_buffer']
faces = brain['index_buffer']
VERT_SHADER = """
#version 120
uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_projection;
uniform vec4 u_color;
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec4 a_color;
varying vec3 v_position;
varying vec3 v_normal;
varying vec4 v_color;
void main()
{
v_normal = a_normal;
v_position = a_position;
v_color = a_color * u_color;
gl_Position = u_projection * u_view * u_model * vec4(a_position,1.0);
}
"""
FRAG_SHADER = """
#version 120
uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_normal;
uniform vec3 u_light_intensity;
uniform vec3 u_light_position;
varying vec3 v_position;
varying vec3 v_normal;
varying vec4 v_color;
void main()
{
// Calculate normal in world coordinates
vec3 normal = normalize(u_normal * vec4(v_normal,1.0)).xyz;
// Calculate the location of this fragment (pixel) in world coordinates
vec3 position = vec3(u_view*u_model * vec4(v_position, 1));
// Calculate the vector from this pixels surface to the light source
vec3 surfaceToLight = u_light_position - position;
// Calculate the cosine of the angle of incidence (brightness)
float brightness = dot(normal, surfaceToLight) /
(length(surfaceToLight) * length(normal));
brightness = max(min(brightness,1.0),0.0);
// Calculate final color of the pixel, based on:
// 1. The angle of incidence: brightness
// 2. The color/intensities of the light: light.intensities
// 3. The texture and texture coord: texture(tex, fragTexCoord)
// Specular lighting.
vec3 surfaceToCamera = vec3(0.0, 0.0, 1.0) - position;
vec3 K = normalize(normalize(surfaceToLight) + normalize(surfaceToCamera));
float specular = clamp(pow(abs(dot(normal, K)), 40.), 0.0, 1.0);
gl_FragColor = v_color * brightness * vec4(u_light_intensity, 1);
}
"""
class Canvas(app.Canvas):
def __init__(self):
app.Canvas.__init__(self, keys='interactive')
self.size = 400, 300
self.program = gloo.Program(VERT_SHADER, FRAG_SHADER)
self.theta, self.phi = -80, 180
self.translate = 2.5
self.faces = gloo.IndexBuffer(faces)
self.program.bind(gloo.VertexBuffer(data))
self.program['u_color'] = 1, 1, 1, 1
self.program['u_light_position'] = (1., 1., 1.)
self.program['u_light_intensity'] = (1., 1., 1.)
gloo.set_state(blend=False, depth_test=True, polygon_offset_fill=True)
self.update_matrices()
def update_matrices(self):
self.view = np.eye(4, dtype=np.float32)
self.model = np.eye(4, dtype=np.float32)
self.projection = np.eye(4, dtype=np.float32)
rotate(self.model, self.theta, 1, 0, 0)
rotate(self.model, self.phi, 0, 1, 0)
translate(self.view, 0, 0, -self.translate)
self.program['u_model'] = self.model
self.program['u_view'] = self.view
self.program['u_normal'] = np.array(np.matrix(np.dot(self.view,
self.model)).I.T)
def on_resize(self, event):
width, height = event.size
gloo.set_viewport(0, 0, width, height)
self.projection = perspective(45.0, width / float(height), 1.0, 20.0)
self.program['u_projection'] = self.projection
def animation(self, t):
""" Added for animation with MoviePy """
self.phi, self.theta = 180*t, -80
self.update_matrices()
self.update()
gloo.clear()
self.program.draw('triangles', indices=self.faces)
return _screenshot((0, 0, self.size[0], self.size[1]))[:,:,:3]
if __name__ == '__main__':
from moviepy.editor import VideoClip
canvas = Canvas()
canvas.show()
clip = VideoClip(canvas.animation, duration=2)
clip.write_videofile('brain.mp4', fps=20)
#clip.write_gif('brain.gif', fps=20, opt='OptimizePlus', fuzz=10)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment