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.EditedMay 18 2019, 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)

Does not work for me it seems.
It does not matter how much I switch between object, particle and edit modes.

And others still have the same problem:
https://blender.stackexchange.com/questions/134532/blender-2-8-dynamically-set-particle-locations-via-python

@Jose Conseco (joseconseco) That seems more like a work-around to the actual problem. If the original problem is still there, then this ticket should not be set to Resolved.

But this seems to work ok. There is other problem preventing writing to hair positions: https://developer.blender.org/T64805.
Try adding cache manualy, then solution mentioned 2 posts above will work.