Thanks for the input. I didn’t actually write this function myself, I’m just trying to debug it so I don’t totally understand exactly what it’s supposed to do (especially since my linear algebra is pretty rusty).

Anyway, I think a.cross(perp) is only equal to -b (in direction, not necessarily magnitude) when a and b are separated by 90 degrees (pi/2). Or maybe my math is wrong?

I believe that one of the functions (cross or dot or maybe both) returns some nonsensical value when fed two antiparallel vectors or fed a zero vector (since if b = -a, a.cross(b) = 0 right?).

My issue may also have something to do with double/floating point precision.

My math is rusty too. So I tested with a few vectors. You are right, I used the wrong vectors to test with ;).

It is true, when a and b are not orthogonal to each other a.cross(a.cross(b)) is orthogonal to a and a.cross(b), which is not b or -b.

Something I just noticed. The matrices from post#1 do not look like rotation matrices. The first one mirrors the object at two axis (x and y). The second one does nothing (what you get when the vectors are parallel)

Can you tell what the input vectors are?

Something more:

These formulas are used to determine if a is left of b as angle() just returns the smallest angle (not the direction).

This is a valid approach, but mathutils.Rotation() receives the rotation axis (perp). This axis already provides a direction. It looks like the previous calculation cancels this direction, but I’m not really sure about that.

I somehow managed to brute-force solve this lol. I still don’t really know what the problem was, but I just force-corrected the matrix when a and b were antiparallel.

def VecToVecMatrix(a,b):
angle = a.angle(b)
perp = a.cross(b)
if a.cross(perp).dot(b) <= 0:
angle = -angle
rotmat = mathutils.Matrix.Rotation(angle, 3, perp)
if a.dot(b) < 0:
if rotmat[0][0] > 0:
rotmat[0][0] *= -1
if rotmat[1][1] > 0:
rotmat[1][1] *= -1
return rotmat

The cross product of parallel or anti-parallel 3D vectors is actually (0,0,0). This is useless for most 3D math involving cross products. It would not surprise me at all if Blender is using some weird, poorly tested NAN structure to deal with this special case.

You can accept the risk of artifacts (like if you’re writing shaders, where that will never in reality happen) or you can add code to deal with that special case.