I’m working on a project where I set a (relatively) small number of hair strands using particle system. In Blender 2.79 I’d just loop through obj.particle_systems[0].particles
and set each particle’s location
and hair_keys[].co
. As discussed in https://developer.blender.org/T58792 this doesn’t work now in Blender 2.8, but there seems to be a workaround? (or new intended behaviour?)
Anyway, I don’t get it to work. The hair strands are not updated to the positions I try to set anymore.
So my question is: what’s currently the best way to set the hair strands’ position and shape?
I’ve made a minimal example that tries to make a row of 5 hair strands. See this comparison of the code run in Blender 2.79 and Blender 2.80, respectively:
Here is the Blender 2.79 code that gives the desired result:
import bpy
# 1. Use initial cube as object and set CYCLES
obj = bpy.data.objects['Cube']
bpy.context.scene.render.engine = 'CYCLES'
# 2. Add a particle system
psys = obj.modifiers.new("hair", 'PARTICLE_SYSTEM').particle_system
psys.settings.type = 'HAIR'
psys.settings.use_render_emitter = False
psys.settings.use_strand_primitive = True
psys.settings.cycles.radius_scale = 0.2
psys.settings.hair_step = 3
psys.settings.count = 5
# Connect and disconnect (needed, but why?)
bpy.ops.particle.disconnect_hair(all=True)
bpy.ops.particle.connect_hair(all=True)
# 3. Set hair positions vertices
for m in range(len(psys.particles)):
psys.particles[m].location = (m, 0, 0)
for n in range(len(psys.particles[m].hair_keys)):
psys.particles[m].hair_keys[n].co = (m, 0, n)
# Toggle back and forth to update viewport
bpy.ops.particle.particle_edit_toggle()
bpy.ops.particle.particle_edit_toggle()
And here is my current best attempt at the corresponding Blender 2.80 code (with some minor API-changes + the aforementioned workaround):
import bpy
# 1. Use initial cube as object and set CYCLES
obj = bpy.data.objects['Cube']
bpy.context.scene.render.engine = 'CYCLES'
# 2. Add a particle system
psys = obj.modifiers.new("hair", 'PARTICLE_SYSTEM').particle_system
psys.settings.type = 'HAIR'
obj.show_instancer_for_render = False
psys.settings.use_strand_primitive = True
psys.settings.radius_scale = 0.2
psys.settings.hair_step = 3
psys.settings.count = 5
# Connect and disconnect (needed, but why?)
bpy.ops.particle.disconnect_hair(all=True)
bpy.ops.particle.connect_hair(all=True)
""" https://developer.blender.org/T58792 """
#https://docs.blender.org/api/blender2.8/bpy.types.Depsgraph.html <--- relevant?
depsgraph = bpy.context.evaluated_depsgraph_get()
object_eval = obj.evaluated_get(depsgraph)
psys_eval = object_eval.particle_systems[0]
print('Number of particles:\n %d (psys)\n %d (psys_eval)' % (len(psys.particles), len(psys_eval.particles)))
psys = psys_eval
""" ------------------------------------------------------- """
# 3. Set hair positions vertices
for m in range(len(psys.particles)):
psys.particles[m].location = (m, 0, 0)
for n in range(len(psys.particles[m].hair_keys)):
psys.particles[m].hair_keys[n].co = (m, 0, n)
# Toggle back and forth to update viewport
bpy.ops.particle.particle_edit_toggle()
bpy.ops.particle.particle_edit_toggle()