2
$\begingroup$

Hello guys!

To programmatically add a constraint to the camera in my scene, I do the following:

import bpy
from mathutils import Vector
from mathutils import Quaternion
import random

camera = bpy.data.objects.get("Camera")
target_object = bpy.data.objects.get("Cube")

camera.constraints.clear()
track_to = camera.constraints.new('TRACK_TO')
track_to.target = target_object
track_to.track_axis = 'TRACK_NEGATIVE_Z'
track_to.up_axis = 'UP_Y' # <- is it possible to change this somehow?

This works fine and the camera correctly follows the cube. However, for my task, I need the camera constraint to randomly change the selected up_axis to an arbitrary vector on the plane, which lies orthogonal to the track_axis every time I run the script. I hope Figure 1 clarifies my goal. Is there a simple way to do this?

I already tried:

loc, rot, scale = camera.matrix_world.decompose()
new_rot = Quaternion(rot.axis, random.uniform(-180, 180))
camera.constraints.clear() # <- seems to be required for the rotation changes to take effect
camera.rotation_quaternion = new_rot

But this approach causes the camera to entirely lose focus on the cube.

Thank you in advance!

Wanted functionality.

$\endgroup$
7
  • $\begingroup$ Is the script supposed to be run for each frame? $\endgroup$
    – lemon
    Sep 9, 2020 at 9:33
  • $\begingroup$ Hello @lemon! The script will be used to generate an arbitrary amount of renderings. Every possible rotation of the camera, as shown in the figure, must be equally likely (uniform distribution), but there is no need to "animate" something or "to call the script for each frame". The workflow should be as follows: add "Track To" constraint to camera -> randomly change camera position -> randomly change rotation around "Track axis" -> take photo. This should be repeated as often as the user wants it to do so. $\endgroup$
    – alfa98
    Sep 9, 2020 at 9:50
  • $\begingroup$ So do you really need the track to constraint? Why don't you align the cam to the target by the script itself? $\endgroup$
    – lemon
    Sep 9, 2020 at 9:51
  • 2
    $\begingroup$ Could do it using this approach for instance: blender.stackexchange.com/a/73013/19156 $\endgroup$
    – lemon
    Sep 9, 2020 at 9:57
  • 1
    $\begingroup$ Thank you for the tip, @lemon. The linked answer gave me an idea. This answer does the job perfectly. $\endgroup$
    – alfa98
    Sep 9, 2020 at 13:28

1 Answer 1

3
$\begingroup$

Align to and roll on vector.

enter image description here

In a related question showed the math of aligning an object to the view as defined by the camera, instead here will align the camera -Z axis to the object and roll the camera randomly around it.

  • Vector v2 is the global direction camera faces

  • Vector v1 is the vector defined looking at camera from object

  • The rotational difference between the two gives us the rotation required to make camera point at object

  • Change the space to rotate about the origin point of the object in global space.

  • Make another random rotation matrix to roll about this point about the axis v1

Test script (often would use context object for cube and scene camera for camera, to avoid need to edit and run, rather simply change active object)

import bpy
from mathutils import Vector
from mathutils import Matrix
from math import radians
from random import random

camera = bpy.data.objects.get("Camera")
target_object = bpy.data.objects.get("Cube")

cmw = camera.matrix_world
tmw = target_object.matrix_world

v1 = tmw.translation - cmw.translation
v2 = cmw.to_3x3() @ Vector((0, 0, -1))

R = (Matrix.Translation(cmw.translation) @ 
    v2.rotation_difference(v1).to_matrix().to_4x4() @ 
    Matrix.Rotation(random() * radians(360), 4, v1.normalized()) @ 
    Matrix.Translation(-cmw.translation))

camera.matrix_world = R @ cmw

Possibly worth mentioning, could do same by rolling first on v2

R = (Matrix.Translation(cmw.translation) @ 
     Matrix.Rotation(random() * radians(360), 4, v2.normalized()) @ 
     v2.rotation_difference(v1).to_matrix().to_4x4() @        
     Matrix.Translation(-cmw.translation))

Make a dolly

Another approach would be make an empty, parent camera to empty. Track the empty to the cube. Simply roll the camera using the z axis.

Examples.

https://blender.stackexchange.com/a/130456/15543

https://blender.stackexchange.com/a/176762/15543

$\endgroup$
1
  • $\begingroup$ Thank you very much, @batFINGER. That's exactly what I needed. $\endgroup$
    – alfa98
    Sep 10, 2020 at 6:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.