I have my custom axis XYZ vectors (Yellow color in the screenshot below). They are normalized. I need to rotate an object according to these vectors. Is it possible to do this with the python API?
If you want to change the basis you need to set up a transformation matrix. For standard Cartesian coordinates the x (1, 0, 0) , y (0, 1, 0) and z (0, 0, 1) axis vectors make up the columns of the 3 x 3 Indentity matrix.
To make up your basis matrix use the three orthogonal vectors that make up your axis vectors to build a transform matrix.
m = [vx, vy, vz]
which for all extents and purposes is a 3 x 3 rotation matrix.
To rotate your monkey simply multiply its matrix_world by this matrix.
To have translation in your change of coordinates would need a 4 x 4 matrix.
Is all this starting to sound familiar?, it should do as it's pretty much making the cube in image below a child of the empty, and using the empties local space as our new coordinate space.
Using the empty as an example to show the 3 orthogonal vectors that make up its local space.
>>> for v in C.object.matrix_world.to_3x3():
... print(v)
...
<Vector (0.8496, -0.4064, -0.3362)>
<Vector (0.1958, 0.8349, -0.5144)>
<Vector (0.4897, 0.3712, 0.7889)>
# orthogonal ?
>>> degrees(Vector((0.8496, -0.4064, -0.3362)).angle(Vector((0.1958, 0.8349, -0.5144))))
90.00059673093595 # close enough
You can use the rotation_difference
method of the mathutils.Vector
object to calculate the 3 axis angle difference between two vectors.
This function is used as follows:
# Calculate the angle between two vectors. Returns a Quaternion object.
vector1.rotation_difference( vector2 )
Here's some sample code that uses this function:
import bpy
from mathutils import Vector
from math import degrees
v0 = Vector(( 0,0,0 ))
v1 = Vector((-0.792312741279602, 0.6056182980537415, -0.0739390179514885))
rot = v1.rotation_difference( v0 ).to_euler()
print( [ degrees( a ) for a in rot ] )
Output is (angle rotation in each axis):
[ -77.31130736634618, -146.788879528308, -40.89379056097038 ]
Now if you want to rotate an object according to this rotation difference, all you need to do is to assign the value of rot
to the object's rotation_euler
property:
obj.rotation_euler = rot
Note: the image can be a bit misleading since the cube and corresponding empty's location is not the value of V1 at all. V1 represents the rotation / direction values only, with respect to the zero vector (V0).
rotation_difference
between them via the Vector function of the same name: blender.org/api/blender_python_api_current/… $\endgroup$ – TLousky Dec 20 '16 at 10:56