EDIT: The solution I ended up with is:
public static (Vector3, Quaternion, Vector3) GetChildPosLeg(
Transform bottomReference,
Transform topReference,
Transform topTarget,
Transform bottomTarget,
Vector3 parentScale,
Vector3 itemScaleRatio
)
{
// World targets
Vector3 targetAWorldPos = (Vector3.Scale(topTarget.position, parentScale));
Vector3 targetBWorldPos = (Vector3.Scale(bottomTarget.position, parentScale));
// Scale
Vector3 scaledBottom = Vector3.Scale(bottomReference.position, itemScaleRatio);
Vector3 scaledTop = Vector3.Scale(topReference.position, itemScaleRatio);
float incomingDistance = Vector3.Distance(scaledBottom, scaledTop);
float targetDistance = Vector3.Distance(targetAWorldPos, targetBWorldPos);
float scaleRatio = targetDistance / incomingDistance;
Vector3 finalScale = itemScaleRatio * scaleRatio;
// Rotation
Vector3 refDir = scaledBottom - scaledTop;
Vector3 targetDir = topTarget.position - bottomTarget.position;
// Local 'up' vector of the incoming object
Vector3 refUp = refDir.normalized;
// Local 'forward' vector of the incoming object (define this based on prefab orientation)
Vector3 refForward = Vector3.Cross(refUp, bottomReference.forward).normalized; // assuming 'right' is orthogonal
Quaternion refRotation = Quaternion.LookRotation(refForward, refUp);
//Build a target rotation from the target node
Vector3 targetUp = targetDir.normalized;
Vector3 targetForward = topTarget.forward; // assuming the prefab is aligned the same way
Quaternion targetRotation = Quaternion.LookRotation(targetForward, targetUp);
Quaternion finalRotation = targetRotation * Quaternion.Inverse(refRotation);
// Position
// Scale it
Vector3 scaledOffset = Vector3.Scale(scaledBottom, finalScale);
// Rotate it
Vector3 rotatedOffset = finalRotation * scaledOffset;
// Subtract that offset from the target position
Vector3 finalPosition = targetAWorldPos - rotatedOffset;
return (finalPosition, finalRotation, finalScale);
}
