Skip to content

第2章:向量与线性代数基础

2.1 向量基础

2.1.1 什么是向量

在数学中,向量(Vector)是一个既有大小(magnitude)又有方向(direction)的量。与之相对的是标量(Scalar),标量只有大小没有方向。

标量 vs 向量

标量(Scalar):
- 温度:25°C
- 质量:5kg
- 时间:3秒
特点:只有大小

向量(Vector):
- 位移:向东走5米
- 速度:每秒向北3米
- 力:向下100牛顿
特点:有大小和方向


向量的几何表示:


    │  方向

○───┼───────► 
起点      终点(箭头)

向量可以自由移动(只要方向和大小不变)

2.1.2 向量的表示方法

在计算机图形学中,我们使用坐标来表示向量:

2D 向量表示

                    y


                    │    • v = (3, 2)
                    │   ╱│
                    │  ╱ │ 2
                    │ ╱  │
                    │╱   │
    ────────────────┼────┴────► x
                    │    3


向量 v 可以表示为:
- 坐标形式:v = (3, 2)
- 列向量形式:
      ┌   ┐
  v = │ 3 │
      │ 2 │
      └   ┘


3D 向量表示

                    y


                    │    • v = (2, 3, 4)
                    │   ╱
                    │  ╱
                    │ ╱
                    │╱
    ────────────────┼──────────► x
                   ╱│
                  ╱ │
                 ╱  │

                z

向量 v = (2, 3, 4)
- x 分量:2
- y 分量:3
- z 分量:4

2.1.3 JavaScript 中的向量表示

javascript
// 简单对象表示
const vector2D = { x: 3, y: 2 };
const vector3D = { x: 2, y: 3, z: 4 };

// 数组表示
const vec2 = [3, 2];
const vec3 = [2, 3, 4];

// 类表示
class Vector2 {
    constructor(x = 0, y = 0) {
        this.x = x;
        this.y = y;
    }
}

class Vector3 {
    constructor(x = 0, y = 0, z = 0) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

const v2 = new Vector2(3, 2);
const v3 = new Vector3(2, 3, 4);

2.2 向量运算

2.2.1 向量加法

向量加法遵循平行四边形法则或首尾相接法则:

向量加法的几何意义

方法1:首尾相接法

    a + b 的结果:

           b
    ○─────────►
    │          ╲
    │           ╲
  a │            ╲ a + b
    │             ╲
    │              ╲
    ▼               ▼
    ────────────────►


方法2:平行四边形法则

         ╱╲
        ╱  ╲
       ╱    ╲ b
    a ╱      ╲
     ╱   a+b  ╲
    ○─────────►
         b


数学表达式:

如果 a = (a₁, a₂) 且 b = (b₁, b₂),则:

a + b = (a₁ + b₁, a₂ + b₂)

例如:
(3, 2) + (1, 4) = (3+1, 2+4) = (4, 6)

2.2.2 向量减法

向量减法可以理解为加上一个反向向量:

向量减法的几何意义

a - b 等于 a + (-b)

    从 b 指向 a 的向量

    ▲ a


    │    a - b
    │   ╱
    │  ╱
    │ ╱
    ○─────────► b


数学表达式:

a - b = (a₁ - b₁, a₂ - b₂)

例如:
(5, 4) - (2, 1) = (5-2, 4-1) = (3, 3)


应用:计算两点之间的向量

点 A = (1, 2)
点 B = (4, 6)

从 A 到 B 的向量 = B - A = (4-1, 6-2) = (3, 4)

2.2.3 标量乘法

向量乘以标量会改变向量的长度,如果是负数还会改变方向:

标量乘法

设向量 v = (2, 3)

2v = (4, 6)      ← 长度变为2倍
0.5v = (1, 1.5)  ← 长度变为一半
-v = (-2, -3)    ← 方向相反


几何示意:

原向量 v:

    │ v



2v(两倍长度):


    │ 2v




-v(反向):


    │ -v



数学表达式:

如果 v = (v₁, v₂) 且 k 是标量,则:

kv = (k·v₁, k·v₂)

2.2.4 代码实现

javascript
class Vector2 {
    constructor(x = 0, y = 0) {
        this.x = x;
        this.y = y;
    }
    
    // 向量加法
    add(v) {
        return new Vector2(this.x + v.x, this.y + v.y);
    }
    
    // 向量减法
    subtract(v) {
        return new Vector2(this.x - v.x, this.y - v.y);
    }
    
    // 标量乘法
    scale(scalar) {
        return new Vector2(this.x * scalar, this.y * scalar);
    }
    
    // 取反
    negate() {
        return new Vector2(-this.x, -this.y);
    }
}

// 使用示例
const a = new Vector2(3, 4);
const b = new Vector2(1, 2);

console.log(a.add(b));      // Vector2 { x: 4, y: 6 }
console.log(a.subtract(b)); // Vector2 { x: 2, y: 2 }
console.log(a.scale(2));    // Vector2 { x: 6, y: 8 }
console.log(a.negate());    // Vector2 { x: -3, y: -4 }

2.3 点积(内积)

2.3.1 点积的定义

点积(Dot Product)是两个向量的一种乘法运算,结果是一个标量

点积的两种定义

代数定义:
a · b = a₁b₁ + a₂b₂ + a₃b₃

几何定义:
a · b = |a| |b| cos(θ)

其中 θ 是两个向量之间的夹角


例子:

a = (1, 2, 3)
b = (4, 5, 6)

a · b = 1×4 + 2×5 + 3×6
     = 4 + 10 + 18
     = 32

2.3.2 点积的几何意义

点积与夹角的关系

         b


      ╱ θ

    ○─────────► a


a · b = |a| |b| cos(θ)

因此:
cos(θ) = (a · b) / (|a| |b|)


点积结果的含义:

┌──────────────────────────────────────────────────────┐
│  a · b > 0   →   θ < 90°   →   两向量夹角为锐角     │
│  a · b = 0   →   θ = 90°   →   两向量垂直          │
│  a · b < 0   →   θ > 90°   →   两向量夹角为钝角     │
└──────────────────────────────────────────────────────┘


特别地:
- a · a = |a|²  (向量点积自己等于长度的平方)

2.3.3 点积的应用

应用1:计算两向量夹角

function angleBetween(a, b) {
    const dot = a.x * b.x + a.y * b.y;
    const lenA = Math.sqrt(a.x * a.x + a.y * a.y);
    const lenB = Math.sqrt(b.x * b.x + b.y * b.y);
    const cosTheta = dot / (lenA * lenB);
    return Math.acos(cosTheta); // 弧度
}


应用2:判断向量方向关系

function checkDirection(a, b) {
    const dot = a.x * b.x + a.y * b.y;
    
    if (dot > 0) return "同向(夹角 < 90°)";
    if (dot < 0) return "反向(夹角 > 90°)";
    return "垂直(夹角 = 90°)";
}


应用3:投影

向量 a 在向量 b 上的投影长度:

               b
              ╱│
             ╱ │ a
            ╱  │
           ╱ θ │
    ○─────●────┴─────► b

        投影点

投影长度 = |a| cos(θ) = (a · b) / |b|

投影向量 = ((a · b) / |b|²) × b

2.3.4 代码实现

javascript
class Vector2 {
    constructor(x = 0, y = 0) {
        this.x = x;
        this.y = y;
    }
    
    // 点积
    dot(v) {
        return this.x * v.x + this.y * v.y;
    }
    
    // 向量长度
    length() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }
    
    // 长度的平方(避免开方运算)
    lengthSquared() {
        return this.x * this.x + this.y * this.y;
    }
    
    // 计算与另一向量的夹角(弧度)
    angleTo(v) {
        const dot = this.dot(v);
        const len = this.length() * v.length();
        return Math.acos(Math.max(-1, Math.min(1, dot / len)));
    }
    
    // 投影到另一向量
    projectOnto(v) {
        const scalar = this.dot(v) / v.lengthSquared();
        return new Vector2(v.x * scalar, v.y * scalar);
    }
    
    // 判断是否与另一向量垂直
    isPerpendicularTo(v, epsilon = 0.0001) {
        return Math.abs(this.dot(v)) < epsilon;
    }
}

// 使用示例
const a = new Vector2(3, 4);
const b = new Vector2(4, 3);

console.log(a.dot(b));      // 24
console.log(a.length());    // 5
console.log(a.angleTo(b));  // 约 0.284 弧度 ≈ 16.26°

// 垂直测试
const v1 = new Vector2(1, 0);
const v2 = new Vector2(0, 1);
console.log(v1.isPerpendicularTo(v2)); // true

2.4 叉积(外积)

2.4.1 叉积的定义

叉积(Cross Product)是两个向量的另一种乘法运算,结果是一个向量(仅限于3D向量):

叉积的定义(3D)

a × b = (a₂b₃ - a₃b₂, a₃b₁ - a₁b₃, a₁b₂ - a₂b₁)


使用行列式表示:

          | i   j   k  |
a × b = | a₁  a₂  a₃ |
          | b₁  b₂  b₃ |


展开:
= i(a₂b₃ - a₃b₂) - j(a₁b₃ - a₃b₁) + k(a₁b₂ - a₂b₁)


例子:
a = (1, 0, 0)
b = (0, 1, 0)

a × b = (0×0 - 0×1, 0×0 - 1×0, 1×1 - 0×0)
      = (0, 0, 1)

结果是 z 轴正方向的单位向量

2.4.2 叉积的几何意义

叉积的结果

1. 方向:垂直于 a 和 b 组成的平面
2. 大小:|a × b| = |a| |b| sin(θ)(等于平行四边形面积)


右手定则:

四指从 a 转向 b,大拇指指向 a × b 的方向

           a × b



    ○────────┤
   ╱         │
  a          └──────► b


注意:叉积不满足交换律
a × b ≠ b × a
实际上:a × b = -(b × a)

2.4.3 2D 中的"叉积"

虽然严格意义上2D向量没有叉积,但我们可以定义一个类似的运算:

2D 叉积(返回标量)

a × b = a₁b₂ - a₂b₁


这个值的几何意义:

1. 结果的绝对值 = 平行四边形面积
2. 结果的符号 = 确定旋转方向

               b



    ○──────●────► a

如果 a × b > 0:b 在 a 的逆时针方向(左侧)
如果 a × b < 0:b 在 a 的顺时针方向(右侧)
如果 a × b = 0:a 和 b 平行

2.4.4 叉积的应用

应用1:计算法向量(3D)

给定平面上的两个向量,叉积得到平面的法向量

function surfaceNormal(v1, v2) {
    return v1.cross(v2).normalize();
}


应用2:判断点在线段的哪一侧(2D)

    点 P 在 AB 的哪一侧?

         P •


    A●──────●B

向量 AB = B - A
向量 AP = P - A

如果 AB × AP > 0,P 在左侧
如果 AB × AP < 0,P 在右侧


应用3:计算三角形面积

三角形 ABC 的面积 = |AB × AC| / 2

2.4.5 代码实现

javascript
// 3D 向量
class Vector3 {
    constructor(x = 0, y = 0, z = 0) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    
    // 叉积
    cross(v) {
        return new Vector3(
            this.y * v.z - this.z * v.y,
            this.z * v.x - this.x * v.z,
            this.x * v.y - this.y * v.x
        );
    }
    
    // 长度
    length() {
        return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
    }
    
    // 归一化
    normalize() {
        const len = this.length();
        if (len === 0) return new Vector3();
        return new Vector3(this.x / len, this.y / len, this.z / len);
    }
}

// 2D 向量
class Vector2 {
    constructor(x = 0, y = 0) {
        this.x = x;
        this.y = y;
    }
    
    // 2D "叉积"(返回标量)
    cross(v) {
        return this.x * v.y - this.y * v.x;
    }
    
    // 判断点在线段的哪一侧
    static pointSide(lineStart, lineEnd, point) {
        const line = new Vector2(
            lineEnd.x - lineStart.x,
            lineEnd.y - lineStart.y
        );
        const toPoint = new Vector2(
            point.x - lineStart.x,
            point.y - lineStart.y
        );
        
        const cross = line.cross(toPoint);
        
        if (cross > 0) return 'left';
        if (cross < 0) return 'right';
        return 'on_line';
    }
    
    // 计算三角形面积
    static triangleArea(a, b, c) {
        const ab = new Vector2(b.x - a.x, b.y - a.y);
        const ac = new Vector2(c.x - a.x, c.y - a.y);
        return Math.abs(ab.cross(ac)) / 2;
    }
}

// 使用示例
const v1 = new Vector3(1, 0, 0);
const v2 = new Vector3(0, 1, 0);
const v3 = v1.cross(v2);
console.log(v3); // Vector3 { x: 0, y: 0, z: 1 }

// 判断点的位置
const a = { x: 0, y: 0 };
const b = { x: 10, y: 0 };
const p = { x: 5, y: 3 };
console.log(Vector2.pointSide(a, b, p)); // 'left'

// 计算三角形面积
const t1 = { x: 0, y: 0 };
const t2 = { x: 4, y: 0 };
const t3 = { x: 0, y: 3 };
console.log(Vector2.triangleArea(t1, t2, t3)); // 6

2.5 向量规范化

2.5.1 单位向量

单位向量(Unit Vector)是长度为1的向量,它只表示方向:

单位向量

任意非零向量 v 可以被规范化为单位向量:

        v
v̂ = ─────
      |v|


视觉表示:

原向量(长度为5):
    ────────────────────► v

单位向量(长度为1):
    ────► v̂


例子:
v = (3, 4)
|v| = √(3² + 4²) = √25 = 5

v̂ = (3/5, 4/5) = (0.6, 0.8)

验证:|v̂| = √(0.6² + 0.8²) = √(0.36 + 0.64) = √1 = 1 ✓

2.5.2 为什么需要单位向量

单位向量的用途

1. 表示纯方向
   - 光线方向
   - 表面法向量
   - 运动方向

2. 简化计算
   - |v̂| = 1,很多公式可以简化
   - 例如:a · v̂ 直接得到投影长度

3. 着色器中的常见需求
   - 法向量必须是单位向量
   - 光照计算需要单位方向向量

2.5.3 代码实现

javascript
class Vector2 {
    constructor(x = 0, y = 0) {
        this.x = x;
        this.y = y;
    }
    
    // 向量长度
    length() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }
    
    // 规范化(返回新向量)
    normalize() {
        const len = this.length();
        if (len === 0) {
            console.warn('Cannot normalize zero vector');
            return new Vector2();
        }
        return new Vector2(this.x / len, this.y / len);
    }
    
    // 就地规范化(修改自身)
    normalizeSelf() {
        const len = this.length();
        if (len === 0) {
            console.warn('Cannot normalize zero vector');
            return this;
        }
        this.x /= len;
        this.y /= len;
        return this;
    }
    
    // 检查是否为单位向量
    isUnit(epsilon = 0.0001) {
        return Math.abs(this.length() - 1) < epsilon;
    }
    
    // 设置长度(保持方向)
    setLength(newLength) {
        return this.normalize().scale(newLength);
    }
    
    scale(scalar) {
        return new Vector2(this.x * scalar, this.y * scalar);
    }
}

// 使用示例
const v = new Vector2(3, 4);

console.log(v.length());         // 5
console.log(v.normalize());      // Vector2 { x: 0.6, y: 0.8 }
console.log(v.normalize().length()); // 1 (或非常接近1)
console.log(v.normalize().isUnit()); // true

2.6 向量空间

2.6.1 基本概念

向量空间的概念

向量空间是由向量组成的集合,满足加法和标量乘法的封闭性。


2D 向量空间:
- 所有形如 (x, y) 的向量
- 任意两个向量相加仍在空间中
- 任意向量乘标量仍在空间中


基向量(Basis Vectors):

在 2D 中,标准基向量为:
- e₁ = (1, 0) ─ x 轴方向的单位向量
- e₂ = (0, 1) ─ y 轴方向的单位向量

任何 2D 向量都可以表示为基向量的线性组合:

v = (3, 4) = 3·e₁ + 4·e₂


坐标系示意:

       e₂


        │ (0,1)

────────┼────────► e₁
        │        (1,0)

2.6.2 线性组合与生成空间

线性组合

给定向量 v₁, v₂, ..., vₙ 和标量 c₁, c₂, ..., cₙ

线性组合:c₁v₁ + c₂v₂ + ... + cₙvₙ


生成空间(Span)

向量组的所有可能线性组合构成的集合

例如:
span{(1,0), (0,1)} = 整个 2D 平面
span{(1,0)} = x 轴(一条直线)
span{(1,2), (2,4)} = 过原点的一条直线(因为 (2,4) = 2·(1,2))

2.6.3 线性无关

线性无关

如果向量组中没有任何一个向量可以用其他向量的线性组合表示,
则称这组向量线性无关。


判断方法:

2D 中两个向量 a, b 线性无关 ⟺ a × b ≠ 0(不平行)


例子:
v₁ = (1, 2)
v₂ = (3, 4)

v₁ × v₂ = 1×4 - 2×3 = 4 - 6 = -2 ≠ 0

所以 v₁, v₂ 线性无关,它们可以作为 2D 空间的基。

2.6.4 坐标变换基础

不同基下的坐标

同一个向量在不同的基下有不同的坐标表示。


例子:

标准基 {e₁=(1,0), e₂=(0,1)} 下:
v = (3, 4)

新基 {b₁=(1,1), b₂=(1,-1)} 下:
v = (3, 4) = ?·b₁ + ?·b₂

解方程:
3 = 1·c₁ + 1·c₂
4 = 1·c₁ + (-1)·c₂

解得:c₁ = 3.5, c₂ = -0.5

验证:
3.5·(1,1) + (-0.5)·(1,-1) = (3.5, 3.5) + (-0.5, 0.5) = (3, 4) ✓

2.7 完整向量类实现

javascript
/**
 * 完整的 2D 向量类
 */
class Vec2 {
    constructor(x = 0, y = 0) {
        this.x = x;
        this.y = y;
    }
    
    // ========== 静态工厂方法 ==========
    
    static zero() {
        return new Vec2(0, 0);
    }
    
    static one() {
        return new Vec2(1, 1);
    }
    
    static unitX() {
        return new Vec2(1, 0);
    }
    
    static unitY() {
        return new Vec2(0, 1);
    }
    
    static fromAngle(angle) {
        return new Vec2(Math.cos(angle), Math.sin(angle));
    }
    
    static fromArray(arr) {
        return new Vec2(arr[0] || 0, arr[1] || 0);
    }
    
    static random(min = 0, max = 1) {
        const range = max - min;
        return new Vec2(
            Math.random() * range + min,
            Math.random() * range + min
        );
    }
    
    // ========== 基本运算 ==========
    
    clone() {
        return new Vec2(this.x, this.y);
    }
    
    copy(v) {
        this.x = v.x;
        this.y = v.y;
        return this;
    }
    
    set(x, y) {
        this.x = x;
        this.y = y;
        return this;
    }
    
    add(v) {
        return new Vec2(this.x + v.x, this.y + v.y);
    }
    
    addSelf(v) {
        this.x += v.x;
        this.y += v.y;
        return this;
    }
    
    subtract(v) {
        return new Vec2(this.x - v.x, this.y - v.y);
    }
    
    subtractSelf(v) {
        this.x -= v.x;
        this.y -= v.y;
        return this;
    }
    
    scale(scalar) {
        return new Vec2(this.x * scalar, this.y * scalar);
    }
    
    scaleSelf(scalar) {
        this.x *= scalar;
        this.y *= scalar;
        return this;
    }
    
    divide(scalar) {
        if (scalar === 0) {
            console.warn('Division by zero');
            return new Vec2();
        }
        return new Vec2(this.x / scalar, this.y / scalar);
    }
    
    negate() {
        return new Vec2(-this.x, -this.y);
    }
    
    negateSelf() {
        this.x = -this.x;
        this.y = -this.y;
        return this;
    }
    
    // ========== 向量积 ==========
    
    dot(v) {
        return this.x * v.x + this.y * v.y;
    }
    
    cross(v) {
        return this.x * v.y - this.y * v.x;
    }
    
    // ========== 长度与规范化 ==========
    
    length() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }
    
    lengthSquared() {
        return this.x * this.x + this.y * this.y;
    }
    
    normalize() {
        const len = this.length();
        if (len === 0) return new Vec2();
        return new Vec2(this.x / len, this.y / len);
    }
    
    normalizeSelf() {
        const len = this.length();
        if (len > 0) {
            this.x /= len;
            this.y /= len;
        }
        return this;
    }
    
    setLength(length) {
        return this.normalize().scaleSelf(length);
    }
    
    limit(maxLength) {
        const lenSq = this.lengthSquared();
        if (lenSq > maxLength * maxLength) {
            return this.normalize().scale(maxLength);
        }
        return this.clone();
    }
    
    // ========== 角度与旋转 ==========
    
    angle() {
        return Math.atan2(this.y, this.x);
    }
    
    angleTo(v) {
        const dot = this.dot(v);
        const len = this.length() * v.length();
        if (len === 0) return 0;
        return Math.acos(Math.max(-1, Math.min(1, dot / len)));
    }
    
    signedAngleTo(v) {
        return Math.atan2(this.cross(v), this.dot(v));
    }
    
    rotate(angle) {
        const cos = Math.cos(angle);
        const sin = Math.sin(angle);
        return new Vec2(
            this.x * cos - this.y * sin,
            this.x * sin + this.y * cos
        );
    }
    
    rotateSelf(angle) {
        const cos = Math.cos(angle);
        const sin = Math.sin(angle);
        const x = this.x * cos - this.y * sin;
        const y = this.x * sin + this.y * cos;
        this.x = x;
        this.y = y;
        return this;
    }
    
    // ========== 投影与反射 ==========
    
    projectOnto(v) {
        const lenSq = v.lengthSquared();
        if (lenSq === 0) return new Vec2();
        const scalar = this.dot(v) / lenSq;
        return v.scale(scalar);
    }
    
    reject(v) {
        return this.subtract(this.projectOnto(v));
    }
    
    reflect(normal) {
        const d = 2 * this.dot(normal);
        return new Vec2(
            this.x - d * normal.x,
            this.y - d * normal.y
        );
    }
    
    // ========== 距离计算 ==========
    
    distanceTo(v) {
        const dx = this.x - v.x;
        const dy = this.y - v.y;
        return Math.sqrt(dx * dx + dy * dy);
    }
    
    distanceSquaredTo(v) {
        const dx = this.x - v.x;
        const dy = this.y - v.y;
        return dx * dx + dy * dy;
    }
    
    manhattanDistanceTo(v) {
        return Math.abs(this.x - v.x) + Math.abs(this.y - v.y);
    }
    
    // ========== 插值 ==========
    
    lerp(v, t) {
        return new Vec2(
            this.x + (v.x - this.x) * t,
            this.y + (v.y - this.y) * t
        );
    }
    
    // ========== 比较 ==========
    
    equals(v, epsilon = 0.0001) {
        return Math.abs(this.x - v.x) < epsilon && 
               Math.abs(this.y - v.y) < epsilon;
    }
    
    isZero(epsilon = 0.0001) {
        return this.lengthSquared() < epsilon * epsilon;
    }
    
    isUnit(epsilon = 0.0001) {
        return Math.abs(this.lengthSquared() - 1) < epsilon;
    }
    
    // ========== 垂直向量 ==========
    
    perpendicular() {
        return new Vec2(-this.y, this.x);
    }
    
    perpendicularCW() {
        return new Vec2(this.y, -this.x);
    }
    
    // ========== 工具方法 ==========
    
    toArray() {
        return [this.x, this.y];
    }
    
    toString() {
        return `Vec2(${this.x.toFixed(4)}, ${this.y.toFixed(4)})`;
    }
    
    toFixed(digits = 2) {
        return `(${this.x.toFixed(digits)}, ${this.y.toFixed(digits)})`;
    }
}

// 导出
export default Vec2;

2.8 本章小结

核心概念

概念定义公式
向量有大小和方向的量v = (x, y)
向量加法首尾相接或平行四边形法则a + b = (a₁+b₁, a₂+b₂)
标量乘法改变向量长度kv = (kv₁, kv₂)
点积两向量乘法,结果为标量a·b = a₁b₁ + a₂b₂
叉积两向量乘法,结果为向量a×b = (a₂b₃-a₃b₂, ...)
单位向量长度为1的向量v̂ = v/
向量长度向量的大小

关键公式

向量长度:    |v| = √(v₁² + v₂² + v₃²)

点积:        a · b = |a||b|cos(θ) = a₁b₁ + a₂b₂ + a₃b₃

叉积大小:    |a × b| = |a||b|sin(θ)

夹角:        cos(θ) = (a · b) / (|a||b|)

投影长度:    proj = (a · b) / |b|

2D叉积:      a × b = a₁b₂ - a₂b₁

图形学中的应用

操作应用场景
向量加法位移、力的合成、速度叠加
向量减法计算方向向量、相对位置
点积光照计算、判断方向、投影
叉积法向量、判断左右、面积计算
规范化方向向量、法向量
投影阴影、碰撞检测

下一章预告:在第3章中,我们将学习矩阵与变换,理解如何用矩阵表示旋转、缩放、平移等几何变换。


文档版本:v1.0
字数统计:约 10,000 字

如有转载或 CV 的请标注本站原文地址