# Pointing the camera in a particular direction programmatically

I'm trying to use Python to place a camera. I know the camera's location, and the forward and up vectors for the camera (i.e. the direction it's pointing and its orientation). How do I do this?

I know that it's possible to calculate a raw world matrix from the above information, which I can then apply to the camera, but I was rather hoping not to have to. Is there an easier way?

• do you want to set the cameras direction in the game engine? – stacker Dec 1 '13 at 17:35
• No, I'm writing a script to create a scene with the camera in a specific location. – David Given Dec 1 '13 at 17:37

## 3 Answers

Heres a script to make a camera point towards any point in space.

import bpy

def look_at(obj_camera, point):
loc_camera = obj_camera.matrix_world.to_translation()

direction = point - loc_camera
# point the cameras '-Z' and use its 'Y' as up
rot_quat = direction.to_track_quat('-Z', 'Y')

# assume we're using euler rotation
obj_camera.rotation_euler = rot_quat.to_euler()

# Test
obj_camera = bpy.data.objects["Camera"]
obj_other = bpy.data.objects["Cube"]

obj_camera.location = (5.0, 2.0, 3.0)
look_at(obj_camera, obj_other.matrix_world.to_translation())

• I'm afraid I don't understand this --- the docs for to_track_quat() are... brief. I don't see how the fixed axis parameters get rotated to point in my desired direction. (When I say I have the location and forward and up vectors, I mean literally I have a Point and two Vector objects.) Can you expand? – David Given Dec 2 '13 at 18:22
• The camera starts off pointing along the -Z axis with the top of the camera pointing along the +Y axis. The variable "direction" is the vector from the camera to the point. The function direction.to_track_quat('-Z', 'Y') returns the quaternion that rotates '-Z' so that it aligns with the direction vector. This rotation is not unique because the rotated camera can still rotate about direction vector. Specifying Y gives the rotation quaternion with the -Z vector aligned with the direction vector and the Y vector pointing up. – Chuck Nov 23 '16 at 23:59
• You might want to call bpy.context.scene.update() after changing the camera's location to make sure the matrix is up to date. – Daerst Mar 26 '19 at 10:15

Here is a version of ideasman42's look_at function that also allows you to roll the camera (or any object) about the axis from camera to target:

def point_at(obj, target, roll=0):
"""
Rotate obj to look at target

:arg obj: the object to be rotated. Usually the camera
:arg target: the location (3-tuple or Vector) to be looked at
:arg roll: The angle of rotation about the axis from obj to target in radians.

Based on: https://blender.stackexchange.com/a/5220/12947 (ideasman42)
"""
if not isinstance(target, mathutils.Vector):
target = mathutils.Vector(target)
loc = obj.location
# direction points from the object to the target
direction = target - loc

quat = direction.to_track_quat('-Z', 'Y')

# /usr/share/blender/scripts/addons/add_advanced_objects_menu/arrange_on_curve.py
quat = quat.to_matrix().to_4x4()
rollMatrix = mathutils.Matrix.Rotation(roll, 4, 'Z')

# remember the current location, since assigning to obj.matrix_world changes it
loc = loc.to_tuple()
#obj.matrix_world = quat * rollMatrix
# in blender 2.8 and above @ is used to multiply matrices
# using * still works but results in unexpected behaviour!
obj.matrix_world = quat @ rollMatrix
obj.location = loc


It can be used like this:

import math
cube = bpy.data.objects["Cube"]
cube.location = (5, -5, 5)
cam = bpy.data.objects["Camera"]
cam.location = (5, -5, -2)
point_at(cam, cube.location, roll=math.radians(45)) One way is to assign tuples directly to the camera object's location and rotation_euler attributes. For example, with the camera selected:

import bpy
from math import radians

camera = bpy.context.object
camera.location = (1.0, 0.0, 1.0)
camera.rotation_euler = (radians(45), 0.0, radians(30))