3
$\begingroup$

Fellowing instructions found in a youtube tutorial, I managed to draw a slinky.

See my .blend (note that I did not add the curve modifier as I want my slinky to be along an axis, see below).

enter image description here

Now, I'd like to animate it so I could illustrate how a longitudinal wave propagates (as show in this video). For simplicity, let's consider a sinusoidal wave: the displacement field is xi(x, t) = xi0 cos(2 pi f t - 2 pi x / lambda) where f is the frequency of the wave and lambda is the wavelength (lambda f = v where v is the velocity of the wave).

My question is: how can I use Python to add keyframes so that the vertices of the lattice (and the slinky) are moved according to the displacement field?

$\endgroup$
2
$\begingroup$

Well, that was not easy for a beginner like me but I think I found a way. Explanations about lattice_index_from_uvw can be found in this question of mine. Just run the script once and then the handler bpy.app.handlers.frame_change_pre does the job.

import bpy
from math import cos

pi = 3.1415

lat = bpy.data.lattices['Lattice']
obj = bpy.data.objects['Lattice']

# Space

def lattice_index_from_uvw(lat, u, v, w):
    totu = lat.points_u
    totv = lat.points_v
    return w * (totu * totv) + (v * totu) + u

points = obj.data.points

Delta_x = points[lattice_index_from_uvw(lat, 1, 0, 0)].co_deform.x - points[lattice_index_from_uvw(lat, 0, 0, 0)].co_deform.x 

x0 = [points[lattice_index_from_uvw(lat, u, 0, 0)].co_deform.x for u in range(lat.points_u)]

A = Delta_x / 3
Lambda = 10 * Delta_x

# Time

scn = bpy.context.scene 

frame_start = scn.frame_start
frame_end = scn.frame_end

Delta_t = 1
T = frame_end - frame_start


def sine_wave(x, t, A, T, Lambda):
    return A * cos(2 * pi * ( (t / T) - (x / Lambda)))

def update_wave(t):
    for u in range(lat.points_u):
        for v in range(lat.points_v):
            for w in range(lat.points_w):
                points[lattice_index_from_uvw(lat, u, v, w)].co_deform.x = x0[u] + sine_wave(x0[u], t, A, T, Lambda)

def my_handler(scene):
    print(scene.frame_current)
    update_wave(scene.frame_current * Delta_t)

bpy.app.handlers.frame_change_pre.append(my_handler)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.