Snap and align two cubes

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;

This sounds like you actually want the “snapped” cube to become a child, so it assumes the rotation of the parent.


More to the point, however, is that you probably want an empty GameObject that owns the first cube, and this empty game object is the one that should rotate as you’ve described. That way, any an all objects made children of the empty, parent gameobject will rotate and move with the parent in the way it appears you want.


You can experiment in the editor before coding by creating this arrangement in the scene to see how this parental arrangement works.