Object snapping : Rotation matrix issue

Started by
3 comments, last by JoeJ 1 year, 8 months ago

I've been stuck on a problem for a long time and wondered if anyone could help tell me where I'm going wrong.

I have multiple objects in world space, each object has multiple snap points.

In the image the yellow object is fixed and already inserted, the grey object is "inserting" and movable by mouse until clicked, which then inserts. The objects snap point is under the cursor, and you can cycle through the snap points by pressing Ctrl, similar to CAD software.

The snap points are defined by their own coordinate frame.

I'm using the following method to find the rotation matrix between any 2 snap points:
https://web.archive.org/web/20200223130502/http://www.meshola.com:80/Articles/converting-between-coordinate-systems

When the yellow object has no rotation (Euler 0,0,0), it works perfectly for all snap points (as shown in the images above).

However when the yellow object has an arbitrary rotation, only 1 out of 4 snap points work on the grey object (Images below).

The snap point that works is when the coordinate frame of the Grey obj snap point is inline with the world frame, with negative direction.

Unit vectors of snap point coordinate frame (grey obj):
X = -1, 0, 0
Y = 0, -1, 0
Z = 0, 0, -1

Working snap point
Same snap point on another side

The only time it works is when the Grey object active snap point has the coordinate frame defined above.

I'm hoping someone can point out what I'm doing wrong without having to read my code, but I can share code if needed, it's in VB though

Advertisement

jbexx said:
Unit vectors of snap point coordinate frame (grey obj): X = -1, 0, 0 Y = 0, -1, 0 Z = 0, 0, -1

Seeing all numbers are negative, and also seeing some of your wrong results look somewhat mirrored, i assume your problem is that you mix right and left handed conventions, which does not work.

To check this, calculate determinants of all your object and snapping point matrices. You're fine if they are either all positive or all negative. If some are negative but some others are positive, we have found the reason of the problem, which then should be easy to fix.

In case you don't know, the determinant of a 3x3 matrix relates to the volume of the space it represents (think of forming a cube aligned to the basis vectors).
If we negate one basis vector to mirror the space, the volume becomes negative. So usually we are not allowed to do this.
If we negate two basis vectors, volume remains positive, so we are fine (Because the transformation we just did represents a rotation, not a mirror)
If we negate all three basis vectors, volume becomes negative again.

Your quoted example seems a result of that latter case, so i guess you do not respect those rules.

To calculate the determinant of a 3x3 matrix you can do:

float determinant = dot ( Z, cross(X, Y) );

Which for the example should give -1, so negative volume, indicating a ‘mirrored’ or 'flipped' space causing problems when combined with a space which is not mirrored.

The determinant calculation makes it easy to verify this with matrices of arbitrary rotations.

@JoeJ
Thanks for the suggestion I hadn't thought of that, I've been playing with it for a while and still no luck.

When inverting the snap points the same problem is there, but now only works when the the unit vectors are (1,0,0 : 0,1,0 : 0,0,1)
For the 2nd snap point I only invert X and Y (to achieve the 180 degree snap)
Only the X and Z basis vectors are specified, the Y vector is calculated using cross product, so I think all snaps follow the same convention. (If cross always gives the same convention? I'll investigate that)

The matrix between the 2 snap points is written directly to the object, and isn't applied to any existing matrices.
The active snap point is treated as if it isn't transformed (as if the grey object has no rotation)

I'll keep playing with it, I feel like the issue is hidden deeper

jbexx said:
Only the X and Z basis vectors are specified, the Y vector is calculated using cross product, so I think all snaps follow the same convention.

You're right.
Too bad. Then the reason is something else.

jbexx said:
The matrix between the 2 snap points is written directly to the object, and isn't applied to any existing matrices. The active snap point is treated as if it isn't transformed (as if the grey object has no rotation)

I do not precisely understand. But the snapping you want should use the same data and math than what i use right now for physics constraints.

For example, i have upper and lower arm bodies (two of your boxes), and there is a joint which connects them at the elbow (your snapping points), and there is a motor driven rotation between the bodies (your desired matching of box orientations).

So the code that i use might help for reference. Problem is, it's old and ugly, and currently i'm refactoring / porting it to a math lib with different conventions. Not 100% sure if this code even works:

sQuat PredictBodyOrn0 (sQuat targetOrn, sQuat body1orn)
		{
			sQuat q1 = body1orn; q1 *= localRot1;

			sQuat qt0 = q1 * targetOrn;
			return qt0 * localRot0.Inversed();
		}

		sQuat PredictBodyOrn1 (sQuat targetOrn, sQuat body0orn)
		{
			sQuat q0 = body0orn; q0 *= localRot0;
		
			sQuat qt1 = q0 * targetOrn.Inversed();
			return qt1 * localRot1.Inversed();
		}

I use quaternions, but the same operations work equally with 3x3 matrices.

body0/1Orn would be the orientation matrix of your two boxes.

localRot0/1 would be the rotation from the box orientation to the current snapping-orientation for this box.

targetOrn is the desired rotation offset between the two snapping orientation which should meet. In your case that's just zero, so you could replace it with identity matrix and later optimize it away.

The functions then return the orientation of the current box the user is dragging. So that's what you want, and after that you only need to translate to bring the snapping points together.

Basically you should have some similar math. Maybe a comparison helps. But it depends on the usual conventions. For example, currently i need to swap multiplication order to port it to the new math library.


This topic is closed to new replies.

Advertisement