LOADING

加载过慢请开启缓存 浏览器默认开启

Unity 向量计算专题(1):Vector3


一、Vector3 基础

public struct Vector3 {
    public float x;
    public float y;
    public float z;

    public Vector3(float x, float y, float z) { … }
    public static Vector3 zero    => new Vector3(0,0,0);
    public static Vector3 one     => new Vector3(1,1,1);
    public static Vector3 up      => new Vector3(0,1,0);
    public static Vector3 forward => new Vector3(0,0,1);
    // … 还有 right, down, back
}
  • magnitude:向量长度,计算公式

    $$|\mathbf{v}| = \sqrt{x^2 + y^2 + z^2}$$

  • sqrMagnitude:长度平方,避免 sqrt 开销

    $$|\mathbf{v}|^2 = x^2 + y^2 + z^2$$

  • normalized:单位向量

    $$\hat{\mathbf{v}} = \frac{\mathbf{v}}{|\mathbf{v}|}$$

Tip:若只需比较两个向量长度的大小,优先使用 sqrMagnitude


二、常用向量运算

2.1 加减与缩放

Vector3 a = new Vector3(1,2,3);
Vector3 b = new Vector3(4,5,6);
Vector3 sum     = a + b;      // (5,7,9)
Vector3 diff    = a - b;      // (-3,-3,-3)
Vector3 scaled  = a * 2f;     // (2,4,6)
Vector3 invScale= a / 2f;     // (0.5,1,1.5)

2.2 点积(Dot Product)

  • 定义

    $$\mathbf{a} \cdot \mathbf{b} = a_x b_x + a_y b_y + a_z b_z$$

  • 应用

    • 计算两向量夹角:

      $$\cos\theta = \frac{\mathbf{a}\cdot \mathbf{b}}{|\mathbf{a}||\mathbf{b}|}$$

  • 投射长度:proj = Vector3.Dot(a, b.normalized)

float dot = Vector3.Dot(a, b);
float angle = Mathf.Acos(dot / (a.magnitude * b.magnitude)) * Mathf.Rad2Deg;

2.3 叉积(Cross Product)

  • 定义

    $$\mathbf{a} \times \mathbf{b}= \bigl(a_y b_z - a_z b_y \ \ a_z b_x - a_x b_z \ \ a_x b_y - a_y b_x\bigr)$$

  • 应用

    • 计算法线向量;
    • 判断三角形面向。
Vector3 normal = Vector3.Cross(b - a, Vector3.up).normalized;

2.4 投影(Projection)

  • 向量在基向量上的投影

    $\mathrm{proj}_{\mathbf{b}}\mathbf{a}= \left(\frac{\mathbf{a}\cdot \mathbf{b}}{|\mathbf{b}|^2}\right)\mathbf{b}$

Vector3 projOnB = Vector3.Project(a, b);
Vector3 perp     = Vector3.ProjectOnPlane(a, b);  // a 在与 b 垂直平面上的分量

2.5 反射(Reflection)

  • 公式
    $$\mathbf{r} = \mathbf{d} - 2(\mathbf{d}\cdot \mathbf{n}),\mathbf{n}$$
Vector3 inDir  = (target - origin).normalized;
Vector3 refl   = Vector3.Reflect(inDir, normal);  

三、性能与精度思考

  1. 避免重复计算
    • 缓存 normalizedsqrMagnitude
    • 批量计算时尽量合并操作。
  2. 精度误差
    • 在大世界坐标下,浮点精度下降,可考虑 局部原点平移
    • 对非关键视觉效果可适当降低精度。
    • GC Alloc 痕迹
    • 频繁创建临时 Vector3 容易触发 GC,推荐使用 静态复用ref/out 参数:
// 示例
private static Vector3 _tmp;
void Move(ref Vector3 pos, Vector3 dir, float speed) {
    _tmp = dir * speed * Time.deltaTime;
    pos += _tmp;
}

四、实战案例

4.1 相机平滑跟随

public class SmoothFollow : MonoBehaviour {
    public Transform target;
    public float   smoothTime = 0.2f;
    private Vector3 velocity = Vector3.zero;

    void LateUpdate() {
        Vector3 desired = target.position + new Vector3(0,5,-10);
        transform.position = Vector3.SmoothDamp(
            current: transform.position,
            target:  desired,
            currentVelocity: ref velocity,
            smoothTime: smoothTime
        );
        transform.LookAt(target);
    }
}

4.2 角色转向与移动

void Update() {
    Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
    if (input.sqrMagnitude > 0.01f) {
        Vector3 dir = input.normalized;
        // 平滑转向
        transform.rotation = Quaternion.Slerp(
            from: transform.rotation,
            to:   Quaternion.LookRotation(dir),
            t:    Time.deltaTime * turnSpeed
        );
        // 前进
        transform.position += dir * moveSpeed * Time.deltaTime;
    }
}

4.3 碰撞法向力计算

void OnCollisionEnter(Collision col) {
    ContactPoint cp = col.contacts[0];
    Vector3 reflectDir = Vector3.Reflect(rb.velocity.normalized, cp.normal);
    rb.velocity = reflectDir * bounceSpeed;
}