Is it possible to achieve a spirograph efect?

I've been trying to create a spirograph effect by using a few parented empties, rotating at different rates, with an emmisive object at the end of the partent chain.

I tried using motion blur to get a long line drawn of the object's path, but what I get is just two lines. I guess the motion blur time resolution was not enough. So I have cranked that up for my emissive object, but nothing has changed. I guess it's because of the empties.

I tried slowing down the animation so the motion will span more frames to hopefully make the motion blur arcs more precise - but nothing has changed.

I wonder if there are any other approaches that could help me generate Lissajous curves with Blender.

Lissajous curves are described using the parameteric equations:

\begin{aligned} x &= A\sin{(at+\delta)}\\ y &= B\sin{(bt)} \end{aligned}

So there is no need to take an implicit approach. We can easily implement this system of paremeteric equations in Animation Nodes as follows:

• Fabulous! I wonder if I could use an audio file (waveform) as input to get a vectorscope effect with this. – unfa Mar 27 '18 at 11:52
• @unfa I suppose yes, I am not entirely sure what how an audio vectorscope. But what ever it is, it is possible. – Omar Emara Mar 27 '18 at 16:21

import bpy

start_frame = 1 # when do you want to start the tracking?
end_frame = 1000 # and when should it stop again?
stylus = 'Empty' # name of the object to track
new_name = "Whirl" # name of the created object

verts = [] # list of all vertices
edges = [] # list of all edges

sce = bpy.context.scene # the current scene
old_frame = sce.frame_current # remember the current frame

vertex_count = start_frame
while vertex_count <= end_frame: # iterate through the specified time
sce.frame_set(vertex_count) # set the frame so the object is in the right place for any given frame
loc = bpy.data.objects[stylus].matrix_world.translation # the global coordinates of the stylus
verts.append((loc.x, loc.y, loc.z)) # add the position to the vertex list
vertex_count += 1

edge_count = 1 # starting with the second vert because the edge list is one item shorter
end = len(verts)

while edge_count < end: # building the edges
edges.append((edge_count - 1, edge_count)) # assigns the indices of the verts to the edges
edge_count += 1

#edges = [(x-1 , x) for x in range(len(verts)) if x > 0] # this does the same as the above edge code. list comprehensions are scary

mesh_data = bpy.data.meshes.new(new_name + '-mesh') # makes a new mesh
mesh_data.from_pydata(verts, edges, []) # fills verts and edges into the mesh
mesh_data.update()

obj = bpy.data.objects.new(new_name, mesh_data) # makes a new object with the mesh linked