- Home /
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[i] = rotationDiff[i] % 90f;
if (rotationDiff[i] > 45f) rotationDiff[i] -= 90f;
else if (rotationDiff[i] < -45f) rotationDiff[i] += 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: https://youtu.be/GfzIbWuV54o
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;
During runtime. This is somewhat of a building block game but blocks can be rotated. I have this joint system that snaps the nearest face to the other block and the problem would be solved if I just copied the rotation of the other object to the object I am trying to place but I do not want my object to rotate more than 90 degrees in any direction. Let's say you are snapping a (rectangular) wing to a (rectangular) fuselage, you want your wing to snap with the face that is nearest to the fuselage.
Answer by JVene · Aug 02, 2018 at 08:49 PM
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.
Put some more info above. Beco$$anonymous$$g child is not really possible due to the system of triggers I have and the fact that the child still needs rotate locally to keep the user set rotation as much as possible.