0
$\begingroup$

Following this example I added a psys to my scene. I add the cube from the script because for this application I CAN NOT use the GUI, so adding this snippet:

bpy.ops.mesh.primitive_cube_add(size=0.25, calc_uvs=True, enter_editmode=False, align='WORLD',
                                    location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0))
    bpy.context.active_object.name = 'Cube'
def particleSetter(self):
    particle_systems = object.evaluated_get(degp).particle_systems
    particles = particle_systems[0].particles
    totalParticles = len(particles)

    scene = bpy.context.scene
    cFrame = scene.frame_current
    sFrame = scene.frame_start

    # at start-frame, clear the particle cache
    if cFrame == sFrame:
        psSeed = object.particle_systems[0].seed
        object.particle_systems[0].seed = psSeed

    # Rotate particles based on index (t_p) and frame (t_f)
    t_p = np.linspace(0, 2*np.pi, totalParticles, endpoint=False)
    t_f = cFrame / 20.0
    data = np.array([np.sin(t_p + t_f), np.cos(t_p + t_f), np.zeros(t_p.shape)]).T
    flatList = data.ravel()

    # Set the location of all particle locations to flatList
    particles.foreach_set("location", flatList)
    

# Prepare particle system
object = bpy.data.objects["Cube"]
object.modifiers.new("ParticleSystem", 'PARTICLE_SYSTEM')
object.particle_systems[0].settings.count = 10
object.particle_systems[0].settings.frame_start = 1
object.particle_systems[0].settings.frame_end = 1
object.particle_systems[0].settings.lifetime = 1000
object.show_instancer_for_viewport = False
degp = bpy.context.evaluated_depsgraph_get()

#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 = 2

I would expect to see particles, but nothing is shown in the render. Also, if I set

object.particle_systems[0].settings.type = 'HAIR'

I see the spikes, but I want particles that whose location can be specified, not just spikes on a surface. Whant am I doing wrong?

Edit: I tried to specify the object instantiation, still no effect:

bpy.ops.mesh.primitive_cube_add(size=0.25, calc_uvs=True, enter_editmode=False, align='WORLD',
                                location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0))
bpy.context.active_object.name = 'Cube'
context = bpy.context
dg = context.evaluated_depsgraph_get()
ob = dg.objects.get("Cube")
ob.modifiers.new("ParticleSystem", 'PARTICLE_SYSTEM')
ps = ob.particle_systems.active
ps.settings.render_type = "OBJECT"
ps.settings.display_method = "RENDER"
ps.settings.instance_object = ob
po = ps.settings.instance_object
for p in ps.particles:
    p.location = (5*np.random.rand(), 5*np.random.rand(), 5*np.random.rand())
bpy.context.view_layer.update()
$\endgroup$
2
  • $\begingroup$ As mentioned in blender.stackexchange.com/questions/134532/… above will work as expected if instancing an object via ps. Please see later examples of link in question re the arguments of the handler being scene and depsgraph. (IMO do not mix context with handlers, the evaluated object in this case is obj = depsgraph.objects.get("Cube") Later on speculates render anim with render still + frame set. Related blender.stackexchange.com/questions/142741/…` $\endgroup$
    – batFINGER
    Jun 29, 2021 at 17:13
  • $\begingroup$ @batFINGER thanks for your comment, but I am still not getting the expected result. I tried to specify object instancing like in the edited question, but still no cube is shown in the render. $\endgroup$ Jun 29, 2021 at 23:16

1 Answer 1

3
$\begingroup$

Instance object.

Re question edit

I tried to specify the object instantiation, still no effect:

As mentioned in Blender 2.8: dynamically set particle locations via python above will work as expected if instancing an object via ps.

Please see later examples of link in question re the arguments of the handler being scene and depsgraph. (IMO do not mix context with handlers, the evaluated object in this case is obj = depsgraph.objects.get("Cube") Or whatever the name of our cube object

Notice link Later on speculates render anim with render still + frame set. The issue re moved hair particles not rendering is also expanded on here How do I programmatically set hair position and shape in Blender 2.8? (albeit also misleadingly using self as handler argument)

Here is a basic test script,

  • adds ico as instance object

  • adds a cube as emitter

  • adds basic PS to cube using ico as object

  • defines a handler method

  • gives particles vert number for X and animates in Z using current frame.

 

import bpy
context = bpy.context

# instance object
bpy.ops.mesh.primitive_ico_sphere_add()
ico = context.object
#ico.hide_set(True)


# cube with ps
bpy.ops.mesh.primitive_cube_add()
cube = context.object


# ps

ps = cube.modifiers.new("SomeName", 'PARTICLE_SYSTEM').particle_system
psname = ps.name
ps.settings.count = 8
ps.settings.lifetime = 1000
ps.settings.frame_start = ps.settings.frame_end = 1
ps.settings.render_type = "OBJECT"
ps.settings.instance_object = ico

def particle_handler(scene, depsgraph):
    ob = depsgraph.objects.get(cube.name)
    if ob:
        ps = ob.particle_systems[psname]
        f = scene.frame_current
        for m, particle in enumerate(ps.particles):
            setattr(particle, "location", (m, 0, f / 20))


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

# Register our particleSetter with the post frame handler
bpy.app.handlers.frame_change_post.append(particle_handler)

# Trigger frame update
bpy.context.scene.frame_current = 0

Tip.

Since you are running blender headless, suggest splitting up scripts, for example read_factory_settings makes all other operators call fail in a python script ran at startup

For above a script to create the scene objects particle systems etc another to set up handlers. Since the cube is added last in script above, it will be the context object going forward.

Can pass variables to be used in scripts via How to pass command line arguments to a Blender Python script?

Lastly, object is a python built in type for the generic object type. Good practice to avoid redefining, as, depending on scope, (python is forgiving) a later call to eg obj = object() will fail.

$\endgroup$
1
  • $\begingroup$ It, worked, but only after setting bpy.context.scene.frame_current = 2 It is quite weird, considering that the psys should end at frame 1, but it works. $\endgroup$ Jun 30, 2021 at 15:32

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.