Calculate vector exactly between 2 vectors

Lets say i have vector.forward and vector.right. How would i use those two vectors to get the vector pointing forwardright?
The reason im asking is because im implementing motion relative to camera. I was able to successfully implement left and right addforce directions using

cameraRelativeRight = cam.TransformDirection (Vector3.right);

and up,down using

    cameraRelativeUp = cam.TransformDirection (Vector3.forward);
    cameraRelativeUp.y = 0;
    cameraRelativeUp = cameraRelativeUp.normalized;

but using the same approach for upright didnt work

cameraRelativeUpRight = cam.TransformDirection (Vector3(1,0,1));
cameraRelativeUpRight.y = 0;
cameraRelativeUpRight = cameraRelativeUpRight.normalized;

The resulting vector is skewed more to the right, and i assume that’s because i modified the y component of the forward vector which lessened its magnitude in that direction.

I was thinking then to somehow combine the cameraRelativeUp and cameraRelativeRight vectors since individually they are correct, but i’m a bit confused as to how to do this? help please :slight_smile:

The Vector half way between two normalized vectors is their sum, normalized.

  var halfWayVector = (Vector3.up + Vector3.right).normalized;

If you want the weights of the original Vector3 to count toward the final weight, it’s:

Vector3 first = //Something
Vector3 second = //Something else
Vector3 bisection = (first + second) * 0.5;

If you want it normalized, you have to normalize the first and second vectors first, then normalize the third. (This will find the vector that bisects the angle rather than bisects by weight.)

And btw, bisection is the mathematical term for what you’re asking for.

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:

  1. A vector that literally points to a position between the two original vectors, or
  2. 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);
    }
}

To be honest I’ve never used TransformDirection so I could be way off here. I’ll throw a few examples in case they might work:

enter code here:

//rotation with angles instead of vectors:

transform.RotateAround (transform.position, transform.up, 90f);
transform.RotateAround (transform.position, transform.right, 90f);

//rotation with making camera look at vectors:
// you may need to add all these vectors below to your original camera transform position depending on how you are coding all this.

Vector3 vectorUpPosition = new Vector3 (0, 1, 0);
Vector3 vectorRightPostition = new Vector3 (1, 0, 0);

vector3 cameraLookVectorPosition = vectorUpPosition + vectorRightPosition;

transform.LookAt (cameraLookVectorPosition);

//this.transform can be very helpful for looking at objects to depending on what you're doing. you could set a vector like:

playerDestinationVector = new Vector3 (rayHitObject.transform.position.x, this.transform.position.y, rayHitObject.transform.position.z);

this.transform.LookAt (playerDestinationVector)

//in above example the transform will only rotate the x and z coordinates. The Y will remain where it currently is due to the this.transform statement.

There’s a few quick ideas it would be easier to give you an answer if you explained how you want the camera to function, I assume it doesn’t just look randomly in certain directions like your example suggests?