Maths

Vectors (Maths for Game Developers)

Edit on Github | Updated: 26th April 2026

Introduction to Vectors

A vector describes magnitude and direction 1. In game code, that usually means a small structure such as Vector2 or Vector3, but the storage type is only the implementation detail. The useful part is that a vector can represent both where something is pointing and how strong that movement, force, or offset is.

Vectors appear everywhere in game engines:

  • Position offsets - The displacement from one object to another
  • Velocity - Speed plus direction
  • Acceleration - Forces such as gravity or recoil
  • Surface normals - Perpendicular directions used for lighting and collision
  • Facing directions - Where a camera, enemy, or projectile is aimed

Core Operations

A few vector operations appear in almost every game codebase:

Addition and subtraction

Adding vectors combines offsets or forces 1. Subtracting b - a gives the vector from point a to point b, which is why subtraction is usually the first step for steering, target tracking, and range checks 1.

This small example shows both operations in a gameplay-style context:

type Vec3 = { x: number; y: number; z: number };

function add(a: Vec3, b: Vec3): Vec3 {
  return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
}

function subtract(a: Vec3, b: Vec3): Vec3 {
  return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
}

const playerPos = { x: 4, y: 0, z: 1 };
const step = { x: 1, y: 0, z: 0 };
const enemyPos = { x: 10, y: 0, z: 5 };

const nextPlayerPos = add(playerPos, step);
const toEnemy = subtract(enemyPos, playerPos);

In the above example nextPlayerPos becomes { x: 5, y: 0, z: 1 }, while toEnemy becomes { x: 6, y: 0, z: 4 }.

Magnitude and normalization

The magnitude is the length of the vector. Normalization keeps the direction but rescales the length to 1, which is useful when you want a direction without carrying the original speed or distance 2. If the vector has zero length, normalization has to be handled carefully because there is no valid direction to preserve 2.

This short example shows how magnitude-related helpers are usually written in engine code:

type Vec3 = { x: number; y: number; z: number };

function magnitude(v: Vec3): number {
  return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
}

function normalize(v: Vec3): Vec3 {
  const len = magnitude(v);
  if (len === 0) {
    return { x: 0, y: 0, z: 0 };
  }

  return { x: v.x / len, y: v.y / len, z: v.z / len };
}

const velocity = { x: 3, y: 4, z: 0 };

const speed = magnitude(velocity);
const direction = normalize(velocity);

The result of the above is speed = 5, while direction keeps the same heading but rescales the vector to unit length so it is { x: 0.6, y: 0.8, z: 0 }. The zero-vector branch here is just a defensive programming choice for the example, because a vector with no length does not have a meaningful direction to normalize.

Distance and squared distance

Distance between two points is the magnitude of their difference, so distance(a, b) = length(b - a) 3. Many engines also expose squared distance because it avoids the square root step that a true magnitude calculation needs 13. That matters in hot code such as proximity checks, AI perception, and broad collision filtering. For example, an enemy AI can check whether the player has entered its aggro radius, or a pickup can check whether the player is close enough to collect it, without paying for a square root every frame.

The Brackeys video below is a good companion for this section because it walks through displacement vectors, distance, and the cost of repeated square root operations in engine code:

When you only need a comparison, prefer patterns like these:

  • Range checks - Compare distanceSq < maxRange * maxRange
  • Sorting nearby objects - Compare squared distances directly
  • Cheap rejection tests - Reject obvious misses before doing more expensive work

This is the same optimization pattern exposed later on this page by VEC_SquareMagnitude and VEC_SquareDistance.

Here is the same idea in code using a player and enemy position:

type Vec3 = { x: number; y: number; z: number };

function subtract(a: Vec3, b: Vec3): Vec3 {
  return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
}

function lengthSq(v: Vec3): number {
  return v.x * v.x + v.y * v.y + v.z * v.z;
}

const enemyPos = { x: 10, y: 0, z: 5 };
const playerPos = { x: 4, y: 0, z: 1 };

// `toEnemy` is the displacement vector from the player to the enemy.
const toEnemy = subtract(enemyPos, playerPos); // result: { x: 6, y: 0, z: 4 }
// `inRange` uses squared distance to avoid an unnecessary square root.
const inRange = lengthSq(toEnemy) < 64; // 8 units squared, result: true

In this example lengthSq(toEnemy) is 52, so inRange is true.

Dot product

The dot product measures how much one vector points in the direction of another 14. For normalized vectors, it collapses to the cosine of the angle between them 4. It is also often called the inner product, especially in more formal math libraries and SDKs such as the Sony PSP VFPU headers.

The sign and size of the result usually mean:

  • Positive - The vectors point in roughly the same direction
  • Zero - The vectors are perpendicular
  • Negative - The vectors point in opposite hemispheres

This makes dot products useful for:

  • Field-of-view checks - Is a target broadly in front of an actor?
  • Back-face culling - Is a triangle facing away from the camera?
  • Lighting - How closely does a surface normal align with a light direction?
  • Signed speed tests - How much of a velocity vector lies along a forward axis?

PothOnProgramming offers a technical breakdown of the 2D dot product and its critical applications in game design and engine logic. The video highlights several fundamental applications of the dot product used in game development and vector math.

This snippet shows a typical field-of-view style use of the dot product:

type Vec3 = { x: number; y: number; z: number };

function dot(a: Vec3, b: Vec3): number {
  return a.x * b.x + a.y * b.y + a.z * b.z;
}

function normalize(v: Vec3): Vec3 {
  const len = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
  if (len === 0) {
    return { x: 0, y: 0, z: 0 };
  }

  return { x: v.x / len, y: v.y / len, z: v.z / len };
}

const playerForward = normalize({ x: 1, y: 0, z: 0 });
const toEnemy = normalize({ x: 6, y: 0, z: 4 });
// `facingScore` moves toward `1` when the player is looking directly at the enemy and toward `-1` when facing away.
const facingScore = dot(playerForward, toEnemy);

In this example it is about 0.83, which means the enemy is clearly in front of the player but not perfectly centered.

Cross product

The cross product only makes sense in 3D 15. It returns a new vector perpendicular to both inputs, with a magnitude based on the sine of the angle between them 5. Some libraries also call this an outer product, although in broader linear algebra that term can mean a different operation. In practice, game programmers use it to build triangle normals, construct camera bases, and derive right, up, or forward axes from each other.

Jorge Rodriguez has a good video on how to derive a character’s “right” vector from their “forward” and “up” vectors using the cross product. This video demonstrates how to implement lateral movement (strafing) relative to a camera’s orientation, which is a fundamental requirement for first-person and third-person movement systems. Rodriguez provides both the mathematical theory for calculating orthogonal vectors and the practical C++ implementation needed to integrate these concepts into a game’s velocity calculations.

Games often use a local coordinate frame for the player or camera, so movement can be relative to where the player is facing rather than fixed world axes. The cross product helps derive directions such as forward or right from the other local axes. In this context right, up, and forward are direction axes, not movement values by themselves. Movement happens when the game moves an object along one of those axes.

This example shows how a game can derive a forward direction from existing axes, which is useful when building camera orientation, movement bases, or surface normals:

type Vec3 = { x: number; y: number; z: number };

function cross(a: Vec3, b: Vec3): Vec3 {
  return {
    x: a.y * b.z - a.z * b.y,
    y: a.z * b.x - a.x * b.z,
    z: a.x * b.y - a.y * b.x,
  };
}

const right = { x: 1, y: 0, z: 0 }; // the player's right
const up = { x: 0, y: 1, z: 0 }; // the player's up
const forward = cross(right, up); // the direction the player or camera is facing

In this basis forward becomes { x: 0, y: 0, z: 1 }. If you swap the argument order, the sign flips, which is why operand order matters when working with handedness.

If you want to continue from vectors into transforms and rotations, the Matrix page is the natural next step:


Vector Libraries used in Retail Console Game Development

Looking at retail SDK headers is useful because it shows which operations console programmers expected to use frequently.

Nintendo DS Official Vector Library

The Nintendo DS boot ROM headers expose a compact vector helper API in IrisVEC.h, which is catalogued in this site’s Platinum leak coverage 6. Before looking at the declarations, a few details stand out:

  • Multiple storage widths - Vec10, Vec16, and Vec32 show that Nintendo exposed vector math for different precision and packing tradeoffs
  • Bit-packed coordinates - Vec10 uses 10-bit fields, which is unusual enough to suggest tight memory or hardware-format constraints
  • Performance-aware helpers - VEC_SquareMagnitude, VEC_SquareDistance, and Fast variants reflect the same cost-saving patterns seen in modern engines
  • 2D and 3D support - The header mixes full 3D structs with helper macros such as VEC2D_DotProduct

The fixed-point flavour is especially noticeable here. Both VEC2D_DotProduct and VEC2D_CrossProduct shift by V_SFT, which looks more like a scaling constant than a floating-point API.

Combined with Vec10 and the separate Fast variants, the header reads like an interface designed around compact integer storage and predictable performance on DS-era hardware.

Here are the main storage types exposed by the header:

#define vl volatile

// 10-bit packed coordinates
typedef struct {
    s32 x:10;
    s32 y:10;
    s32 z:10;
} Vec10, Pos10, TestVec;
typedef  vl Pos10     vPos10;
typedef  vl Vec10     vVec10;

// 16-bit
typedef struct {
    s16 x;
    s16 y;
    s16 z;
    s16 w;
} Vec16, Vec, Pos16, TestPos;
typedef  vl Pos16     vPos16;
typedef  vl Vec16     vVec16;
typedef  vl Vec       vVec;

// 32-bit
typedef struct {
    s32 x;
    s32 y;
    s32 z;
} Vec32, Pos32, Pos;
typedef  vl Vec32     vVec32;
typedef  vl Pos32     vPos32;
typedef  vl Pos       vPos;

Here are the main vector helpers exposed by the header:

void VEC_Copy2Vec10(const Vec   *srcp, Vec10 *dstp);
void VEC_Copy2Vec32(const Vec   *srcp, Vec32 *dstp);
void VEC32_Copy2Vec(const Vec32 *srcp, Vec   *dstp);

void VEC_AlignPoint2Vec10(const Vec   *srcp, Vec10 *dstp);
void VEC10_AlignPoint2Vec(const Vec10 *srcp, Vec   *dstp);

s32  VEC_DotProduct(      const Vec   *a, const Vec   *b);
s32  VEC32_DotProduct(    const Vec32 *a, const Vec32 *b);
s32  VEC32_DotProductFast(const Vec32 *a, const Vec32 *b);
s32  VEC32VEC_DotProduct( const Vec32 *a, const Vec   *b);
#define VEC2D_DotProduct(ax, ay, bx, by)    (((ax) * (bx) + (ay) * (by)) >>V_SFT)

void VEC_CrossProduct(      Vec   *a, Vec   *b, Vec   *axb);
void VEC32_CrossProduct(    Vec32 *a, Vec32 *b, Vec32 *axb);
void VEC32_CrossProductFast(Vec32 *a, Vec32 *b, Vec32 *axb);
#define VEC2D_CrossProduct(ax, ay, bx, by)    (((ax) * (by) - (ay) * (bx)) >>V_SFT)

void VEC_Normalize(      Vec   *srcp, Vec   *dstp);
void VEC32_Normalize(    Vec32 *srcp, Vec32 *dstp);
void VEC32_Normalize2Vec(Vec32 *srcp, Vec   *dstp);

void VEC_Add(Vec *a, Vec *b, Vec *ab);
void VEC_Sub(Vec *a, Vec *b, Vec *a_b);
void VEC_Scale(Vec *srcp, Vec *dstp, s32 scale);
void VEC_Reverse(const Vec *srcp, Vec *dstp);

u32  VEC_Magnitude(const Vec *v);
u32  VEC_SquareMagnitude(const Vec *v);

u32  VEC_Distance(const Vec *a, const Vec *b);
u32  VEC_SquareDistance(const Vec *a, const Vec *b);

void VEC_Lerp(Vec *a, Vec *b, Vec *d, s32 t);
void VEC32_Lerp(Vec32 *a, Vec32 *b, Vec32 *d, s32 t);
void VEC32_LerpFast(Vec32 *a, Vec32 *b, Vec32 *d, s32 t);

You can find out more about the Nintendo DS Boot ROM in the Platinum leak:


Sony PSP Vector Library

The official PlayStation Portable (PSP) SDK exposes vector types such as ScePspVector2, ScePspVector3 through the psptypes.h header and vector functions through the VFPU library header libvfpu.h. What makes the PSP vector API interesting is that it looks much closer to a modern real-time graphics math library than the simpler DS helper headers.

The use of floating-point vector types, 16-byte-aligned 4D vectors, and operations such as dot product, cross product, normalization, lerp, reflection, refraction, and face-forward suggests an API designed around the PSP’s VFPU and 3D rendering workloads rather than just basic gameplay math.

The repeated XYZ variants are especially telling, because they imply that many engine data structures were stored in 4D form while still treating only the first three components as position or direction data. In that style of API, the w component is often used for homogeneous-coordinate math, padding/alignment, or some non-spatial extra value while x, y, and z carry the actual spatial direction or position.

Here are the main storage types exposed by the header (psptypes.h). The prefix tells you the underlying storage format: S means short, I means int, L64 means 64-bit integer storage, and F means float.

The union forms such as ScePspVector2 and ScePspVector3 are useful because they let the same bytes be viewed either as named vector structs (fv, iv) or plain arrays (f[], i[]), which makes it easier to switch between component-wise code and bulk math or VFPU-oriented helper code:

  // 2D Vectors
  typedef struct ScePspSVector2 {
    short x, y;
  } ScePspSVector2;

  typedef struct ScePspIVector2 {
    int x, y;
  } ScePspIVector2;

  typedef struct ScePspL64Vector2 {
    SceLong64 x, y;
  } ScePspL64Vector2;

  typedef struct ScePspFVector2 {
    float x, y;
  } ScePspFVector2;

  typedef union ScePspVector2 {
    ScePspFVector2 fv;
    ScePspIVector2 iv;
    float f[2];
    int   i[2];
    struct {
      float fx, fy;
    };
    struct {
      int ix, iy;
    };
  } ScePspVector2;

  // 3D Vectors
  typedef struct ScePspSVector3 {
    short x, y, z;
  } ScePspSVector3;

  typedef struct ScePspIVector3 {
    int x, y, z;
  } ScePspIVector3;

  typedef struct ScePspL64Vector3 {
    SceLong64 x, y, z;
  } ScePspL64Vector3;

  typedef struct ScePspFVector3 {
    float x, y, z;
  } ScePspFVector3;

  typedef union ScePspVector3 {
    ScePspFVector3 fv;
    ScePspIVector3 iv;
    float f[3];
    int   i[3];
    struct {
      float fx, fy, fz;
    };
    struct {
      int ix, iy, iz;
    };
  } ScePspVector3;


  // 4D Vectors
  typedef struct ScePspSVector4 {
    short x, y, z, w;
  } ScePspSVector4;

  typedef struct ScePspIVector4 {
    int x, y, z, w;
  } ScePspIVector4 __attribute__((aligned(16)));

  typedef struct ScePspIVector4Unaligned {
    int x, y, z, w;
  } ScePspIVector4Unaligned;

  typedef struct ScePspL64Vector4 {
    SceLong64 x, y, z, w;
  } ScePspL64Vector4;

  typedef struct ScePspFVector4 {
    float x, y, z, w;
  } ScePspFVector4 __attribute__((aligned(16)));

  typedef struct ScePspFVector4Unaligned {
    float x, y, z, w;
  } ScePspFVector4Unaligned;

  typedef union ScePspVector4 {
    ScePspFVector4 fv;
    ScePspIVector4 iv;
    SceULong128 qw;
    float f[4];
    int   i[4];
    struct {
      float fx, fy, fz, fw;
    };
    struct {
      int ix, iy, iz, iw;
    };
  } ScePspVector4 __attribute__((aligned(16)));
  #define	SVector2		ScePspSVector2
  #define	IVector2		ScePspIVector2
  #define	L64Vector2		ScePspL64Vector2
  #define	FVector2		ScePspFVector2
  #define	Vector2			ScePspVector2

  #define	SVector3		ScePspSVector3
  #define	IVector3		ScePspIVector3
  #define	L64Vector3		ScePspL64Vector3
  #define	FVector3		ScePspFVector3
  #define	Vector3			ScePspVector3

  #define	SVector4		ScePspSVector4
  #define	IVector4		ScePspIVector4
  #define	L64Vector4		ScePspL64Vector4
  #define	FVector4		ScePspFVector4
  #define	Vector4			ScePspVector4

Here are the main vector helpers exposed by the header libvfpu.h 7. They are repeated for each of the vector sizes, so this tab only shows one representative declaration and lists the related variants in a trailing comment.

Some of the less obvious helpers are worth explaining before reading the declarations 8:

  • PositiveZero and NegativeZero show that the PSP SDK cared about exact floating-point bit patterns as well as numeric value. In the source, the negative-zero helpers write the 0x80000000 sign-bit pattern directly into each float lane.
  • Ceil, Trunc, Round, Floor, and FromIVector make the bridge between float vectors and integer vectors explicit. That is useful when an engine moves between VFPU math, grid or tile coordinates, screen-space values, and packed gameplay data.
  • Clamp, Min, Max, Abs, and Neg are all component-wise cleanup helpers. They are the kinds of operations you need when bounding movement, constraining camera input, mirroring directions, or sanitising values before later math.
  • InnerProduct is the PSP SDK’s formal name for the dot product, while OuterProduct is used as the implementation name behind the SDK’s cross-product helpers.
  • Funnel is an unusual name, but the implementation shows that it literally sums the components of the vector. Average does the same reduction and then divides by the number of components.
  • FaceForward, Reflect, and Refract are surface-response helpers that fit naturally with lighting, collision response, and other rendering-style calculations.
  • The sceVfpuVector2FaceForwardXYZ name shown below looks inconsistent with the surrounding 4D XYZ helpers. It is reproduced here as written in the SDK header, but it likely reflects a naming mistake or typo in the original API.
  • NormalizePhase is not vector normalization in the usual magnitude sense. The implementation wraps each component back into the [-pi, +pi] range, so it is better understood as angle or phase normalisation.
// Initialize vectors to positive or negative zero
#define sceVfpuVector2Null(_pv)                          sceVfpuVector2PositiveZero(_pv) // Variants: sceVfpuVector2Zero, sceVfpuVector3Null, sceVfpuVector3Zero, sceVfpuVector4Null, sceVfpuVector4Zero
ScePspFVector2 *sceVfpuVector2PositiveZero(ScePspFVector2 *pv); // Variants: sceVfpuVector3PositiveZero, sceVfpuVector4PositiveZero
ScePspFVector2 *sceVfpuVector2NegativeZero(ScePspFVector2 *pv); // Variants: sceVfpuVector3NegativeZero, sceVfpuVector4NegativeZero

// Set and copy vectors
ScePspFVector2 *sceVfpuVector2Set(ScePspFVector2 *pv0, float x, float y); // Variants: sceVfpuVector3Set, sceVfpuVector4Set
ScePspFVector4 *sceVfpuVector4SetXYZ(ScePspFVector4 *pv0, float x, float y, float z);
ScePspFVector2 *sceVfpuVector2Copy(ScePspFVector2 *pv0, const ScePspFVector2 *pv1); // Variants: sceVfpuVector3Copy, sceVfpuVector4Copy

// Convert floating-point vectors to integer vectors
ScePspIVector2 *sceVfpuVector2Ceil(ScePspIVector2 *pv0, const ScePspFVector2 *pv1); // Variants: sceVfpuVector3Ceil, sceVfpuVector4Ceil
ScePspIVector2 *sceVfpuVector2Trunc(ScePspIVector2 *pv0, const ScePspFVector2 *pv1); // Variants: sceVfpuVector3Trunc, sceVfpuVector4Trunc
ScePspIVector2 *sceVfpuVector2Round(ScePspIVector2 *pv0, const ScePspFVector2 *pv1); // Variants: sceVfpuVector3Round, sceVfpuVector4Round
ScePspIVector2 *sceVfpuVector2Floor(ScePspIVector2 *pv0, const ScePspFVector2 *pv1); // Variants: sceVfpuVector3Floor, sceVfpuVector4Floor

// Convert integer vectors to floating-point vectors
ScePspFVector2 *sceVfpuVector2FromIVector(ScePspFVector2 *pv0, const ScePspIVector2 *pv1); // Variants: sceVfpuVector3FromIVector, sceVfpuVector4FromIVector

// Component-wise arithmetic
ScePspFVector2 *sceVfpuVector2Add(ScePspFVector2 *pv0, const ScePspFVector2 *pv1, const ScePspFVector2 *pv2); // Variants: sceVfpuVector3Add, sceVfpuVector4Add
ScePspFVector4 *sceVfpuVector4AddXYZ(ScePspFVector4 *pv0, const ScePspFVector4 *pv1, const ScePspFVector4 *pv2);

#define sceVfpuVector2Subtract(_pv0, _pv1, _pv2)        sceVfpuVector2Sub(_pv0, _pv1, _pv2) // Variants: sceVfpuVector3Subtract, sceVfpuVector4Subtract
#define sceVfpuVector4SubtractXYZ(_pv0, _pv1, _pv2)     sceVfpuVector4SubXYZ(_pv0, _pv1, _pv2)
ScePspFVector2 *sceVfpuVector2Sub(ScePspFVector2 *pv0, const ScePspFVector2 *pv1, const ScePspFVector2 *pv2); // Variants: sceVfpuVector3Sub, sceVfpuVector4Sub
ScePspFVector4 *sceVfpuVector4SubXYZ(ScePspFVector4 *pv0, const ScePspFVector4 *pv1, const ScePspFVector4 *pv2);

#define sceVfpuVector2Multiply(_pv0, _pv1, _pv2)        sceVfpuVector2Mul(_pv0, _pv1, _pv2) // Variants: sceVfpuVector3Multiply, sceVfpuVector4Multiply
#define sceVfpuVector4MultiplyXYZ(_pv0, _pv1, _pv2)     sceVfpuVector4MulXYZ(_pv0, _pv1, _pv2)
ScePspFVector2 *sceVfpuVector2Mul(ScePspFVector2 *pv0, const ScePspFVector2 *pv1, const ScePspFVector2 *pv2); // Variants: sceVfpuVector3Mul, sceVfpuVector4Mul
ScePspFVector4 *sceVfpuVector4MulXYZ(ScePspFVector4 *pv0, const ScePspFVector4 *pv1, const ScePspFVector4 *pv2);

#define sceVfpuVector2Divide(_pv0, _pv1, _pv2)          sceVfpuVector2Div(_pv0, _pv1, _pv2) // Variants: sceVfpuVector3Divide, sceVfpuVector4Divide
#define sceVfpuVector4DivideXYZ(_pv0, _pv1, _pv2)       sceVfpuVector4DivXYZ(_pv0, _pv1, _pv2)
ScePspFVector2 *sceVfpuVector2Div(ScePspFVector2 *pv0, const ScePspFVector2 *pv1, const ScePspFVector2 *pv2); // Variants: sceVfpuVector3Div, sceVfpuVector4Div
ScePspFVector4 *sceVfpuVector4DivXYZ(ScePspFVector4 *pv0, const ScePspFVector4 *pv1, const ScePspFVector4 *pv2);

// Unary operations and range helpers
ScePspFVector2 *sceVfpuVector2Neg(ScePspFVector2 *pv0, const ScePspFVector2 *pv1); // Variants: sceVfpuVector3Neg, sceVfpuVector4Neg
ScePspFVector2 *sceVfpuVector2Abs(ScePspFVector2 *pv0, const ScePspFVector2 *pv1); // Variants: sceVfpuVector3Abs, sceVfpuVector4Abs
ScePspFVector2 *sceVfpuVector2Clamp(ScePspFVector2 *pv0, const ScePspFVector2 *pv1, float min, float max); // Variants: sceVfpuVector3Clamp, sceVfpuVector4Clamp
ScePspFVector4 *sceVfpuVector4ClampXYZ(ScePspFVector4 *pv0, const ScePspFVector4 *pv1, float min, float max);
ScePspFVector2 *sceVfpuVector2Max(ScePspFVector2 *pv0, const ScePspFVector2 *pv1, const ScePspFVector2 *pv2); // Variants: sceVfpuVector3Max, sceVfpuVector4Max
ScePspFVector2 *sceVfpuVector2Min(ScePspFVector2 *pv0, const ScePspFVector2 *pv1, const ScePspFVector2 *pv2); // Variants: sceVfpuVector3Min, sceVfpuVector4Min

// Scale and interpolation
ScePspFVector2 *sceVfpuVector2Scale(ScePspFVector2 *pv0, const ScePspFVector2 *pv1, float s); // Variants: sceVfpuVector3Scale, sceVfpuVector4Scale
ScePspFVector4 *sceVfpuVector4ScaleXYZ(ScePspFVector4 *pv0, const ScePspFVector4 *pv1, float s);
#define sceVfpuVector2Inter(_pv0,_pv1,_pv2,_t)         sceVfpuVector2Lerp(_pv0,_pv1,_pv2,(1.0f - (_t))) // Variants: sceVfpuVector3Inter, sceVfpuVector4Inter
ScePspFVector2 *sceVfpuVector2Lerp(ScePspFVector2 *pv0, const ScePspFVector2 *pv1, const ScePspFVector2 *pv2, float t); // Variants: sceVfpuVector3Lerp, sceVfpuVector4Lerp
#define sceVfpuVector4InterXYZ(_pv0,_pv1,_pv2,_t)      sceVfpuVector4LerpXYZ(_pv0,_pv1,_pv2,(1.0f - (_t)))
ScePspFVector4 *sceVfpuVector4LerpXYZ(ScePspFVector4 *pv0, const ScePspFVector4 *pv1, const ScePspFVector4 *pv2, float t);

// Dot and cross products
#define sceVfpuVector2Dot(_v1,_v2)                      sceVfpuVector2InnerProduct(_v1,_v2) // Variants: sceVfpuVector3Dot, sceVfpuVector4Dot
#define sceVfpuVector4DotXYZ(_v1,_v2)                   sceVfpuVector4InnerProductXYZ(_v1,_v2)
float sceVfpuVector2InnerProduct(const ScePspFVector2 *pv1, const ScePspFVector2 *pv2); // Variants: sceVfpuVector3InnerProduct, sceVfpuVector4InnerProduct
float sceVfpuVector4InnerProductXYZ(const ScePspFVector4 *pv1, const ScePspFVector4 *pv2);
#define sceVfpuVector3Cross(_v0,_v1,_v2)                sceVfpuVector3OuterProduct(_v0,_v1,_v2) // Variant: sceVfpuVector4Cross
ScePspFVector3 *sceVfpuVector3OuterProduct(ScePspFVector3 *pv0, const ScePspFVector3 *pv1, const ScePspFVector3 *pv2); // Variant: sceVfpuVector4OuterProductXYZ
ScePspFVector4 *sceVfpuVector4OuterProductXYZ(ScePspFVector4 *pv0, const ScePspFVector4 *pv1, const ScePspFVector4 *pv2);

// Aggregate queries and comparison helpers
float sceVfpuVector2Funnel(const ScePspFVector2 *pv); // Variants: sceVfpuVector3Funnel, sceVfpuVector4Funnel
float sceVfpuVector2Average(const ScePspFVector2 *pv); // Variants: sceVfpuVector3Average, sceVfpuVector4Average
SceBool sceVfpuVector2IsEqual(const ScePspFVector2 *pv1, const ScePspFVector2 *pv2); // Variants: sceVfpuVector3IsEqual, sceVfpuVector4IsEqual
#define sceVfpuVector2IsNull(_pv)                       sceVfpuVector2IsZero(_pv) // Variants: sceVfpuVector3IsNull, sceVfpuVector4IsNull
SceBool sceVfpuVector2IsZero(const ScePspFVector2 *pv0); // Variants: sceVfpuVector3IsZero, sceVfpuVector4IsZero
ScePspFVector2 *sceVfpuVector2SignFloat(ScePspFVector2 *pv0, const ScePspFVector2 *pv1); // Variants: sceVfpuVector3SignFloat, sceVfpuVector4SignFloat
ScePspIVector2 *sceVfpuVector2SignInt(ScePspIVector2 *piv, const ScePspFVector2 *pfv); // Variants: sceVfpuVector3SignInt, sceVfpuVector4SignInt

// Length, normalization, and geometric helpers
ScePspFVector2 *sceVfpuVector2Normalize(ScePspFVector2 *pv0, const ScePspFVector2 *pv1); // Variants: sceVfpuVector3Normalize, sceVfpuVector4Normalize
ScePspFVector4 *sceVfpuVector4NormalizeXYZ(ScePspFVector4 *pv0, const ScePspFVector4 *pv1);
float sceVfpuVector2Length(const ScePspFVector2 *pfv); // Variants: sceVfpuVector3Length, sceVfpuVector4LengthXYZ
float sceVfpuVector2Distance(const ScePspFVector2 *pv1, const ScePspFVector2 *pv2); // Variants: sceVfpuVector3Distance, sceVfpuVector4DistanceXYZ
ScePspFVector4 *sceVfpuVector4NormalizePhase(ScePspFVector4 *pv0, const ScePspFVector4 *pv1);
ScePspFVector2 *sceVfpuVector2FaceForward(ScePspFVector2 *pv0, const ScePspFVector2 *pv1, const ScePspFVector2 *pv2, const ScePspFVector2 *pv3); // Variants: sceVfpuVector3FaceForward, sceVfpuVector2FaceForwardXYZ
ScePspFVector4 *sceVfpuVector2FaceForwardXYZ(ScePspFVector4 *pv0, const ScePspFVector4 *pv1, const ScePspFVector4 *pv2, const ScePspFVector4 *pv3);
ScePspFVector2 *sceVfpuVector2Reflect(ScePspFVector2 *pv0, const ScePspFVector2 *pv1, const ScePspFVector2 *pv2); // Variants: sceVfpuVector3Reflect, sceVfpuVector4ReflectXYZ
ScePspFVector4 *sceVfpuVector4ReflectXYZ(ScePspFVector4 *pv0, const ScePspFVector4 *pv1, const ScePspFVector4 *pv2);
ScePspFVector2 *sceVfpuVector2Refract(ScePspFVector2 *pv0, const ScePspFVector2 *pv1, const ScePspFVector2 *pv2, float eta); // Variants: sceVfpuVector3Refract, sceVfpuVector4RefractXYZ
ScePspFVector4 *sceVfpuVector4RefractXYZ(ScePspFVector4 *pv0, const ScePspFVector4 *pv1, const ScePspFVector4 *pv2, float eta);

References