0
$\begingroup$

I'm working on a project that is intended to simulate the motions of stars in a galaxy by importing snapshot txt files with thousands of xyz coordinates each - but for the purposes of this question, I'm including a simpler coordinate generator of 3 points that change positions over 10 frames. My plan was to create/update a point cloud particle system for each frame and emit a particle from each vert (so in this case 3 particles for each of the 10 frames). My problem is that with my current script I can change the vert positions of the particle system for each frame but not every frame emits particles - only three frames emit one particle each. I think Blender is only seeing one particle system and distributing three particles equally over 10 frames. Here is my current script:

import bpy
import numpy as np
import os
import pathlib
import mathutils
import glob
from bpy.app.handlers import frame_change_post

# Delete any existing objects
objs = [ob for ob in bpy.context.scene.objects 
        if ob.type in ('LIGHT', 'MESH', 'OBJECT')]
if len(objs):
    bpy.ops.object.delete({"selected_objects": objs})

# Create simple coordinates   
nframes = 10
nparticles = 3
xyz = np.zeros((nframes, nparticles, 3))
for i in range(3):
    xyz[:, i, i] = np.linspace(-4, 4, nframes)
cache = xyz

scene = bpy.context.scene

# Create point cloud object and link to group
def make_point_cloud_mesh(ob_name, coords, edges=[], faces=[]):
    me = bpy.data.meshes.new(f"{ob_name} Mesh")
    ob = bpy.data.objects.new(ob_name, me)
    me.from_pydata(coords, [], [])
    me.update()
    return ob

# Create particle setter for each frame
obj_cache = []
def particleSetter(scene, depsgraph):
    print(scene.frame_current)
    i = scene.frame_current - 1
    if i > (len(cache)) or i < 0:
        return
    
    for obj in obj_cache:
        bpy.context.collection.objects.unlink(obj)
    obj_cache.clear()
    
    data = cache[i]
    obj = make_point_cloud_mesh("point-cloud", data)
    bpy.context.collection.objects.link(obj)
    
    # Prepare particle system
    obj.modifiers.new(f"part{i}", 'PARTICLE_SYSTEM')
    part = obj.particle_systems[0]
    part.settings.count = len(data)
    part.settings.lifetime = 1
    part.settings.frame_start = 0
    part.settings.frame_end = len(cache)+1
    part.settings.use_emit_random = False
    part.settings.physics_type = 'NO'
    part.settings.display_size = .5
    part.settings.emit_from = 'VERT'
    obj_cache.append(obj)
    
bpy.context.scene.render.fps = 1 

# Clear the post frame handler
bpy.app.handlers.frame_change_post.clear()

# Run the function on each frame
bpy.app.handlers.frame_change_post.append(particleSetter)

# Update to a frame where particles are updated
bpy.context.scene.frame_current = 1
bpy.context.scene.frame_start = 1
bpy.context.scene.frame_end = len(cache)
bpy.context.view_layer.update()
print('done')

TL;DR Is there a way to produce particles for each frame of an animation using particle systems?

$\endgroup$

Your Answer

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

Browse other questions tagged or ask your own question.