2
$\begingroup$

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?

$\endgroup$
2
  • $\begingroup$ That should be really easy if you know the distance $\endgroup$
    – Rick Riggs
    Commented Feb 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 Riggs
    Commented Feb 8, 2018 at 21:56

2 Answers 2

4
$\begingroup$

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'])
$\endgroup$
1
  • $\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$ Commented Feb 7, 2021 at 15:12
1
$\begingroup$

Shift + A >> E >> P enter image description here

Set X Location to 1.00000 enter image description here

Add another Empty (it will automatically be named 'Empty.001')

Shift + A >> E >> P enter image description here

Now add a Camera

Shift + A >> E >> P enter image description here

Position the Camera as follows:

[1.00000, 0.00000, 0.00000]

Rotate the Angles as follows:

90°, 0°, 90° enter image description here

With the Camera still selected...

Shift + Select the First Empty >> Ctrl + P >> K (Object (Keep Transform)) enter image description here

Next select only the first Empty and add a Track To Modifier enter image description here

Then set the Target to: Empty.001

Then set To to: -X enter image description here


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. enter image description here

Here's an example of the result

enter image description here

$\endgroup$

You must log in to answer this question.

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