Hello,
the problem is probably simple but I have spent way too much time on it so far:
I have cube 1 that is slowly rotating in place along x, y, z axis. I have cube 2 that I can snap to cube 1. Snapping the position works great but the thing I cannot make work is snapping rotation. Essentially I would need to rotate cube 2 the least amount possible so that one of it’s faces is flush with cube 1.
Any help would be great.
EDIT:
Some more info
Here is the code I have at the moment (very naive tho):
Vector3 rotationDiff = otherAnchor.transform.localRotation.eulerAngles - transform.localRotation.eulerAngles;
for(int i = 0; i < 3; i++)
{
rotationDiff _= rotationDiff *% 90f;*_
if (rotationDiff > 45f) rotationDiff -= 90f;
else if (rotationDiff < -45f) rotationDiff += 90f;
}
transform.localRotation = Quaternion.Euler(rotationDiff) * transform.localRotation;
And the video of it in action. Notice that the small subcube is always in roughly the same position as it tries to keep the user set rotation as much as possible. Also, everything works perfectly fine as long as rotation is only along one axis.
*Video: Rotation Problem - YouTube
EDIT 2:
This is the solution I went for in the end. Works great but needs some optimization:
// Position this objects initially so that, once rotated, this object is still in the correct position
transform.position = otherAnchor.GlobalPosition + (transform.position - GlobalPosition);_
// Make this object face the other object along the face normals
if (Mathf.Abs(Vector3.Dot(otherAnchor.GlobalFaceNormal(), GlobalFaceNormal())) < 1f)
{
rotationAxis = Vector3.Cross(-otherAnchor.GlobalFaceNormal(), GlobalFaceNormal()).normalized;
float angle = Vector3.SignedAngle(-otherAnchor.GlobalFaceNormal(), GlobalFaceNormal(), rotationAxis);
transform.localRotation = Quaternion.AngleAxis(-angle, rotationAxis) * transform.localRotation;
}
// Find one alignment axis from this object that is not the same as the rotation axis
Vector3 thisAlignmentAxis = Vector3.zero;
float normalForwardDot = Mathf.Abs(Vector3.Dot(GlobalFaceNormal(), transform.forward));
float normalRightDot = Mathf.Abs(Vector3.Dot(GlobalFaceNormal(), transform.right));
thisAlignmentAxis = normalForwardDot < normalRightDot ? transform.forward : transform.right;
// Calculate all possible dots between this alignment axis and all directions of the other object
float xDot = Vector3.Dot(thisAlignmentAxis, otherAnchor.transform.right);
float yDot = Vector3.Dot(thisAlignmentAxis, otherAnchor.transform.up);
float zDot = Vector3.Dot(thisAlignmentAxis, otherAnchor.transform.forward);
float dot45 = 0.7f;
// Find nearest axis to this alignment axis on the other object so that least rotation is needed to align them
Vector3 otherAlignmentAxis = Vector3.zero;
if (Mathf.Abs(xDot) > dot45 && Mathf.Abs(xDot) < 1f) otherAlignmentAxis = xDot > 0 ? otherAnchor.transform.right : -otherAnchor.transform.right;
else if (Mathf.Abs(zDot) > dot45 && Mathf.Abs(zDot) < 1f) otherAlignmentAxis = zDot > 0 ? otherAnchor.transform.forward : -otherAnchor.transform.forward;
else if (Mathf.Abs(yDot) > dot45 && Mathf.Abs(yDot) < 1f) otherAlignmentAxis = yDot > 0 ? otherAnchor.transform.up : -otherAnchor.transform.up;
else Debug.Log(“Could not find alignment axis.”);
// Apply rotation around rotation axis so that two alignment axis are pointing at the same direction
transform.localRotation = Quaternion.FromToRotation(thisAlignmentAxis, otherAlignmentAxis) * transform.localRotation;
// Fix position once more to make sure that both anchors are at the exactly same position
transform.position += otherAnchor.GlobalPosition - GlobalPosition;