Page 1 of 1

Problem with cal3d derived

Posted: Fri Jul 16, 2004 5:32 pm
by MangoFusion
I've noticed a slight oddity in the cal3d exporter code. (which is used by many other exporters).

Specifically, this function :

Code: Select all

def blender_bone2matrix(head, tail, roll):
  # Convert bone rest state (defined by bone.head, bone.tail and bone.roll)
  # to a matrix (the more standard notation).
  # Taken from blenkernel/intern/armature.c in Blender source.
  # See also DNA_armature_types.h:47.
  target = [0.0, 1.0, 0.0]
  delta  = [tail[0] - head[0], tail[1] - head[1], tail[2] - head[2]]
  nor    = vector_normalize(delta)
  axis   = vector_crossproduct(target, nor)
  if vector_dotproduct(axis, axis) > 0.0000000000001:
    axis    = vector_normalize(axis)
    theta   = math.acos(vector_dotproduct(target, nor))
    bMatrix = matrix_rotate(axis, theta)
    if vector_crossproduct(target, nor) > 0.0: updown =  1.0
    else:                                      updown = -1.0
    # Quoted from Blender source : "I think this should work ..."
    bMatrix = [
      [updown, 0.0, 0.0, 0.0],
      [0.0, updown, 0.0, 0.0],
      [0.0, 0.0, 1.0, 0.0],
      [0.0, 0.0, 0.0, 1.0],
  rMatrix = matrix_rotate(nor, roll)
  return matrix_multiply(rMatrix, bMatrix)
Take a look at the "vector_crossproduct" line. This function returns a vector, but the if statement appears to expect a scalar float.

Really, it should be calling "vector_dotproduct". This is also what happens in the original code.

For comparison, here is the original function in the blender code :

Code: Select all

void make_boneMatrixvr (float outmatrix[][4],float delta[3], float roll)
/*	Calculates the rest matrix of a bone based
	On its vector and a roll around that vector */
	float	nor[3],axis[3],target[3]={0,1,0};
	float	theta;
	float	rMatrix[3][3], bMatrix[3][3], fMatrix[3][3];

	VECCOPY (nor,delta);
	Normalise (nor);

	/*	Find Axis & Amount for bone matrix*/
	Crossf (axis,target,nor);

	if (Inpf(axis,axis) > 0.0000000000001) {
		/* if nor is *not* a multiple of target ... */
		Normalise (axis);
		theta=(float) acos (Inpf (target,nor));

		/*	Make Bone matrix*/
		VecRotToMat3(axis, theta, bMatrix);
	else {
		/* if nor is a multiple of target ... */
		float updown;

		/* point same direction, or opposite? */
		updown = ( Inpf (target,nor) > 0 ) ? 1.0 : -1.0;

		/* I think this should work ... */
		bMatrix[0][0]=updown; bMatrix[0][1]=0.0;    bMatrix[0][2]=0.0;
		bMatrix[1][0]=0.0;    bMatrix[1][1]=updown; bMatrix[1][2]=0.0;
		bMatrix[2][0]=0.0;    bMatrix[2][1]=0.0;    bMatrix[2][2]=1.0;

	/*	Make Roll matrix*/
	VecRotToMat3(nor, roll, rMatrix);
	/*	Combine and output result*/
	Mat3MulMat3 (fMatrix,rMatrix,bMatrix);
	Mat4CpyMat3 (outmatrix,fMatrix);

Posted: Sat Jul 17, 2004 2:18 pm
by ascotan
Yes it prob should be dot product. Inpf() is the dot product function in arthib.c. Inpf is danish for dot :roll: (Gotta love easy to figure out function names).

Posted: Sat Jul 17, 2004 11:52 pm
by der_ton
Wow, thanks, I use that code for my exporter too and never saw that. Hmm, why does it work anyway? I've never seen that that affects the output. In what cases does it make a difference?

Posted: Sun Jul 18, 2004 11:16 am
by MangoFusion
I'm not entirely certain; But of course, it effects if the "updown" value if negative or not.
The name, and the comment ("point same direction, or opposite?") implies it has something to do with the bone matrix pointing "up" or "down", so i would guess that it inverts the rotation/translation?

The typo'd statement appears to return True all the time, so updown would always be 1.0