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.
-
$\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 BobCommented Sep 16, 2016 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$– aliasguruCommented Sep 16, 2016 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$– AIGuy110Commented Sep 17, 2016 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$– aliasguruCommented Sep 17, 2016 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$– AIGuy110Commented Sep 20, 2016 at 10:48
2 Answers
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:
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:
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:
Here are two comparison screenshots after the baking process, the first one is at frame 1, the other one at frame 250:
-
$\begingroup$ This is simply untrue and misleading, I think.
.matrix_local
and.matrix_world
seem to include rigid body simulation transformations. Do.matrix_local.to_quaternion()
for quaternions. Some latency may apply. (I'm still investigating the latency. I think it's just a caching issue.) $\endgroup$ Commented Mar 20, 2021 at 21:15
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 )