5

I have a path of 6 DOF camera poses. Say my path has 100 frames, so I have a 6x100 matrix.

Now in blender, I want my camera to follow exactly that path. I have seen tutorials about creating a path and modify the path shape. However, that won't give me precisely the path I want.

How can I do this?

David
  • 49,291
  • 38
  • 159
  • 317
  • Can you elaborate on "that won't give me precisely the path I want"? What exactly isn't as it should be? Is it the actual shape of the path or is it the timing that's lacking? – Oliver Giesen Mar 18 '16 at 08:56
  • If it is about the timing (i.e. controlling when the camera is at what point of your path), then you might want to look at http://blender.stackexchange.com/a/21046/1259 – Oliver Giesen Mar 18 '16 at 09:29

1 Answers1

3

I have been searching for help about this for a long time. The answer would be "not using follow path", use "keyframe on camera transform" instead. Path is a set of points with no direction, while you need a 6 DOF description of camera motion.

Here's some Python scripts. Assuming you have camera pose in translation + quaternion format.

camera name in blender: Camera

camera pose data: PATHTO_pose.txt

data_format:
           frame  x            y           z            qx         qy           qz           qw
PATHTO_pose.txt:
           1      26.211       7.1004      24.8995      0.97571    0.0402501    -0.212604    -0.034192
           2      26.1915      7.12682      24.8661     0.975725    0.0402611    -0.212369   -0.0351898
           3      26.1693      7.15424      24.9107     0.975688    0.0406072    -0.212337   -0.0360215
           ...
import bpy
import numpy as np
import math
from mathutils import *

bridge_M_CV_blender = Quaternion((0.0, 1.0, 0.0, 0.0)).to_matrix().to_4x4()

def read_pose(pose_path): camera_pose_raw = np.loadtxt(pose_path) rows = camera_pose_raw.shape[0] cols = camera_pose_raw.shape[1] # cols should be 8, [frame x y z dx dy dz dw] if cols != 8: raise ValueError('cols of pose.txt should be 8, [frame x y z dx dy dz dw]') start_frame = int(camera_pose_raw[0][0]) end_frame = int(camera_pose_raw[-1][0]) movement_list = [] # identity mat for unknown pose frame_id_list = [] for x in range(0, rows): curr_quat = Quaternion( (camera_pose_raw[x][7], camera_pose_raw[x][4], camera_pose_raw[x][5], camera_pose_raw[x][6])) # (w,x,y,z) curr_loca = Vector((camera_pose_raw[x][1], camera_pose_raw[x][2], camera_pose_raw[x][3])) # (x,y,z) curr_loca *= 1 # modify if translation in blender is not appropriate curr_mat = curr_quat.to_matrix() curr_mat = curr_mat.to_4x4() curr_mat.translation = curr_loca movement_list.append(curr_mat) frame_id_list.append(int(camera_pose_raw[x][0])) return movement_list, frame_id_list, start_frame, end_frame

def key_frame_insert(obj_name, camera_tracefile, set_scene_frame=True): bpy.ops.object.select_all(action='DESELECT') cam_obj = bpy.data.objects[obj_name] cam_obj.rotation_mode = 'QUATERNION' start_pose = Euler((math.pi / 2, 0, math.pi / 2)).to_matrix().to_4x4() movement_poses, frame_id_list, start_frame_id, end_frame_id = read_pose(camera_tracefile) if set_scene_frame: bpy.data.scenes["Scene"].frame_start = start_frame_id bpy.data.scenes["Scene"].frame_end = end_frame_id global_poses = [] for mat, f_id in zip(movement_poses, frame_id_list): curr_frame_global_pose = start_pose @ bridge_M_CV_blender.inverted() @ mat @ bridge_M_CV_blender global_poses.append(start_pose @ mat) cam_obj.location = curr_frame_global_pose.to_translation() cam_obj.rotation_quaternion = curr_frame_global_pose.to_quaternion() cam_obj.keyframe_insert(data_path="location", frame=f_id) cam_obj.keyframe_insert(data_path="rotation_quaternion", frame=f_id) print("keyframe insterted in frame", f_id) return 0

if name == 'main': trace_path = "PATHTO_pose.txt" key_frame_insert("Camera", trace_path)

bridge_M_CV_blender is used for converting camera pose between different camera coordinate system "Blender(z-backward,x-rightward,y-upward) and CV(z-forward, x-right ward,y-downward)"

function read_pose read camera pose from file and turn them into bpy matrix format.

function key_frame_insert insert movement generated by read_poseto camera keyframe.

If you want to use Euler rotation (since you were saying 6x100 matrix), you need to do some work on function read_pose.

vicky Lin
  • 31
  • 5
  • 1
    Since you have read the data into a numpy array could bake this to fcurves very quickly. See the fcurve method in this example https://blender.stackexchange.com/a/239656/15543 – batFINGER Oct 09 '21 at 03:12
  • 1
    That's an idea. Modify object.animation_data directly will truly be quicker. – vicky Lin Oct 09 '21 at 07:29