Vincent Duindam

Navigation

3D Graphics

I spent quite some spare time having fun with 3D graphics, both just as a hobby and as a way to illustrate research, lectures, and other ideas. The tools I use are all open-source and include

  1. Blender for 3d modeling and bitmap rendering
  2. The GIMP for texturing and bitmap post-processing
  3. Inkscape for vector graphics
  4. LaTeX/PSfrag for better-looking labels and mathematical symbols
Below are some examples on how I've used these tools so far: to create simulation movies, visualize research results, and design my dissertation cover image. I hope the information and examples here are useful; comments and tips are welcome.


Animations in Blender using physical simulation data

One of the most interesting things (from a engineer's point of view) you can do with Blender is to program it using the embedded python interpreter. Although Blender's code/text editor leaves some things to be desired, the API is very powerful and can turn boring data plots into shiny animations.

I had a hard time finding the right bits of code in the online API documentation, so I compiled a short example of how you can convert simulation data from a regular text format to an animation. The code example below should be run whenever the frame is changed, also make sure scripts are enabled.

The simulation data consists of three data arrays, tdata containing time stamps, q1data containing one variable, and q2data containing a second variable. This data was obtained from a dynamics simulation made in 20sim, but really any data will do. At frame 1 or if the data is not ready, the code loads the data from a file into python arrays. These arrays are made part of the blender environment (by calling them B.xxx instead of xxx), since regular variables are lost between frames. Another less efficient method would be to just reload the data at every frame.

At every frame, the current time is computed (based on the current frame number and the number of frames per second in the animation), and the appropriate datapoints are retrieved from the arrays (with linear interpolation between time stamps). Then, the data values are used to set the y-position of the two colored blocks, and the joint angles of the armature, to which the two pendulum links are connected. Note that the 'Get' functions in the Blender API return objects by reference (not by value), and so modifying these objects directly influences the data structures they refer to.

You will need the following files to reproduce the movie

  1. The main dataimport.blend file with code included.
  2. Data files: simulated double pendulum dynamics at 25 fps and some synthetic data at 1 fps. The first file is used in the example blend, the second file is useful to test linear or other interpolation.
Download the blender and data files into one directory, open the blender file, hover your mouse over the 3d viewing area in the top left, and press alt-a to start the animation. I hope this example will help you on your way, let me know if you have examples of other neat things you can do with the Blender API.

import Blender as B
from Blender import *
from Blender.Mathutils import *
from math import pi

######################################################
#### find first larger element in an ordered list ####
######################################################

def findlarger(l,x):
  for i in range(0,len(l)):
    if (l[i]>=x):
      return i
  return -1

############################################
#### open datafile and fill data arrays ####
############################################

# check for existence of custom variable dataready in Blender
# environment. If it does not exist, we should get the data.
try: B.dataready
except:
  B.dataready=False

# update data if it is not there or at frame 1, store data
# arrays in Blender environment (B.tdata instead of tdata)
# to make it survive between frames.
if (B.dataready==False or Get("curframe")==1):
  print "reading data.."
  dat=file("25fps.dat","r")
  B.tdata=[]
  B.q1data=[]
  B.q2data=[]
  for line in dat.readlines():
    row=map(float,line.split())
    B.tdata.append(row[0])
    B.q1data.append(row[1])
    B.q2data.append(row[2])
  dat.close()
  B.dataready=True

###################################################
#### calculate and set current joint positions ####
###################################################

# calculate absolute time (based on fps and frame number)
fps=B.Scene.GetCurrent().getRenderingContext().fps
t=(Get("curframe")-1.0)/fps

# linear interpolation between appropriate data points
# for t outside data range (i=0 or i=-1), extrapolate constant
i=findlarger(B.tdata,t)
if (i==0) or (i==-1):
  q1=B.q1data[i]
  q2=B.q2data[i]
else:
  rat=(B.tdata[i]-t)/(B.tdata[i]-B.tdata[i-1])
  q1=rat*B.q1data[i-1]+(1-rat)*B.q1data[i]
  q2=rat*B.q2data[i-1]+(1-rat)*B.q2data[i]

# set cubes positions equal to q1, q2
obj1=Object.Get("redcube")
obj2=Object.Get("bluecube")
obj1.setLocation(1.7,q1,-0.2)
obj2.setLocation(1.2,q2,-0.2)

# set angles of the bones
pose=Object.Get("pendulum").getPose()
b1=pose.bones["top"]
b2=pose.bones["bottom"]
b1.quat=RotationMatrix((180/pi)*q1,4,'x').toQuat()
b2.quat=RotationMatrix((180/pi)*q2,4,'x').toQuat()

# update pose display
pose.update()


Research — Illustrations in articles and online

My academic research dealt with 3d mechanics and robotics as encountered in various applications. Over the past years, I have found that clean visualization of the geometry and structure of these 3d systems is indispensable to gain intuition and to convey the general idea of analysis and control algorithms designed for such systems. Below are some of the figures I made in the past year or so, all related to ongoing research work. A few more figures can be found on the other pages of this website. All meshes except Asimo's body parts are made from scratch.

The 3D humanoid robot is Honda's Asimo, the model is partially based on an accurate mesh model from Honda's website (in Japanese). Unfortunately, it seems Asimo's model has since been removed from the website. Additional modeling, posing, and labeling was done using Blender, Inkscape, and LaTeX/PSfrag.

The surgical robot arm is loosely based on publicly available pictures of Intuitive Surgical's DaVinci system. Check this movie (mp4, 0.5MB) to see the null motion of the manipulator, computed in Blender's embedded python interpreter using standard robotics algorithms, and applied as a motion transformation to the manipulator following the same approach as illustrated in the previous section.

The surgical needle picture was created for the needle-steering project website and shows three flexible bevel-tip needles being inserted into the tissue and guided around obstacles to a target area marked by the red-glowing cross-hairs. Modeled, posed, and rendered using Blender.



Ph.D. dissertation cover — Ascending and descending

The image below was created using Blender 2.36 for the cover of my PhD dissertation. It is based on the famous piece 'Ascending and Descending' by Dutch graphic artist M.C. Escher, who in turn was inspired by the article "Impossible Objects: A Special Type of Visual Illusion" by Penrose and Penrose, published in the British Journal of Psychology in 1958.

The main difference with Escher's work is obviously the inclusion of robots instead of monks walking around the endless staircase. It is supposed to symbolize that walking robots need to be able to do more than just walk down a slope to get anywhere in the real world. My dissertation discusses extensions to passive dynamic walking robots, which can walk down a slope without actuation forces. The silver-colored robot model is taken from the Solidworks design files of the experimental walking robot Dribbel, built at the University of Twente where I obtained my degree; the church tower in the top-right of the image is modeled after the university's church tower. Finally, the results in my dissertation rely on the theory of port-Hamiltonian systems and bond graphs, which is symbolized by the white half-arrows on the pillars in the structure.

The illusion is created in the same way that Andrew Lipson created a Lego version, see this movie (wmv, 4.0 MB) for a fly-through of my version.