I'll be animating a large number of small objects following pre-calculated orbits. I'd like to add glowing trails that follow the orbit with an intensity that drops off with a specified decay function. Actually I'd like to emulate this effect as close as possible.
Below is a small demo example to give a rough idea. The script generates an animation ready to run, but the trails are implemented as zillions of mesh objects. This obviously wouldn't scale.
The real thing will be bigger (imagine asteroid belt or Oort cloud or space junk), so I need those narrow, but beautifully defined trails as seen in the first link or here also.
I am thinking of creating one-dimensional mesh objects (a line of connected vertices) and assigning some kind of non-linear material ramp (would that even work?), but maybe there is a better approach.
Run the animation generated by the script...
def RK4(x, v, n, h, F):
for i in range(n): # written for readability, not speed
kv1 = F( x[:, i] )
kx1 = v[:, i]
kv2 = F( x[:, i] + kx1 * (h/2.0) )
kx2 = v[:, i] + kv1 * (h/2.0)
kv3 = F( x[:, i] + kx2 * (h/2.0) )
kx3 = v[:, i] + kv2 * (h/2.0)
kv4 = F( x[:, i] + kx3 * h )
kx4 = v[:, i] + kv3 * h
v[:, i+1] = v[:, i] + (h/6.0) * (kv1 + 2.*(kv2 + kv3) + kv4)
x[:, i+1] = x[:, i] + (h/6.0) * (kx1 + 2.*(kx2 + kx3) + kx4)
def acc(x):
""" acceleration due to the sun's gravity (NumPy version) """
return -Gm * x / ( ((x**2).sum(axis=1)**1.5)[:,None] )
import bpy
import numpy as np
Gm = 1.3271244002E+20 # m^3 s^-2 (Wikipedia Standard Gravitational Parameter)
t_year = 31558464. # s (roughly)
scale = 4.0E-11 # blender units per meter
n_frames = 250
Dt = t_year / float(n_frames) # time step
n = 8
X = np.zeros((n, 1000, 3))
V = np.zeros((n, 1000, 3))
T = np.zeros((n, 1000))
tilt = 30. * (np.pi/180.) #radians
sin_tilt, cos_tilt = np.sin(tilt), np.cos(tilt)
X[:,0] = np.array([1.5E+11, 0.0, 0.0])[None, :] # start in the same place...
V[:,0] = 29300. * (np.linspace(0.5, 1.2, n)[:, None] *
np.array([0.0, cos_tilt, sin_tilt])[None, :] ) # ...but different initial velocities
# NOTE!! This is just for quickie demos only.
# Will give wrong result if step size too big.
RK4(X, V, n_frames, Dt, acc) # pre-calculate orbits
p_size, s_size = 0.2, 0.5
# Create the Universe
ok = bpy.ops.mesh.primitive_ico_sphere_add(size=s_size, location=(0.0, 0.0, 0.0))
sun = bpy.context.active_object
sun.name = "Sun"
n_echos, frames_per_echo = 20, 1
e_sizes = np.linspace(p_size, 0, n_echos+1)[:-1]
things, trails = [], []
for i in range(n):
ok = bpy.ops.mesh.primitive_ico_sphere_add(size=p_size, location=(0.0, 0.0, 0.0))
p = bpy.context.active_object
p.name = "p" + str(i)
things.append(p)
echos = []
for i_echo in range(n_echos):
ok = bpy.ops.mesh.primitive_ico_sphere_add(size=e_sizes[i_echo], location=(0.0, 0.0, 0.0))
e = bpy.context.active_object
e.name = "p" + str(i) + "e" + str(i_echo)
echos.append(e)
trails.append(echos)
# Animate the Universe
bpy.context.scene.frame_end = n_frames
for i_frame in range(n_frames):
for i, p in enumerate(things):
p.location = scale * X[i, i_frame]
p.keyframe_insert(data_path="location", frame = i_frame + 1, index=-1)
for iecho, echo in enumerate(trails[i]):
i_frame_echo = max(0, i_frame - frames_per_echo*(iecho+1))
echo.location = scale * X[i, i_frame_echo]
echo.keyframe_insert(data_path="location", frame = i_frame + 1, index=-1)