2
$\begingroup$

I'm trying to use blender to test the probabilities associated with different faces of non-cubic dice (some of you may even know why). I've already written a python script that randomly sets the objects position, rotation, initial linear velocity and initial angular velocity, then bakes the physics and jumps to a frame where the shape is likely in a settled position. The problem is that the rotation data at this frame seems to be the same as the frame right before the physics engine took over. It looks like the physics engine doesn't operate directly on object transformations. Is there a way to get this rotation information from python? Right now I can't even seem to find it in the UI.

$\endgroup$
  • $\begingroup$ I am not confident, but you might want to investigate parsing the values from a physics cache. blender.stackexchange.com/questions/15577/… has some techniques and particle system examples. $\endgroup$ – Mutant Bob Sep 16 '16 at 15:44
  • $\begingroup$ are you sure the physics have been baked properly? When I create a scene like that (simple cube in rotated orientation falling on a plane) and bake those physics, I do see changing rotation values in the transform panel. Are you using the 'Bake to Keyframes' button in the Physics Panel? $\endgroup$ – aliasguru Sep 16 '16 at 16:14
  • $\begingroup$ @aliasguru What version of python are you using? I'm using 2.77a. Also, what rotation mode are you using? I've tried this for Axis angle, XYZ Euler, and Quaternion, and have not been able to see results in the object transformation panel. $\endgroup$ – AIGuy110 Sep 17 '16 at 3:27
  • $\begingroup$ I've tested this with both 2.76 and the current release candidate of 2.78. The important part of my last comment was if you are using the 'bake to keyframes' function. Baking the physics via the Poperties Panel shows the behavior you see. Using the bake to keyframes function gives you access to the rotation and location values. The Python command is bpy.ops.rigidbody.bake_to_keyframes(). You'll need to set the rotation to quarternions before baking! $\endgroup$ – aliasguru Sep 17 '16 at 6:45
  • $\begingroup$ Ah, thanks @aliasguru! I was not able to find the "Bake to Keyframes" button, and none of the seemingly related buttons in the Scene > Rigid Body Cache panel seemed to do the trick, but "bpy.ops.rigidbody,bake_to_keyframes()" did exactly what I was looking for! $\endgroup$ – AIGuy110 Sep 20 '16 at 10:48
0
$\begingroup$

To be able to read out transformation values from rigid body physics simulations, those simulations need to be baked to keyframes. Baking the Physics from the Physics tab is not enough. Find the Bake to Keyframes button here:

bake to keyframes

From Python you can access the function via this operator:

bpy.ops.rigidbody.bake_to_keyframes()

You will be asked to enter a framerange when using the interactive operator:

framerange

Again, in Python you can use these keyword arguments to achieve the same thing:

bpy.ops.rigidbody.bake_to_keyframes(frame_start=1, frame_end=250, step=1)

Before baking, you should set the rotation mode to either Quarternions or Euler, depending on what you need to read out later. After baking, you can see the generated keyframes in the Timeline:

keyframes

Here are two comparison screenshots after the baking process, the first one is at frame 1, the other one at frame 250:

frame 1

frame 250

$\endgroup$
3
$\begingroup$

enter image description here

There's a fairly simple way to get the transformations of an object under a physics simulation without baking (which also applies to other situations such as parent-child relationships, constraints, etc).

To do this you simply need to access the object's world matrix property. Here are some examples you can test through the interactive python console:

# Accessing through the location property will give the initial value before the simulation starts
>>> C.object.location
Vector((0.0, 0.0, 14.47101879119873))

# The world matrix though gives the real, simulated location
>>> C.object.matrix_world.to_translation()
Vector((0.5996798276901245, 1.5040934085845947, 1.7373782396316528))

# Same goes for rotation
>>> [ degrees(a) for a in C.object.rotation_euler ]
[0.0, 0.0, 0.0]

>>> [ degrees(a) for a in C.object.matrix_world.to_euler() ]
[176.1907675277052, -11.192468775907107, -74.38630617504491]

# To access quaternion rotation values, simply use "to_quaternion"
>>> C.object.matrix_world.to_quaternion()
Quaternion((0.17901940643787384, -0.7067779302597046, 0.6757702231407166, -0.10840550810098648))

You can also add an app handler that calculates and prints the simulated location and rotation after every frame change:

import bpy
from math import degrees

def print_simulated_loc_rot( scene ):
    C = bpy.context
    o = C.object

    simulated_loc   = o.matrix_world.to_translation()
    simulated_rot   = o.matrix_world.to_euler()
    sim_rot_degrees = [ degrees(v) for v in simulated_rot ]

    print_friendly_loc = [ round( v, 2 ) for v in simulated_loc   ]
    print_friendly_rot = [ round( v, 2 ) for v in sim_rot_degrees ]

    print( "Location: ", print_friendly_loc )
    print( "Rotation: ", print_friendly_rot )

bpy.app.handlers.frame_change_post.append( print_simulated_loc_rot )
$\endgroup$

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.