Creating Aurora Animation
Creating a 3D Voxel Aurora Animation
This guide walks you through how to generate a looping 3D voxel animation of an aurora borealis using SpatialStudio.
The script creates shimmering, flowing auroral curtains that wave and dance in a night sky, then saves the animation to a .splv
file.
What this script does
- Creates a 3D scene of size 128×128×128
- Generates an aurora with:
- Multiple flowing curtains of light
- Dynamic color gradients (greens, blues, purples)
- Realistic wave-like motion
- Particle effects for stars
- Animates for 10 seconds at 30 FPS
- Outputs the file
aurora.splv
that you can play in your viewer
How it works (simplified)
-
Voxel volume Each frame is a 3D grid filled with RGBA values (
SIZE × SIZE × SIZE × 4
). -
Aurora curtains Created using noise-based wave functions that define the curtain's shape and flow.
-
Color gradients Colors shift smoothly between preset aurora hues using sine interpolation.
-
Motion system Uses layered sine waves and Perlin noise to create natural flowing movement.
-
Star field Randomly placed white voxels that twinkle using brightness variation.
-
Animation loop A normalized time variable
t
cycles from0 → 2π
, ensuring seamless looping.
Try it yourself
Install requirements first:
pip install spatialstudio numpy tqdm noise
Then copy this script into aurora.py
and run:
python aurora.py
Full Script
import numpy as np
from spatialstudio import splv
from noise import pnoise3
from tqdm import tqdm
# Scene setup
SIZE, FPS, SECONDS = 128, 30, 10
FRAMES = FPS * SECONDS
OUT_PATH = "../outputs/aurora.splv"
# Aurora settings
CURTAIN_COUNT = 3
NOISE_SCALE = 30.0
WAVE_HEIGHT = 40
def add_voxel(volume, x, y, z, color, alpha=255):
if 0 <= x < SIZE and 0 <= y < SIZE and 0 <= z < SIZE:
volume[x, y, z, :3] = color
volume[x, y, z, 3] = alpha
def generate_aurora_curtain(volume, offset, t):
colors = [
(0, 255, 127), # Green
(0, 255, 255), # Cyan
(147, 0, 255), # Purple
]
for x in range(SIZE):
# Wave motion
wave = np.sin(x * 0.05 + t + offset) * WAVE_HEIGHT
height = int(SIZE * 0.7 + wave)
for z in range(SIZE):
noise = pnoise3(x/NOISE_SCALE, t, z/NOISE_SCALE, octaves=4)
curtain_height = int(height + noise * 20)
for y in range(curtain_height - 20, curtain_height):
fade = (y - (curtain_height - 20)) / 20.0
color_idx = int(fade * len(colors))
color = colors[min(color_idx, len(colors)-1)]
alpha = int((1.0 - fade) * 200)
add_voxel(volume, x, y, z, color, alpha)
def add_stars(volume, t):
for _ in range(1000):
x = np.random.randint(0, SIZE)
y = np.random.randint(SIZE//2, SIZE)
z = np.random.randint(0, SIZE)
brightness = int(127 + 128 * np.sin(t * 2 + x * y * z))
add_voxel(volume, x, y, z, (brightness, brightness, brightness))
def generate_scene(volume, t):
# Add stars first
add_stars(volume, t)
# Generate aurora curtains
for i in range(CURTAIN_COUNT):
offset = (i / CURTAIN_COUNT) * 2 * np.pi
generate_aurora_curtain(volume, offset, t)
enc = splv.Encoder(SIZE, SIZE, SIZE, framerate=FPS, outputPath=OUT_PATH, motionVectors="off")
for frame in tqdm(range(FRAMES), desc="Generating aurora"):
volume = np.zeros((SIZE, SIZE, SIZE, 4), dtype=np.uint8)
t = (frame / FRAMES) * 2*np.pi
generate_scene(volume, t)
enc.encode(splv.Frame(volume, lrAxis="x", udAxis="y", fbAxis="z"))
enc.finish()
print(f"Created {OUT_PATH}")
Next steps
- Adjust
CURTAIN_COUNT
to change the number of aurora curtains - Modify the
colors
list to create different aurora color schemes - Experiment with
NOISE_SCALE
andWAVE_HEIGHT
for different motion effects - Add more star layers at different depths for parallax
- Try different noise functions for varied curtain patterns
Tips for best results
- Keep the scene dark (low ambient light) to make the aurora stand out
- Use semi-transparent voxels for more realistic light diffusion
- Layer multiple noise functions for more complex motion
- Adjust the star count and brightness for different atmospheric effects
- Consider adding ground elements like mountains for scale reference