Obtaining World-Oriented Quaternions

Although I have read some stuff about the armature system being majorly redone, for now and if the problem persists is a solution to obtaining World-Oriented Quaternions. I have tried to test this a lot, and I think that it works, but if you find some situation in which it does not work, please tell me. I will try to fix it, as I must also use this :).

Oh, and I think that there’s something about not creating armatures except in the XY view… not doing this seems to mess up the rotations.

Auxiliary Quaternion Code:

def QuatMultiply(Quat1, Quat2):
	Cv = Blender.Mathutils.Vector([Quat1.x, Quat1.y, Quat1.z])
	Cw = Quat1.w

	v = Blender.Mathutils.Vector([Quat2.x,Quat2.y,Quat2.z])
	w = Quat2.w

	Nv = Blender.Mathutils.CrossVecs(Cv, v) + w * Cv + Cw * v
	Nw = Cw * w - Blender.Mathutils.DotVecs(Cv, v)

	return Blender.Mathutils.Quaternion([Nw, Nv.x, Nv.y, Nv.z])

def QuatConverse(Quat):
	# Note that the converse is equal to the inverse if the quaternion is normalized
	Quat.conjugate()
	return Quat
  • QuatMultiply is used exclusively for concatenating rotations exclusively. I could find no blender tools for doing this. The conjugate one I made before I found Quat.conjugate(), but it allows for shortening of the code.

Now for the goodies:


def GetRootQuat(QuatBone):
	# Get parents' roots
	# Then calculate root rotation based on head, tail, and roll
	# append to root rotation

	RootQuat = Blender.Mathutils.Quaternion([1, 0, 0, 0])

	if QuatBone.hasParent() == 1:
		RootQuat = QuatMultiply(RootQuat, GetRootQuat(QuatBone.getParent()))
		RootQuat.normalize()

	Vect = (QuatBone.getTail() - QuatBone.getHead())
	Vect.normalize()
	Target = Blender.Mathutils.Vector([0, 1, 0])

	if Blender.Mathutils.DotVecs(Target, Vect) > 0.99999999:
		return RootQuat

	VectCross = Blender.Mathutils.CrossVecs(Target, Vect)
	ThisRootQuat = Blender.Mathutils.Quaternion([VectCross.x, VectCross.y, VectCross.z], Blender.Mathutils.AngleBetweenVecs(Target, Vect))
	RootQuat = QuatMultiply(ThisRootQuat, RootQuat)
	RootQuat = QuatMultiply(Blender.Mathutils.Quaternion([0, 1, 0], QuatBone.getRoll()), RootQuat)
	RootQuat.normalize()

	return RootQuat

def GetFixedQuat(QuatBone):
	# Rotation order:
	"""
	Remember: Multiplying quaternions concatenates them -- you cannot transorm a quaternion, only an object.  Therefore
	one must concatenate them in the right order to simulate this transormation.
	1. Rotate object by reverse root
	2. Rotate object by its own quaternion
	3. Rotate object back by root
	4. Apply parents' rotations (from bottom up).  This function is called recursively to do so.

	1-3: The root quaternion (GetRootQuat) is the rotation that if applied to the anim-quat would
	make it aligned to its parent.  However, because of the lack of quaternion-quaternion transformations
	(AFAIK), the solution must be done with concatenations only.

	4: Self explanatory... just apply all the other fixed rotations afterwords in order, down the parent->child chain.
	"""

	QuatRoot = QuatConverse(GetRootQuat(QuatBone))
	QuatRoot = QuatMultiply(QuatBone.getQuat(), QuatRoot)
	QuatRoot = QuatMultiply(GetRootQuat(QuatBone), QuatRoot)

	if QuatBone.hasParent() == 1:
		QuatRoot = QuatMultiply(GetFixedQuat(QuatBone.getParent()), QuatRoot)

	QuatRoot.normalize()
	return QuatRoot

As most of you probably already know, or don’t, Blender stores its rotations as relative to a root rotation. The root rotation calculates the rotation that if applied to the other rotations, would orient them for the object. However, as far as I can tell the only way to achieve this is by concatenating the rotations. Solution: Rotate the object backwards by the root (conjugate of root), apply rotations, and then rotate back.

Once again, please tell me if this is at all useful and working. Thanks!

I have a problem similar to the one you describe solving. There’s two things that keep me from solving it. I think what you describe is one of them.

The Background:
I have a set of data in a model file. This file contains:

  1. The Mesh to be deformed.
  2. The Bones of the Armature.
  3. The Vertex Groups of the Mesh, including parenting and weight of up to 4 parent bones (tho most have 1-2) for each vertex in the mesh.

The Mesh data is given in global coordinates. Each Vertex is located where it would be at the binding pose (more on this in a sec).

Each Bone of the Armature has an assigned parent, and a { scale, translate, quaternion } record. These records describe the Binding Pose. (Most human models this pose has the model with their arms straight out, legs apart)

Now, I have a problem. I can load this data into blender, and I get a lovely mesh. The armature, however is a problem.

If I set each bone to have a location of head (0, 0, 0) and tail (0, 1, 0) I can apply the translation, scaling, and quaternions using IPO Curves. Using these curves, if I look at the first frame of the animation, everything lines up nicely. However, in Edit Mode, all the bones are on top of one another (as I expect them to be). If I parent my imported Mesh to this armature, the vertices are deformed by the armature, when for this given pose, they are already where they should be.

Now, if I use lots of Math, I can apply the transformations to each bone, and place them where they should be in space. Then, when I look at the armature and the mesh, everything lines up nicely. But the Bone Roll Values are off, because Blender only lets me set the bone’s inital position using setHead(), setTail(), and setRoll() - and setRoll() doesn’t seem to want to work for whatever reason. But regardless, I still have another problem if I do things this way.

I have seperate files describing Animations for the Amature. These are also given as {scaling, rotation, quaternion} for each bone for each frame. Problem is, these {scaling, rotation, quaternion} records are not relative to the binding pose.

For Example, if the binding pose for Bone027 says:
{ translate by (0.0, 1.0, 0.5) , scale by (1.0, 1.0, 1.0), rotate about (1.0, 0.0, 0.0) by 30 degrees }
the first frame of the animation would tell me:
{ translate by (0.0, 1.0, 0.5) , scale by (1.0, 1.0, 1.0), rotate about (1.0, 0.0, 0.0) by 32 degrees }
It would be better for me if I could find some way to convert it to:
{ translate by (0.0, 0.0, 0.0) , scale by (1.0, 1.0, 1.0), rotate about (1.0, 0.0, 0.0) by 2 degrees }

The Best, though, would be to about to tell Blender “Hey, this frame of the animation is how the bones and the mesh line up”, and then still be able to express the animations as translate, scale, rotate from the parent to the new location and not have to calculate the Deltas between the binding pose and each frame. But if I knew how to calculate those deltas (especially for the rotations), I could live with that.

I have not had a chance to dig in-depth into the armature changes coming for 2.4, so I do not yet know if this problem has been solved.

Thanks in advance.

Rolls are fixed in the cvs version of blender