I have a setup where my spacecraft each have one docking port at an arbitrary location on their hull. The docking port transform is a child of its parent ship, and its position is the “dock point”.
I’m trying to create a 3 step process whereby:
- one ship moves near to the target’s docking port,
- rotates such that its docking port lines up with the target’s, and then
- moves towards it
I’m almost there – the rotations are easy – but I’m stuck on the rotation! I’m fine with lerping so let’s pretend I’m doing snap rotations and translations.
Assume that a docking port’s z-axis points in the direction ships should dock from.
I’ve successfully positioned Ship A’s docking port a few metres away from Ship B’s. Now I need to rotate my ship around its docking port such that the docking port’s Z axis points at ship B’s docking port. Ideally the docking ports’ X axes should also be aligned too. That’s what I’m stuck on.
If the docking port was aligned with the ship transform’s center, I could do something like:
transform.rotation = Quaternion.LookRotation(targetDockingPort.position - transform.position) * Quaternion.Inverse(this.dock.localRotation);
But… well, it’s obviously not that easy.
Can anybody help?
How’s this? This aligns the ship my “dock” object in front of it, (0,0,1 being foward, a fancier one could just get the position of a child docking point) and lerps to the desired rotation. Specifying a new Up in the LookRotation means the roll (x axis) also aligns nicely that way too

[25914-spaceshipdocking697131.zip|25914]
Transform GetDockTransform()
{
GameObject Dock = GameObject.Find ("dock");
if (!Dock)
return null;
return Dock.transform;
}
void Update () {
Transform Dock = GetDockTransform ();
if (!Dock)
return;
Vector3 DockLocalDirection = new Vector3 (0, 0, 1);
Vector3 DockForward = Dock.localToWorldMatrix.MultiplyVector ( DockLocalDirection );
Vector3 DockUp = Dock.localToWorldMatrix.MultiplyVector (Vector3.up);
DockForward.Normalize();
// face each other
DockForward *= -1;
// fly to where we want to be in world space
Vector3 TargetPos = DockForward * 2;
transform.position = Vector3.Lerp (transform.position, TargetPos, 0.1f);
// generate rotation we want to be (foward & up) and lerp to it
Quaternion start = transform.rotation;
Quaternion dest = Quaternion.LookRotation (DockForward,DockUp);
transform.rotation = Quaternion.Slerp (start, dest, 0.1f );
}
Phew, I figured it out for the general case. This assumes that you want your docking port’s positive Z axis to be 180 degrees rotated from the target docking port, and with their X axes aligned.
The principle is you’re trying to figure out how much you’d need to rotate your docking port to make it match the target docking port’s rotation. But remember the target docking port is rotated 180 degrees around its X axis, so we need to correct for that first. In theory you could make docking “targets” that correspond to how you want the docking ship’s port to be aligned, but this saves doubling up on transforms.
This makes a lot of sense if you know the following:
rotationalDifference = destinationRotation * INVERSE(originRotation)
and
destinationRotation = rotationalDifference * originRotation
Because quaternions are non-commutative, you MUST keep the multiplications in this order.
Dividing quaternions finds the difference between them (and multiplying them is basically adding them together). You can’t actually divide them in Unity, so you have to multiply one quaternion by the inverse of the other. Kinda like how 14/2 = 7 and 14*(1/2) = 7.
TL;DR here’s the code:
//Calculate your docking port's rotation if it was flipped
Quaternion flippedDockRotation = yourDock.rotation * Quaternion.Euler(180,0,0);
//Find out how much you'd have to rotate your dock to arrive at the target's rotation.
//Note: the multiplication MUST be this way around.
Quaternion rotationDifference = targetDock.rotation * Quaternion.Inverse(flippedDockRotation);
//Move to the target dock. The extra minus in there is to account for the offset of your docking port from your centre
transform.position = Vector3.Lerp (transform.position, targetDock.position - (yourDock.position-transform.position), Time.deltaTime);
//Rotate towards the rotation target: the rotational difference * your current rotation. This multiplication breaks if you reverse it
transform.rotation = Quaternion.Slerp(transform.rotation, rotationDifference*transform.rotation, Time.deltaTime);