Converting Hair object particles to Animated Meshes problem with python script

Hey, new to blender, a brilliant script by Jasper van Nieuwenhuizen converts each frame of a particle system into mesh instances that are animated based on the loc/rot/scale of the original particle system.
I’m trying to modify his code to apply to my hair particle system that uses objects as strands.
I can’t get his code to keyframe the loc/rot/scale of the hair particles properly to my meshes.

What particle information am I getting wrong?

Individual meshes are generating fine, keyframes are being generated for each frame, but the rotation, location and scale are wrong… AND, the animated loc/rot/scale of the mesh isn’t changing to match the baked loc/rot/scale changes of the hair/particles (or, is there already a feature that converts baked hair particles into ANIMATED meshes inside of blender that I’m unaware of?)

The code works by selecting the proxy object first, and then selecting the particle system second (so that it is active).

import bpy

def create_objects_for_particles(ps, obj):
    # Duplicate the given object for every particle and return the duplicates.
    # Use instances instead of full copies.
    obj_list = []
    mesh =
    for i, _ in enumerate(ps.particles):
        dupli =
    return obj_list

def match_and_keyframe_objects(ps, obj_list, start_frame, end_frame):
    # Match and keyframe the objects to the particles for every frame in the
    # given range.
    for frame in range(start_frame, end_frame + 1):
        for p, obj in zip(ps.particles, obj_list):
            match_object_to_particle(p, obj)

def match_object_to_particle(p, obj):
    # Match the location, rotation, scale and visibility of the object to
    # the particle.
    loc = p.location 
    rot = p.rotation
    size = p.size
    vis = True
    obj.location = loc
    # Set rotation mode to quaternion to match particle rotation.
    obj.rotation_mode = 'QUATERNION'
    obj.rotation_quaternion = rot
    obj.scale = (size, size, size)
    obj.hide = False
    obj.hide_render = False

def keyframe_obj(obj):
    # Keyframe location, rotation, scale and visibility if specified.

def main():
    # Assume only 2 objects are selected.
    # The active object should be the one with the particle system.
    ps_obj = bpy.context.object
    obj = [obj for obj in bpy.context.selected_objects if obj != ps_obj][0]
    ps = ps_obj.particle_systems[0]  # Assume only 1 particle system is present.
    start_frame = bpy.context.scene.frame_start
    end_frame = bpy.context.scene.frame_end
    obj_list = create_objects_for_particles(ps, obj)
    match_and_keyframe_objects(ps, obj_list, start_frame, end_frame)

if __name__ == '__main__':

I believe that the hair matrix information is in the {co}, but I’m wondering how to integrate that information back into loc/rot/scale coordinates for meshes like the code found above.

import bpy

object = bpy.context.object
hairs = object.particle_systems[0].particles
for i, h in enumerate(hairs):
    print('hair number {i}:'.format(i=i))
    for i, hv in enumerate(h.hair_keys):
        print('  vertex {i} coordinates: {co}'.format(i=i,

Thanks guys, I’m not sure where stuff like this is found in the blender wiki.

(I’m trying to attach a sample file but having trouble with the baked 100MB .blend upload at the moment… so you can try here, if I’m allowed to use outside links: )

Thanks for those who looked into this. I ended up utilizing an ugly loop of the properties>modifiers>“convert” function in a python script that acts like a repeating macro. My contribution to the code is too inelegant to post publicly :wink: but it calls “bpy.ops.object.duplicates_make_real(use_hierarchy=False, use_base_parent=False)” by frame, keyframes the loc/rot/scale, deletes the duplicate mesh… then repeats for the next frame. Copy back to the first keyframe, and there you go–meshed and looped.

Could you still post the code you made ? I didn’t find any way to convert animated hair to animated mesh and I am not good enough with Python to figure it out myself.
I would say that generally, even if a script is “inelegant”, if it can get the job done, then it can help the community. You may just have to precise that it could be more efficient or cleaner.