Page MenuHome

Cant set particles[0].hair_keys[-1].co = Vector((0,0,3))
Closed, ResolvedPublic

Description

There is no way in blender 2.8 to write hair_key[x].co to hair particle system.
Simple blend file with one particle hair and script:

bpy.context.active_object.particle_systems.active.particles[0].hair_keys[-1].co = Vector((0,0,3))

Works ok in blender 2.79. I tried to write hair_key.co to depsgraph evaluated object, but it would not work too.

Details

Type
Bug

Event Timeline

I haven't worked on Blender's source before, and found this ticket which seemed debuggable.
I found the culprit, which is in rna_ParticleHairKey_location_object_info of rna_particle.c.
In this check: if (psmd && psmd->mesh_final && psmd->psys) {, mesh_final is null, so it never finds the ParticleHairKey instance to modify. I don't really know what mesh_final is for, but I noticed that it isn't used anywhere in the function, so changing that if statement to: if (psmd && psmd->psys) { makes the problem in this ticket's description go away. I have no idea if this will cause other problems, because maybe it's important to check that mesh_final is not null.

Sebastian Parborg (zeddb) triaged this task as Confirmed, Medium priority.

I have run into this same problem writing to hair_key[x].co and I've also noticed that it's not just the ParticleHairKey that can't be found. When I try to access it, the Particle instance can't be found either.

If I'm looking for

C.object.particle_systems[0].particles[0].hair_key[0].co

reading from

C.object.particle_systems[0].particles[0]

also fails, which used to work in 2.79.

The problem goes far deeper:
Depsgraph copies every object and all their parts including ParticleSystemModifierData.
The copy of ParticleSystemModifierData is used in deformVerts and gets a mesh_final assigned.
However, the rna_ParticleHairKey_location_object_info looks in the original object for the ParticleSystemModifierData and that one never gets a mesh_final.
rna_ParticleHairKey_location_object_info also does a linear search over all hairs for every access to a HairKey which is extremely inefficient.

Thus, rna_ParticleHairKey_location_object_info is fundamentally broken in two ways: Its performance and it can never output a ParticleData pointer.
As the comment in the source code says, a fix would be storing all needed pointers like ParticleSystemModifierData and ParticleData in the ParticleHairKey pointerRNA.
Here an example of how the pointers of copies look like:

direct_link_modifiers psmd=0x7fbd0577d528

deg_expand_copy_on_write_datablock id_orig=0x7fbd062dde08 id_cow=0x7fbd06426c08 id_cow_recalc=0x2087
BKE_object_copy_data ob_dst=0x7fbd06426c08 ob_src=0x7fbd062dde08
initData psmd=0x7fbd05a134d8
copyData dst_psmd=0x7fbd05a134d8 src_psmd=0x7fbd0577d528
deformVerts psmd=0x7fbd05a134d8 psmd->mesh_final=0x7fbd0624d008

deg_expand_copy_on_write_datablock id_orig=0x7fbcfef17408 id_cow=0x7fbd0630ec08 id_cow_recalc=0xffffff83
freeData psmd=0x7fbd05a134d8
deg_expand_copy_on_write_datablock id_orig=0x7fbd062dde08 id_cow=0x7fbd06426c08 id_cow_recalc=0x2002
BKE_object_copy_data ob_dst=0x7fbd06426c08 ob_src=0x7fbd062dde08
initData psmd=0x7fbd05a008f8
copyData dst_psmd=0x7fbd05a008f8 src_psmd=0x7fbd0577d528
deformVerts psmd=0x7fbd05a008f8 psmd->mesh_final=0x7fbd001dc208

rna_ParticleHairKey_location_object_info ptr=0x11d1db198 hkey=0x7fbd057a79f8 ob=0x7fbd062dde08
    psmd=0x7fbd0577d528 psmd->mesh_final=0x0 psmd->psys=0x7fbd057333b8
rna_ParticleHairKey_location_object_set ptr=0x11d1db198 psmd=0x0 pa=0x0

Note: The mesh_final is necessary because blender stores all HairKeys relative to their emitter mesh surface if the PSYS_HAIR_DYNAMICS flag is not set. See the use of psys_mat_hair_to_object in rna_ParticleHairKey_location_object_get and rna_ParticleHairKey_location_object_set.

Jose Conseco (joseconseco) closed this task as Resolved.EditedSat, May 18, 1:03 PM

After new depsgraph changes I tried to set particle hair keys co again, and got it working. Sollution:

obj = bpy.context.active_object
depsgraph = bpy.context.evaluated_depsgraph_get()
object_eval = obj.evaluated_get(depsgraph)
object_eval.particle_systems.active.particles[0].hair_keys[-1].co = Vector((0,0,3))

Then tab into particle editmode, and out. I should update hair position. Not sure if there is better way (without tab)