Keyframed camera animation

I am trying to write an import/export script for a format that uses cameras animated through bezier curves. Each point on bezier curve in this file format has a timestamp (frame number) attributed to it. So, the speed of the camera when following the path is evaluated based on the timestamps attributed to bezier points.

In Blender, however, Follow Path constraint only gives me an option to offset camera on the curve using some sort of "Offset". How is that value calculated? I am wondering if there is any way to get the exact offset value for the case when the camera is located exactly at each bezier point.

• – user1853 Jun 12 '18 at 21:49
• That solution does not allow finding length of individual parts of the Curve (between each bezier points). I've looked into something like that, did not appear to work. – D. Skarn Jun 12 '18 at 21:52

Use a curve for each segment between timestamped camera points

For the follow path constraint, with fixed position, offset, 0 is start point and offset 1 is the other end point of curve. If instead of using an n point bezier curve, we use n - 1 "segment" beziers, we can use this feature simply.

The curve of points [p0, p1, p2] becomes two curves [p0, p1] and [p1, p2]. At the frame specified for camera to be at p1 can either be offset 1 of first segment, 0 of next Note segments don't have to be 2 point beziers, just require last point to match first point of next.

A follow path constraint is added for each segment. To make the object use the particular segment we set the influence to 1 to use this constraint 0 otherwise. (or set hide inversely). We want the influence of the constraint to be 1 when the current frame is between the end point frames (from your data), Otherwise it is set to 0 and has no effect.

The offset can be calculated using (current_frame - p0.frame) / (p1.frame - p0.frame)

A test case setup using drivers

To each bezier curve segment we add two custom propeties, "frame_start" and "frame_end" ( curve_object["frame_start"] = 44 ) indicating the frames at which to be at end points. (I've used integers here, floats would be much better in hindsight)

via UI, adjust the min / max to suit

Now we set up a couple of drivers. The use_self option of the driver is handy here. The constraint itself is self, the path is self.target, from which we can get the frame range for this curve.

setup in UI, make sure use_self is checked. Might have to click "Update Dependencies".

The driver expressions used are in_segment(self, frame) for influence, (could also drive is_expanded and hide) and segment_offset(self, frame) for offset. The argument frame is known to the driver name space and is context.scene.frame_current. Run script below to define methods and register to the driver namespace

import bpy

def in_segment(self, frame):
segment = self.target
if not segment:
print("No target")
return False
frame_start = segment.get("frame_start", 0)
frame_end = segment.get("frame_end", 0)
return frame_start <= frame < frame_end

def segment_offset(self, frame):
segment = self.target
if not segment:
print("No target")
return 0
frame_start = segment.get("frame_start", 0)
frame_end = segment.get("frame_end", 0)
duration = frame_end - frame_start
if not duration:
return 0
return (frame - frame_start) / duration

bpy.app.driver_namespace["in_segment"] = in_segment
bpy.app.driver_namespace["segment_offset"] = segment_offset


Now with this setup can add a bezier curve, set the custom properties, then add a follow path constraint, set as curve target, and the constrained object will follow that curve for the defined frame duration.

_Cube switching between four bezier circles. The constraints expand is also driven by the influence. Each circle has a 10 frame duration, hence on the smaller circle cube apppears slower. _