1
$\begingroup$
        if df['time'].max() > self.longest_time:
            self.longest_time = df['time'].max()
        for name,edf in df.groupby('objectnum'):
            print(name)
            n = f"Object {name}"
            edf = edf.sort_values('time')
            initialx = edf['x'].iat[0]
            initialy = edf['y'].iat[1]
            initialz = edf['z'].iat[2]
            bpy.ops.mesh.primitive_cube_add(location=(initialx,initialy,initialz))
            orig_cube =bpy.context.view_layer.objects.active;
            orig_cube.name = n
            orig_cube.scale = (0,0,0)
            
            for i,time in enumerate(edf['time']):
                orig_cube.location[0] = edf['x'].iat[i]
                orig_cube.location[1] = edf['y'].iat[i]
                orig_cube.location[2] = edf['z'].iat[i]
                if i == edf.shape[0]-1 or i == 0:
                    orig_cube.scale[0] = 0
                    orig_cube.scale[1] = 0
                    orig_cube.scale[2] = 0
                else:
                    orig_cube.scale[0] = 100000
                    orig_cube.scale[1] = 100000
                    orig_cube.scale[2] = 100000
                orig_cube.keyframe_insert(data_path="location", frame=time)
                orig_cube.keyframe_insert(data_path='scale',frame=time)

How can I just do this with something like this? I'm trying to eliminate the for loop that loops over all the data.

if ['time'].max() > self.longest_time:
    self.longest_time = df['time'].max()
for name,edf in df.groupby('onjectnum'):
    n = f"object {name}"
    edf = edf.sort_values('time')
    initialx = edf['x'].iat[0]
    initialy = edf['y'].iat[1]
    initialz = edf['z'].iat[2]
    bpy.ops.mesh.primitive_cube_add(location=(initialx,initialy,initialz))
    orig_cube =bpy.context.view_layer.objects.active;
    orig_cube.name = n
    orig_cube.scale = (0,0,0)
    #HERE IS WHERE I NEED THE MAGIC

    #Creating a Nx3 array of locations [x,y,z]
    locations = np.array([edf['x'],edf['y'],edf['z']]).T
    orig_cube.ADD_KEYFRAMES(data_path='location',loc=locations,fame=edf['time'])
    #Creating a Nx3 array of scales with first and last instances = 0,0,0
    #With the rest being 1,1,1
    scales = np.ones((edf.shape[0],3))*10000
    scales[0,:] = 0
    scales[-1,:] = 0
    orig_cube.ADD_KEYFRAMES(data_path='scale',scale=scales,frame=edf['time'])
$\endgroup$
0

1 Answer 1

2
$\begingroup$

The pattern for this is

# Create action to hold the fcurves (choose a name)
action = bpy.data.actions.new("CubeAction")

# Action affects objects (vs shapekeys/materials/etc)
action.id_root = 'OBJECT'

# Assign action to your new cube
orig_cube.animation_data_create()
orig_cube.animation_data.action = action

# For each X Y Z component
for i in range(0, 3):
    # Create FCurve affecting location[i]
    fc = action.fcurves.new(data_path="location", index=i, action_group="Location")

    # coords is an array of length 2*(num keyframes) floats in the format
    #   [ frame, value,   frame, value,   frame, value, ... ]
    # values are the value of location[i].
    # It can be a list, array.array, numpy array, ...
    coords = ...

    # Add enough keyframe points
    fc.keyframe_points.add(len(coords) // 2)

    # Set the keyframe point values
    fc.keyframe_points.foreach_set("co", coords)

    # Set all interpolations to LINEAR
    ipo = (
        bpy.types.Keyframe.bl_rna.properties["interpolation"]
        .enum_items['LINEAR'].value
    )
    fc.keyframe_points.foreach_set("interpolation", [ipo] * len(fc.keyframe_points))


# Scale is similar, just change the fcurves.new line...

The format for coords is two values for each keyframe. coords[::2] are the frames/times and coords[1::2] are the FCurve values at those frames. You'll have to figure out how to massage your data into that form on your own, but it shouldn't be too hard.

$\endgroup$
2
  • $\begingroup$ Awesome. This seems to work for location [I haven't tried with scaling just yet.] But I notice that the interpolation between my keyframes is kinda wonky. Is there a way to set them all to LINEAR in a similar way without a loop? $\endgroup$
    – Carl
    Sep 3, 2021 at 23:37
  • $\begingroup$ Yeah, I added it in. $\endgroup$
    – scurest
    Sep 4, 2021 at 0:56

Not the answer you're looking for? Browse other questions tagged .