I want to position the camera around an object using Blender's Python API. Assuming that an object is centered at (0, 0, 0)
, I want to move the camera around it given a set of known (x, y, z)
coordinate values while keeping its focus on the point (0, 0, 0)
and its distance to middle of the object to be dist
, a constant. I wonder how I can do that in Python?
-
$\begingroup$ That should be really easy if you know the distance $\endgroup$– Rick RiggsFeb 8, 2018 at 21:55
-
$\begingroup$ As a matter of fact that should be easy even if you don't, we can calculate distance from to known points (Camera & Origin). Give me a few, I'll post an answer to this. $\endgroup$– Rick RiggsFeb 8, 2018 at 21:56
2 Answers
The next function will rotate the camera towards the focus point. And then place the camera at a certain distance. The location of camera will only change along the direct line with the focus point.
import bpy
import mathutils
def update_camera(camera, focus_point=mathutils.Vector((0.0, 0.0, 0.0)), distance=10.0):
"""
Focus the camera to a focus point and place the camera at a specific distance from that
focus point. The camera stays in a direct line with the focus point.
:param camera: the camera object
:type camera: bpy.types.object
:param focus_point: the point to focus on (default=``mathutils.Vector((0.0, 0.0, 0.0))``)
:type focus_point: mathutils.Vector
:param distance: the distance to keep to the focus point (default=``10.0``)
:type distance: float
"""
looking_direction = camera.location - focus_point
rot_quat = looking_direction.to_track_quat('Z', 'Y')
camera.rotation_euler = rot_quat.to_euler()
# Use * instead of @ for Blender <2.8
camera.location = rot_quat @ mathutils.Vector((0.0, 0.0, distance))
update_camera(bpy.data.objects['Camera'])
-
$\begingroup$ I just wanted to point out that this answer is also useful for (re-)orienting lights as well!!! It's just a matter of passing a light object in the camera variable. Thanks to J Bakker!!! $\endgroup$ Feb 7, 2021 at 15:12
Add another Empty (it will automatically be named 'Empty.001')
Now add a Camera
Position the Camera as follows:
[1.00000, 0.00000, 0.00000]
Rotate the Angles as follows:
With the Camera still selected...
Shift + Select the First Empty >> Ctrl + P >> K (Object (Keep Transform))
Next select only the first Empty and add a Track To Modifier
Then set the Target to: Empty.001
Here's the Python Code to do basically all of the same steps as above
import bpy
import math
bpy.ops.object.empty_add(type='PLAIN_AXES', view_align=False, location=(0, 0, 0), layers=(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
bpy.ops.object.empty_add(type='PLAIN_AXES', view_align=False, location=(0, 0, 0), layers=(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
newEmpties = []
for objName in bpy.data.objects.keys():
if(len(objName.split("mpty")) > 1):
newEmpties.append(objName)
#
print("-----")
print(len(newEmpties))
print("-----")
for i in newEmpties:
print(i)
cnt = len(newEmpties)
myEmpties = []
myEmpties.append(newEmpties[cnt - 2])
myEmpties.append(newEmpties[cnt - 1])
e1 = bpy.data.objects[myEmpties[0]]
e2 = bpy.data.objects[myEmpties[1]]
e1.location.x = 1.0
bpy.ops.object.camera_add(view_align=True, enter_editmode=False, location=(0, 0, 0), rotation=(0.961699, 0.0122912, -0.897371), layers=(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
newCams = []
for objName in bpy.data.objects.keys():
if(len(objName.split("amera")) > 1):
newCams.append(objName)
#
myCam = bpy.data.objects[newCams[len(newCams) - 1]]
myCam.location.x = 1.0
myCam.rotation_euler.x = math.pi * 0.5
myCam.rotation_euler.z = math.pi * 0.5
bpy.ops.object.select_all(action='DESELECT')
myCam.select = True
e1.select = True
bpy.context.scene.objects.active = e1
bpy.ops.object.parent_set(type='OBJECT', keep_transform=True)
bpy.ops.object.constraint_add(type='TRACK_TO')
e1.constraints['Track To'].target = e2
e1.constraints['Track To'].track_axis = 'TRACK_NEGATIVE_X'
bpy.context.scene.objects.active = myCam
scene = bpy.data.scenes['Scene']
scene.camera = myCam
For Blender >2.8 (new python api)
import bpy
import math
def pointACamTo(toPoint, fromPoint):
bpy.ops.object.empty_add(type='PLAIN_AXES', location=fromPoint)
bpy.ops.object.empty_add(type='PLAIN_AXES', location=toPoint)
newEmpties = []
for objName in bpy.data.objects.keys():
if(len(objName.split("mpty")) > 1):
newEmpties.append(objName)
#
print("-----")
print(len(newEmpties))
print("-----")
for i in newEmpties:
print(i)
cnt = len(newEmpties)
myEmpties = []
myEmpties.append(newEmpties[cnt - 2])
myEmpties.append(newEmpties[cnt - 1])
e1 = bpy.data.objects[myEmpties[0]]
e2 = bpy.data.objects[myEmpties[1]]
e1.location.x = fromPoint[0]
e1.location.y = fromPoint[1]
e1.location.z = fromPoint[2]
bpy.ops.object.camera_add(align='VIEW', enter_editmode=False, location=(0, 0, 0), rotation=(0.961699, 0.0122912, -0.897371))
newCams = []
for objName in bpy.data.objects.keys():
if(len(objName.split("amera")) > 1):
newCams.append(objName)
#
myCam = bpy.data.objects[newCams[len(newCams) - 1]]
#myCam.location.x = fromPoint[0]
myCam.location.x = fromPoint[0]
myCam.location.y = fromPoint[1]
myCam.location.z = fromPoint[2]
myCam.rotation_euler.x = math.pi * 0.5
myCam.rotation_euler.z = math.pi * 0.5
bpy.ops.object.select_all(action='DESELECT')
myCam.select = True
e1.select = True
#bpy.context.scene.objects.active = e1
# wrong, read-only bpy.context.active_object = e1
# select: eventually remove
# wrong, for multiple selection eventually: e1.select_set(True)
bpy.context.view_layer.objects.active = e1
bpy.ops.object.parent_set(type='OBJECT', keep_transform=True)
bpy.ops.object.constraint_add(type='TRACK_TO')
e1.constraints['Track To'].target = e2
e1.constraints['Track To'].track_axis = 'TRACK_NEGATIVE_X'
# as safety measure:
##deselectAllObjectsInScene()
# eventually remove
#bpy.context.scene.objects.active = myCam
bpy.context.view_layer.objects.active = myCam
scene = bpy.data.scenes['Scene']
scene.camera = myCam
#and run
pointACamTo([0,0,0], [2,2,2])
Now in a separate python script you can use a function like follows to position the camera to a point.
Here's an example of the result