1
$\begingroup$

I'm trying to use python to get world space location and rotation values of an animated camera, including transformations applied trough parents and constraints.

I need the Values as XYZ coordinates and XYZ rotation in degrees. I can achieve this by manually selecting object>animation>bake action with the options "Visual Keying", "Clear Constraints" and "Clear Parents" enabled: bake action options

And then accessing the data from the baked camera with python using

import bpy
import sys
import mathutils
from math import degrees

    cameraRotationX = degrees(bpy.data.objects["Camera"].rotation_euler[0])
    cameraRotationY = degrees(bpy.data.objects["Camera"].rotation_euler[1])
    cameraRotationZ = degrees(bpy.data.objects["Camera"].rotation_euler[2])
    
    cameraLocationX = bpy.data.objects["Camera"].location[0]
    cameraLocationY = bpy.data.objects["Camera"].location[1]
    cameraLocationZ = bpy.data.objects["Camera"].location[2]

    print("Camera rotation X: ","%.7f" %cameraRotationX)
    print("Camera rotation Y: ","%.7f" %cameraRotationY)
    print("Camera rotation Z: ","%.7f" %cameraRotationZ)

    print("Camera Location X: ","%.7f" %cameraLocationX)
    print("Camera Location Y: ","%.7f" %cameraLocationY)
    print("Camera Location Z: ","%.7f" %cameraLocationZ)

This works fine and it gives me the correct Values, including multiple rotations of the camera, for example 720°. However, I need to go through the process of baking first and I can't change the animation after that, unless I duplicate the object before baking to preserve the editable animation.

Is there a way to get the same values directly in python without going through the baking process first? I tried

rotation=bpy.data.objects['Camera'].matrix_world.to_euler('XYZ')
location=bpy.data.objects['Camera'].matrix_world.to_translation()

rotationX=degrees(rotation[0])
rotationY=degrees(rotation[1])
rotationZ=degrees(rotation[2])

locationX=location[0]
locationY=location[1]
locationZ=location[2]

But this does not result in the same rotation values.

I am a newbie to python and blender, as well as to matrices and the corresponding calculations. So maybe I am missing something obvious.

Can somebody please pint me in the right direction? If there is a way to programmatically bake the animation without losing the original animation, that would help as well.

The reason for this is that I am using the location and rotation values to control a robot arm. I want wo be able to adjust the animation and get the resulting Values without having to go back and forth with baking. I hope that makes sense.

Any input would be appreciated. Thanks.

$\endgroup$

1 Answer 1

3
$\begingroup$

The baking code is actually in Python, so you can copy what it does. The relevant part is this I think.

The way it knows if rotations should be >360° is it remembers the Euler from the previous frame and makes the current Euler "compatible" with it (adds or subtracts multiples of 360° so its close to the previous one I assume). There's a make_compatible function, but you can also pass the previous Euler to to_euler.

So try this to get it at a bunch of different frames:

euler_prev = None
ob = bpy.data.objects['Camera']

for f in range(start_frame, end_frame):
    bpy.context.scene.frame_set(f)
    bpy.context.view_layer.update()
    matrix = ob.matrix_world

    # Location
    loc = matrix.to_translation()

    # Euler Rotation
    if euler_prev is None:
        euler = matrix.to_euler(ob.rotation_mode)
    else:
        euler = matrix.to_euler(ob.rotation_mode, euler_prev)
    euler_prev = euler.copy()

    # Do something with loc and euler...
$\endgroup$
1
  • 1
    $\begingroup$ Awesome, this way it works exactly as needed! Thanks so much for the quick and detailed reply! Make compatible was the part that was missing. I spent hours on this but did not manage to find the right solution. Made my day. $\endgroup$
    – Dave
    Commented Sep 25, 2021 at 16:25

You must log in to answer this question.

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