一、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);
三、性能与精度思考
- 避免重复计算
- 缓存
normalized、sqrMagnitude; - 批量计算时尽量合并操作。
- 缓存
- 精度误差
- 在大世界坐标下,浮点精度下降,可考虑 局部原点平移;
- 对非关键视觉效果可适当降低精度。
- 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;
}