##
TL;DR:

- Two unit vectors: (a + b) / 2, and then normalize it.
- Two non-unit vectors with same magnitude: (a + b) / 2, then normalize it, and then multiply by a’s magnitude (b’s magnitude will also work, as they are the same).
- Two vectors with different magnitude: Vector3.Slerp(a, b, 0.5).

##
Define half-way vector:

First of all, we have to define what exactly we mean by a vector that is half-way between two vectors. Is it:

- A vector that literally points to a position between the two original vectors, or
- A vector that points in the direction half-way from the first to the second?

The second option is most useful when if comes to interpreting vectors as directions, rather than points, which often happens to be the case with camera programming.

Also, we have to consider whether the vectors involved are unit (i.e. their magnitude == 1), and if they have the same magnitude or not.

##
For normalized vectors:

*(This will work exactly the same in 3D.)*

Firstly, we create the two vectors we want to find the half-way vector of. In the image, I call them *a* and *b*.

Then we add *a* and *b* to get a new vector called *c*. This is a vector in the direction half-way between *a* and *b*, but its magnitude is sqrt(2).

If we want a vector that is linearly half-way between *a* and *b*, then all we have to do is to divide *c* by 2. This returns a vector half-way between *a* and *b*, but its magnitude is 0.5.

However, if we want a vector that is *rotated* half-way between *a* and *b*,
then we can normalize *c*. This normalized vector is half-way between *a* and *b*, and it has the same magnitude.

Note that you could choose to normalize either [1, 1] or [0.5, 0.5], and you would still get the same vector, but normalizing [1, 1] in this case would save some computation.

```
// a and b are unit vectors (magnitude == 1).
Vector3 a = new Vector3(1, 0, 0);
Vector3 b = new Vector3(0, 1, 0);
// Position half-way beteen a and b:
Vector3 cL = (a + b) / 2.0f;
// Rotated half-way between a and b:
Vector3 cR = (a + b).normalized;
```

This yields cL = [0.5, 0.5, 0], and cR = [0.71, 0.71, 0].

##
For non-unit vectors with same magnitude:

If your two vectors are not unit (i.e. they do not have magnitude == 1), but still have the same magitude, then you could do the same as above, but after having normalized c you then scale it up by either a’s or b’s magnitude.

```
// Neither a and b are unit, but
// they have the same magnitude.
Vector3 a = new Vector3(3, 0, 0);
Vector3 b = new Vector3(0, 3, 0);
// Position half-way between a and b:
// (This is the same as above)
Vector3 cL = (a + b) / 2.0f;
// Rotated half-way between a and b:
// (Normalize it first, then scale it by
// a's magnitude (either a or b would work here).
Vector3 cR = (a + b).normalized * a.magnitude;
```

This yields cL = [1.5, 1.5, 0], and cR = [2.12, 2.12, 0].

##
For vectors with different magnitude:

Slerp. Slerp stands for "spherical linear interpolation", and it interpolates along a spherical shape, rather than just a line, which is what Lerp does.

```
// a and b do not have the same magnitude.
Vector3 a = new Vector3(1, 0, 0);
Vector3 b = new Vector3(0, 3, 0);
// Position half-way between a and b:
// (This is the same as above)
Vector3 cL = (a + b) / 2.0f;
// Rotated half-way between a and b:
Vector3 cR = Vector3.Slerp(a, b, 0.5f);
```

This yields cL = [0.5, 1.5, 0], and cR = [1.41, 1.41, 0]. Note that the x-component of cR actually extends the original x-value. This is because Vector3.Slerp creates an artificial sphere somewhere so that both vectors touch the crust of the sphere. Because they do not share the same magnitude, the sphere’s center has to be moved away, and this in turn creates this extra curvature.

##
Also related:

I’ve created a quick C# script that we can use to play around with Lerp, Slerp, and Nlerp. Put this script onto any GameObject, and create a UI Slider to use as input.

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class InterpolationTest : MonoBehaviour
{
// Slap this script onto any GameObject, and set a Slider to see
// the effects of Lerp, Slerp, and Nlerp on vectors.
// Try to experiment with non-unit vectors (i.e. vectors whose
// magnitude is not == 1). Try to spot the difference and similarities
// in the angles between the Slerp and Nlerp functions.
// Set the posA, posB, and posC to something like [0, 0, 0], [3, 0, 0], and [6, 0, 0]
[Header("Parameters")]
public Slider slider;
public float t;
public Vector3 a;
public Vector3 b;
[Header("Positioning")]
public Vector3 posA;
public Vector3 posB;
public Vector3 posC;
[Header("Colors")]
public Color colA;
public Color colB;
public Color colC;
[Header("Results")]
[SerializeField]
private Vector3 resultLerp;
[SerializeField]
private float angleLerp;
[SerializeField]
private Vector3 resultSlerp;
[SerializeField]
private float angleSlerp;
[SerializeField]
private Vector3 resultNlerp;
[SerializeField]
private float angleNlerp;
private void Update ()
{
// Updating slider
t = slider.value;
float max = a.magnitude > b.magnitude ? a.magnitude : b.magnitude;
// Lerp
Debug.DrawLine(posA, a + posA, colA);
Debug.DrawLine(posA, b + posA, colB);
resultLerp = Vector3.Lerp(a, b, t);
Debug.DrawLine(posA, resultLerp + posA, colC);
angleLerp = Vector3.Angle(a, resultLerp);
// Slerp
Debug.DrawLine(posB, a + posB, colA);
Debug.DrawLine(posB, b + posB, colB);
resultSlerp = Vector3.Slerp(a, b, t);
Debug.DrawLine(posB, resultSlerp + posB, colC);
angleSlerp = Vector3.Angle(a, resultSlerp);
// Nlerp
Debug.DrawLine(posC, a + posC, colA);
Debug.DrawLine(posC, b + posC, colB);
resultNlerp = resultLerp.normalized;
Debug.DrawLine(posC, resultNlerp + posC, colC);
angleNlerp = Vector3.Angle(a, resultNlerp);
}
}
```