Make quaternion from 3 vectors

How do I make a quaternion from 3 input vectors? I want to set an object to the orientation provide by 3 vectors.

I’m going to suggest you look up stuff in the python docs that are available from a link in blender’s splash screen before asking a bunch of simple questions.

Not that I (or other people I’d imagine) mind helping but the docs and google provide a much faster turnaround time.

To answer your question… dunno off-hand, your question isn’t too clear. Do you mean 3 vectors that provide rot/loc/scale or three transformations that need to be applied in a certain order to get the desired result?

Well, I needed to ask a bunch of simple questions to get rid of my new user (pre 10 post) moderator-pre-approval limitation which was starting to get very annoying. Sorry to annoy you.

Simplest way is to set x, y, and z to the three vectors, and w to 1.0

Wow, I didn’t think that would work. Thanks!

The ‘w’ variable is a sort-of “how much of an affect x, y, and z have on the object” kind of thing (layman’s understanding; take with a HUGE grain of salt). But, with that said, whenever you create a new object, ‘w’ is always set to 1.0 so it should be a safe estimate for converting from Euler.

Ok, so are you sure the x,y, and z values of a quaternion can be set to normalized vectors (as long as the 3 vectors make up a LHS or RHS valid coordinate system, 90 degrees apart etc.) like with a normal matrix? I thought quaternions where way more complex then that.

This function returns the quaternions from a 3x3 rotation matrix t, formed with x, y, z orthonormal vectors (i.e. x, y, z are the columns of the matrix). It requires numpy.

from numpy import matrix, linalg, sqrt, trace
def mat2quat(t):
    #   Adapted from "robotic toolbox for python"
    #   Convert homogeneous transform to a unit-quaternion
    #   Return a unit quaternion corresponding to the rotational part of the
    #   homogeneous transform t.

    qs = sqrt(trace(t)+1)/2.0
    kx = t[2,1] - t[1,2]    # Oz - Ay
    ky = t[0,2] - t[2,0]    # Ax - Nz
    kz = t[1,0] - t[0,1]    # Ny - Ox
    if (t[0,0] >= t[1,1]) and (t[0,0] >= t[2,2]):
        kx1 = t[0,0] - t[1,1] - t[2,2] + 1      # Nx - Oy - Az + 1
        ky1 = t[1,0] + t[0,1]           # Ny + Ox
        kz1 = t[2,0] + t[0,2]           # Nz + Ax
        add = (kx >= 0)
    elif (t[1,1] >= t[2,2]):
        kx1 = t[1,0] + t[0,1]           # Ny + Ox
        ky1 = t[1,1] - t[0,0] - t[2,2] + 1  # Oy - Nx - Az + 1
        kz1 = t[2,1] + t[1,2]           # Oz + Ay
        add = (ky >= 0)
    else:
        kx1 = t[2,0] + t[0,2]           # Nz + Ax
        ky1 = t[2,1] + t[1,2]           # Oz + Ay
        kz1 = t[2,2] - t[0,0] - t[1,1] + 1  # Az - Nx - Oy + 1
        add = (kz >= 0)
    if add:
        kx = kx + kx1
        ky = ky + ky1
        kz = kz + kz1
    else:
        kx = kx - kx1
        ky = ky - ky1
        kz = kz - kz1
    kv = matrix([kx, ky, kz])
    nm = linalg.norm( kv )
    if nm == 0:
        e0 = 1.0
        q = matrix([0.0, 0.0, 0.0])
    else:
        e0 = qs
        q = (sqrt(1 - qs**2) / nm) * kv
    return e0, q[0,0], q[0,1], q[0,2]

Maybe they are, maybe they aren’t. But if you look at it logically, with a fourth coordinate to describe a point in three-dimensional space, it can only take on so many meanings. It’s not time because that’s handled on the Timeline. The only other meanings that come to mind are strength or bias. Either way, the first three variables won’t change their meanings or you’d no longer be describing the same point in space.

There is a much longer explanation on Wikipedia, but you need to understand some pretty heavy math to follow it. I admit I have no idea what they’re talking about on there.

My understanding is derived mainly from this video. I hope it’s of at least some help in your endeavors.

Ok, thanks for the code. Will have a look at the video as well.

Hi elecman,

If you have the basis vectors and want to construct the quaternion to transform to that orientation, you can use mathutils to do the conversions. Here is an example:

from mathutils import Matrix, Vector

# Basis vectors
v1 = Vector((1, 0, 0))
v2 = Vector((0, 1, 0))
v3 = Vector((0, 0, 1))

# Initialise matrix
mat = Matrix.Identity(3)

# Set matrix values
mat.col[0] = v1
mat.col[1] = v2
mat.col[2] = v3

# Make the quaternion from the matrix
quat = mat.to_quaternion()

print(quat)

Obviously this is a simple example, the basis vectors could be whatever you like. Hope this helps.

Cheers,
Truman

Cool! Thanks.

I figured that it is easier to directly set the matrix of my object to the vectors instead of first converting it to a quaternion. But I can’t figure out the correct formatting of the Blender 4x4 matrix. I have a position vector and 3 rotation vectors (v1, v2, v3, in the example above). So I need to combine the position vector and rotational vectors into a single 4x4 matrix.


        mat = Matrix.Identity(3)

        # Set matrix values
        mat.col[0] = v1
        mat.col[1] = v2
        mat.col[2] = v3
        
        #Set the rotation of the empty, but this won't work
        empty.matrix_world = mat.to_4x4()

This doesn’t work either:


        mat = Matrix.Identity(4)
        mat.col[0] = v1
        mat.col[1] = v2
        mat.col[2] = v3
        mat.col[3] = position_vector
        empty.matrix_world = mat

It gives an error: value assignment: sequence size is 3, expected 4

Any ideas?

Hi there,

That error is because the rows of a 4 x 4 matrix have 4 elements. Here is some code that worked fine for me with an empty selected.

import bpy
from mathutils import Vector, Matrix

ob = bpy.context.active_object

v1 = Vector((1, 0, 0))
v2 = Vector((0, 0, 1))
v3 = Vector((0, -1, 0))
v4 = Vector((0, 0, 1))

mat = Matrix.Identity(3)

# Set matrix values
mat.col[0] = v1
mat.col[1] = v2
mat.col[2] = v3

mat.resize_4x4()
mat.translation = v4

#Set the rotation of the empty, but this won't work
ob.matrix_world = mat

Hope that helps.

Cheers,
Truman

Thanks! I got it to work. I changed it a bit but it works the same way.


        mat = Matrix.Identity(4)
        mat.col[0] = v1.to_4d()
        mat.col[1] = v2.to_4d()
        mat.col[2] = v3.to_4d()
        mat.col[3] = position.to_4d()