Unity3D数学第一篇:向量与点、线、面(基础篇)

Unity3D数学第二篇:旋转与欧拉角、四元数(核心变换篇)

Unity3D数学第三篇:坐标系与变换矩阵(空间转换篇)

Unity3D数学第四篇:射线与碰撞检测(交互基础篇)

Unity3D数学第五篇:几何计算与常用算法(实用算法篇)

第三篇:坐标系与变换矩阵(空间转换篇)

在 3D 游戏开发中,我们不断地在不同的“参考系”或“视角”之间切换。一个物体的“前方”可能相对于它自身,也可能相对于整个世界;鼠标点击的屏幕位置,最终要对应到 3D 世界中的某个点。这些转换的背后,离不开坐标系 (Coordinate Systems)变换矩阵 (Transformation Matrices) 的强大作用。

本篇教程将深入探讨 Unity 中各种常见的坐标系,揭示它们之间的转换机制,并为你揭开变换矩阵这一“幕后英雄”的面纱。理解这些概念,将让你对 3D 空间中的一切变换拥有更深刻的洞察力。


1. 深入理解坐标系:3D 空间的“视角”

想象一个房间,你可以在房间的中心描述一件家具的位置(例如,“它在我前面两米”),也可以相对于房间的墙角来描述(例如,“它在东墙角往北三米,往西两米”)。这两种描述方式,分别对应着不同的坐标系。

在 3D 游戏世界中,存在多种相互关联的坐标系,它们服务于不同的目的。

1.1 局部坐标系 (Local Space / Object Space)

  • 概念: 每个独立的 3D 物体都有其自身的局部坐标系。这个坐标系的原点通常位于物体的中心点(或称为轴心点 Pivot),而它的 X、Y、Z 轴则沿着物体自身的特定方向。

    • 例如,一个汽车模型,它的局部 Y 轴通常指向它的“上方”(车顶),局部 Z 轴指向它的“前方”(车头),局部 X 轴指向它的“右方”。
  • 特性: 当物体自身旋转或移动时,它的局部坐标系也跟着它一起旋转和移动。因此,一个点在物体局部坐标系中的坐标是固定不变的

  • Unity 中的体现:

    • Transform.localPosition:表示物体相对于其父对象的局部位置。如果物体没有父对象,则等同于 transform.position

    • Transform.localRotation:表示物体相对于其父对象的局部旋转。

    • Transform.localScale:表示物体相对于其父对象的局部缩放。

    • transform.forwardtransform.uptransform.right:这些便捷属性返回的是物体在世界坐标系下其局部 Z、Y、X 轴的方向向量。例如,transform.forward 就是物体当前面向的世界方向

1.2 世界坐标系 (World Space)

  • 概念: 整个 3D 场景的全局、固定参考系。它的原点通常位于 (0, 0, 0),X、Y、Z 轴指向固定方向。在 Unity 中,通常:

    • X 轴: 指向右方 (Red Axis)

    • Y 轴: 指向上方 (Green Axis)

    • Z 轴: 指向前方 (Blue Axis)

  • 特性: 世界坐标系是所有物体共享的“大地图”。所有物体最终都会被放置在世界坐标系中的某个位置和姿态。

  • Unity 中的体现:

    • Transform.position:表示物体在世界坐标系中的位置。

    • Transform.rotation:表示物体在世界坐标系中的旋转。

    • Transform.lossyScale:表示物体在世界坐标系中的最终缩放(包含了父级的缩放影响)。

1.3 父子关系与层级变换

在 Unity 中,游戏对象可以有父子关系。当一个对象成为另一个对象的子对象时,它的局部坐标系就变成了相对于其父对象的坐标系。子对象的任何变换都会受到父对象变换的影响。

  • 示例: 如果一个手臂是身体的子对象,当身体旋转时,手臂也会跟着旋转(因为手臂的局部坐标系随着身体的世界坐标系一起旋转了)。而手臂自身的局部旋转,则是相对于它当前所处的“父级空间”进行的。

  • Transform.SetParent() 方法可以用来建立和解除父子关系,这在运行时动态组合对象时非常有用,例如拾取武器或附件。


为什么要区分局部坐标系和世界坐标系?

理解这些坐标系的关键在于它们处理问题的方式:

  • 局部坐标系方便描述物体自身的属性(例如,我向前走,就是沿着我的局部 Z 轴),因为它不受外部环境变化的影响。

  • 世界坐标系方便描述物体在整个场景中的绝对位置和关系(例如,哪个物体离世界原点最近),因为它是一个统一的参考标准。

在游戏开发中,我们经常需要在两者之间进行转换。

1.4 屏幕坐标系 (Screen Space)

  • 概念: 你的游戏屏幕(或窗口)上的 2D 像素坐标系。

    • 原点通常在屏幕的左下角 (0, 0)

    • X 轴向右延伸,Y 轴向上延伸。

    • Z 轴通常表示深度,即点离摄像机的距离。

  • 特性: 像素单位,直接对应屏幕上的视觉呈现。

  • Unity 中的体现:

    • Input.mousePosition:鼠标在屏幕上的像素坐标。

    • Input.GetTouch(0).position:触控点在屏幕上的像素坐标。

    • UI Canvas 的 Screen Space - Overlay 模式下的 UI 元素位置。

1.5 视口坐标系 (Viewport Space)

  • 概念: 相机在渲染时看到的**“视口”**的 2D 归一化坐标系。

    • 原点在视口的左下角 (0, 0)

    • 右上角是 (1, 1)

    • X、Y 值范围是 0.01.0

    • Z 轴同样表示深度,即点离摄像机的距离。

  • 特性: 独立于屏幕分辨率。无论屏幕多大,视口左下角始终是 (0,0),右上角始终是 (1,1)。这对于判断物体是否在屏幕内非常有用。

  • Unity 中的体现:

    • Camera.WorldToViewportPoint():世界坐标转视口坐标。

    • Camera.ViewportToWorldPoint():视口坐标转世界坐标。

    • Camera.ViewportToScreenPoint():视口坐标转屏幕坐标。

1.6 其他重要但无需深究的坐标系

  • 摄像机空间 (Camera Space / View Space): 以摄像机自身为原点和轴向的 3D 坐标系。所有物体在渲染前都会被转换到这个空间。

  • 裁剪空间 (Clip Space): 在摄像机空间之后,点被投影到一个立方体(归一化设备坐标,NDC)中。这个空间用于剔除视锥体外的点。

  • 归一化设备坐标 (Normalized Device Coordinates - NDC): 经过裁剪空间后,所有可见点被映射到一个标准的立方体中,X, Y, Z 轴范围都是 [-1, 1]

这些更深层次的坐标系主要在图形渲染管线内部使用,作为开发者,通常只需要理解它们的存在和作用流程,而无需手动操作它们。了解它们能让你更好地理解 3D 世界最终如何映射到 2D 屏幕上。


2. 坐标系转换:在不同“视角”之间穿梭

在游戏开发中,我们经常需要在不同坐标系之间进行点的转换,例如将一个世界坐标的点转换为局部坐标,或者将鼠标的屏幕坐标转换为 3D 世界中的点击点。Unity 提供了方便的 API 来实现这些转换。

2.1 局部坐标系与世界坐标系之间的转换

这些方法都可以在任何 Transform 组件上调用。

  • Transform.TransformPoint(Vector3 position):局部点转世界点

    • 将一个在当前 Transform局部坐标系中定义的点 (position) 转换到世界坐标系中。

    • 应用: 计算角色前方 N 米处的世界坐标、计算子弹从枪口(作为局部点)射出的世界起始位置。

    C#

    // Unity
    // 假设你在物体 A 上,想知道物体 A 的局部坐标 (0, 0, 5) 在世界中的位置
    Vector3 localPoint = new Vector3(0, 0, 5); // 物体 A 前方 5 米处
    Vector3 worldPoint = transform.TransformPoint(localPoint);
    Debug.Log($"局部点 {localPoint} 在世界中是 {worldPoint}");
  • Transform.InverseTransformPoint(Vector3 position):世界点转局部点

    • 将一个在世界坐标系中定义的点 (position) 转换到当前 Transform局部坐标系中。

    • 应用: 判断一个世界中的点相对于物体的具体方位(例如,敌人相对于我在哪里)、计算局部碰撞点。

    C#

    // Unity
    // 假设你想知道世界坐标 (10, 0, 0) 相对于当前物体的位置
    Vector3 worldPoint = new Vector3(10, 0, 0);
    Vector3 localPoint = transform.InverseTransformPoint(worldPoint);
    Debug.Log($"世界点 {worldPoint} 相对于我是在 {localPoint}");
  • Transform.TransformDirection(Vector3 direction):局部方向转世界方向

    • 将一个在当前 Transform局部坐标系中定义的方向向量 (direction) 转换到世界坐标系中。

    • 重要: 这个方法只处理旋转,不考虑平移和缩放。它将局部方向向量的方向转换到世界空间,但不会改变其长度。

    • 应用: 获取物体当前的世界前方 (transform.TransformDirection(Vector3.forward) 等同于 transform.forward),获取物体自身某个方向在世界中的表示。

    C#

    // Unity
    // 获取当前物体局部右方在世界中的方向
    Vector3 localRight = Vector3.right;
    Vector3 worldRight = transform.TransformDirection(localRight);
    Debug.Log($"我的局部右方在世界中是 {worldRight}");
  • Transform.InverseTransformDirection(Vector3 direction):世界方向转局部方向

    • 将一个在世界坐标系中定义的向量 (direction) 转换到当前 Transform局部坐标系中。

    • 同样,只处理旋转,不考虑平移和缩放

    • 应用: 判断世界中的某个力或方向向量对于物体自身来说是哪个方向(例如,世界重力对于斜坡上的角色来说是哪个局部方向)。

    C#

    // Unity
    // 假设你想知道世界坐标的 Vector3.up (世界向上) 对于当前物体是哪个局部方向
    Vector3 worldUp = Vector3.up;
    Vector3 localUp = transform.InverseTransformDirection(worldUp);
    Debug.Log($"世界向上对于我来说是局部 {localUp}");
  • Transform.TransformVector(Vector3 vector)Transform.InverseTransformVector(Vector3 vector)

    • 这两个方法与 TransformDirection 类似,但它们会考虑缩放。当处理法线(需要逆转置矩阵)或非单位长度的向量时,需要特别注意。在大多数情况下,处理方向用 TransformDirection 即可,除非你明确需要考虑缩放对向量的影响。

2.2 世界坐标系与屏幕/视口坐标系之间的转换

这些方法通常在 Camera 组件上调用。

  • Camera.WorldToScreenPoint(Vector3 position):世界点转屏幕点

    • 将 3D 世界坐标系中的一个点 (position) 转换到 2D 屏幕坐标系中。返回的 Vector3xy 是像素坐标,z 是该点距离摄像机的深度。

    • 应用:

      • 将 3D 物体在屏幕上方的位置显示一个血条 UI。

      • 判断一个 3D 物体是否在屏幕内(检查 x, y 是否在 0Screen.width/Screen.height 之间,且 z > 0)。

    C#

    // Unity
    public Transform target3DObject;
    void Update() {Vector3 screenPos = Camera.main.WorldToScreenPoint(target3DObject.position);Debug.Log($"3D 物体 {target3DObject.name} 在屏幕上的位置是 {screenPos}");// 判断是否在屏幕内:if (screenPos.z > 0 && screenPos.x >= 0 && screenPos.x <= Screen.width && screenPos.y >= 0 && screenPos.y <= Screen.height) {Debug.Log("物体在屏幕内!");} else {Debug.Log("物体在屏幕外!");}
    }
  • Camera.ScreenToWorldPoint(Vector3 position):屏幕点转世界点

    • 将 2D 屏幕坐标系中的一个点 (position) 转换到 3D 世界坐标系中。

    • 关键: 由于 2D 屏幕点缺少深度信息,你必须手动为 position.z 赋值,才能确定它在 3D 空间中的深度。

    • 应用:

      • 点击屏幕获取 3D 世界中的一个点(例如,点击地面进行移动)。

      • 将 UI 元素的位置映射到 3D 空间中的特定深度。

    C#

    // Unity
    // 鼠标点击屏幕,获取点击处在世界中的位置
    void Update() {if (Input.GetMouseButtonDown(0)) {Vector3 mouseScreenPos = Input.mousePosition;// 必须提供 Z 深度信息!这里假设我们想在相机前方 10 米处获取世界点mouseScreenPos.z = 10f; // 这里的 z 是指离相机近裁剪面的距离Vector3 worldClickPoint = Camera.main.ScreenToWorldPoint(mouseScreenPos);Debug.Log($"鼠标点击屏幕 {Input.mousePosition} 对应世界点 {worldClickPoint}");}
    }

    注意: 如果你需要精确点击 3D 物体表面,通常会结合射线检测 (Raycasting) 来获取深度,这比固定 z 值更精确。我们会在第四篇详细讲解。

  • Camera.WorldToViewportPoint(Vector3 position):世界点转视口点

    • 将 3D 世界坐标系中的一个点 (position) 转换到 2D 视口坐标系中。返回的 Vector3xy 范围是 0.01.0z 是深度。

    • 应用:

      • 判断物体是否在屏幕内(通常比 WorldToScreenPoint 更方便,因为它不依赖 Screen.width/height)。

      • 创建位于屏幕相对位置的 UI 元素(例如,血条总在敌人上方,但不能超出屏幕)。

    C#

    // Unity
    public Transform targetObject;
    void Update() {Vector3 viewportPos = Camera.main.WorldToViewportPoint(targetObject.position);if (viewportPos.z > 0 && viewportPos.x >= 0 && viewportPos.x <= 1 && viewportPos.y >= 0 && viewportPos.y <= 1) {Debug.Log("物体在视口内!");} else {Debug.Log("物体在视口外!");}
    }
  • Camera.ViewportToWorldPoint(Vector3 position):视口点转世界点

    • 将 2D 视口坐标系中的一个点 (position) 转换到 3D 世界坐标系中。

    • 同样需要手动提供 position.z 深度。

    • 应用: 将一个位于屏幕中央(0.5, 0.5)的 UI 元素映射到 3D 世界中的某个深度。


3. 变换矩阵:空间转换的幕后英雄

在所有的坐标系转换背后,真正执行“数学魔法”的是变换矩阵 (Transformation Matrices)。虽然 Unity 为我们封装了大多数底层矩阵操作,但理解它们的存在和作用原理,能让你更深刻地理解 3D 图形学,并在遇到复杂问题时游刃有余。

3.1 什么是变换矩阵?

  • 概念: 在 3D 图形中,一个矩阵 (Matrix) 是一个矩形排列的数字集合。一个 4x4 的矩阵可以同时表示 3D 空间中的平移 (Translation)旋转 (Rotation)缩放 (Scaling) 这三种基本变换。

  • 矩阵乘法: 当一个 3D 点(表示为齐次坐标下的向量)与一个变换矩阵相乘时,就可以得到变换后的新点。

    • 例如,NewPoint = Matrix * OldPoint
  • 关键特性:不满足交换律! MatrixA * MatrixB 不等于 MatrixB * MatrixA。这意味着变换的顺序至关重要。先旋转再平移,和先平移再旋转,会得到完全不同的结果。这解释了为什么 Unity 中 Transform 组件的 positionrotation 操作是分开的,以及为什么父子变换的顺序会影响最终结果。

3.2 矩阵如何工作?(简要原理)

一个 4x4 的变换矩阵通常结构如下:

| Sx  0   0   Tx |
| 0   Sy  0   Ty |
| 0   0   Sz  Tz |
| 0   0   0   1  |
  • 其中 Sx, Sy, Sz 控制缩放

  • 矩阵左上角的 3x3 部分(包含 0 和对角线上的值)控制旋转

  • Tx, Ty, Tz 控制平移

当一个 3D 点 (x, y, z, 1)(这里的 1 是齐次坐标的约定)与这个矩阵相乘时,就能同时实现平移、旋转和缩放。

3.3 MVP 矩阵:3D 世界到 2D 屏幕的渲染管线

在 3D 渲染管线中,一个 3D 模型从其自身定义到最终呈现在屏幕上,会经历一系列的坐标系转换,这些转换都由特定的变换矩阵完成。这就是著名的 MVP 矩阵

  1. 模型矩阵 (Model Matrix / World Matrix):局部空间 -> 世界空间

    • 作用: 将 3D 模型在它自己的局部坐标系中定义的顶点,转换到世界坐标系中。

    • 每个物体都有一个模型矩阵,它由该物体的 Transform.positionTransform.rotationTransform.localScale 决定。

    • 例如,一个角色模型,它的模型矩阵决定了它在世界中的位置、方向和大小

  2. 视图矩阵 (View Matrix):世界空间 -> 摄像机空间

    • 作用:世界坐标系中的所有点,转换到摄像机(或观察者)的局部坐标系中。这相当于从摄像机的角度“看”世界。

    • 视图矩阵实际上是摄像机自身变换矩阵的逆矩阵

    • 它模拟了摄像机的位置和朝向

  3. 投影矩阵 (Projection Matrix):摄像机空间 -> 裁剪空间/NDC 空间

    • 作用:摄像机空间中的 3D 点,投影到 2D 屏幕上,并进行深度挤压和透视变换

    • 它定义了摄像机的视野 (Field of View - FOV)近裁剪面 (Near Clip Plane)远裁剪面 (Far Clip Plane)

    • 两种主要类型:

      • 透视投影 (Perspective Projection): 模拟人眼看世界的效果,远的物体小,近的物体大,有透视感。

      • 正交投影 (Orthographic Projection): 没有透视感,所有物体大小不变,常用于 2D 游戏、工程视图或特殊的 3D 效果。

    • 投影矩阵的输出通常是裁剪空间,然后通过除以 W 分量(透视除法)进入归一化设备坐标 (NDC) 空间,X、Y、Z 轴范围都是 [-1, 1]

渲染管线中的流程:

顶点数据 (局部坐标) -> 模型矩阵 -> 世界坐标 -> 视图矩阵 -> 摄像机空间 -> 投影矩阵 -> 裁剪空间 -> 透视除法 -> NDC 空间 -> 视口变换 -> 屏幕坐标 -> 最终渲染


为什么要理解 MVP 矩阵?

虽然 Unity 帮你处理了所有这些复杂的矩阵乘法,但了解 MVP 矩阵的工作原理,能让你:

  • 理解 3D 渲染的底层逻辑: 当你在 Shader 中处理顶点或像素时,你是在哪个坐标系下操作?这直接影响你的计算结果。

  • 调试渲染问题: 当物体显示不正确时,可能是哪个矩阵出了问题?

  • 实现自定义渲染效果: 如果你需要编写自定义的渲染管道或着色器,对 MVP 矩阵的理解是必不可少的。


4. 坐标系与变换矩阵在 Unity 中的高级应用

理解坐标系和矩阵的工作方式后,我们可以解决一些实际的游戏开发问题。

4.1 鼠标点击精确拾取 3D 物体(结合射线)

这是最常见的应用之一。鼠标点击的 2D 屏幕点,如何找到它在 3D 世界中击中的物体?

C#

// Unity
void Update() {if (Input.GetMouseButtonDown(0)) {// 1. 将鼠标的屏幕坐标转换为一条射线// Camera.main.ScreenPointToRay() 会根据相机位置和方向,从屏幕点发射一条射线Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);// 2. 声明一个 RaycastHit 结构体来存储射线检测结果RaycastHit hit;// 3. 执行射线检测// Physics.Raycast 会沿着射线方向检测碰撞体if (Physics.Raycast(ray, out hit, 100f)) { // 100f 是射线的最大检测距离Debug.Log($"鼠标点击了物体: {hit.collider.gameObject.name},在世界坐标: {hit.point}");// 你可以对 hit.collider.gameObject 进行操作,例如选中、高亮} else {Debug.Log("没有点击到任何 3D 物体。");}}
}

这里的核心就是将 2D 的屏幕坐标,通过摄像机的投影信息反推回 3D 世界中的一条射线

4.2 UI 元素跟随 3D 物体(血条、名称板)

让一个 UI 元素(例如角色的血条或名称板)始终位于其对应的 3D 角色上方。

C#

// Unity
public Transform target3DCharacter; // 要跟随的 3D 角色
public RectTransform uiElementRectTransform; // 要跟随的 UI 元素的 RectTransformvoid Update() {if (target3DCharacter == null || uiElementRectTransform == null || Camera.main == null) return;// 1. 将 3D 角色头顶的世界坐标转换为屏幕坐标// 假设血条在角色头顶上方 2 个单位处Vector3 worldPositionAboveCharacter = target3DCharacter.position + Vector3.up * 2f;Vector3 screenPosition = Camera.main.WorldToScreenPoint(worldPositionAboveCharacter);// 2. 判断物体是否在摄像机前方且在屏幕内(防止血条显示在屏幕外或背后)if (screenPosition.z > 0 &&screenPosition.x >= 0 && screenPosition.x <= Screen.width &&screenPosition.y >= 0 && screenPosition.y <= Screen.height) {uiElementRectTransform.gameObject.SetActive(true); // 显示 UI 元素// 3. 将屏幕坐标转换为 UI Canvas 的 RectTransform 坐标// UI 坐标通常是相对于 Canvas 的,需要特殊处理Vector2 localUIPos;RectTransformUtility.ScreenPointToLocalPointInRectangle(uiElementRectTransform.parent as RectTransform, // UI 元素的父级 Canvas RectTransformscreenPosition,Camera.main.WorldToScreenPoint(Camera.main.transform.position).z, // 假设 Z 深度相同out localUIPos);// 如果 Canvas 是 Screen Space - Camera 模式,第三个参数是 Camera.main// 如果 Canvas 是 Screen Space - Overlay 模式,第三个参数是 null// 鉴于目前是 Screen Space - Overlay,直接使用 screenPosition 即可// 或者更简单的,直接赋值,Unity UI 系统会处理好:uiElementRectTransform.position = screenPosition;} else {uiElementRectTransform.gameObject.SetActive(false); // 隐藏 UI 元素}
}

注意: 对于 Unity UI,RectTransformUtility.ScreenPointToLocalPointInRectangle 通常用于将屏幕点转换为 Canvas 内部的局部坐标,这取决于你的 Canvas 渲染模式(Screen Space - OverlayScreen Space - CameraWorld Space)。这里为了简化,如果 Canvas 是 Screen Space - Overlay 模式,直接将 uiElementRectTransform.position = screenPosition; 即可,Unity 会处理其与屏幕坐标的映射。

4.3 相机边界限制

限制相机只能在特定区域内移动,或者当玩家靠近屏幕边缘时,相机自动平移。

C#

// Unity
public Transform player;
public float edgeOffset = 0.1f; // 屏幕边缘触发区域 (0-1 范围)
public float cameraMoveSpeed = 5f;void Update() {// 1. 将玩家位置转换为视口坐标Vector3 viewportPos = Camera.main.WorldToViewportPoint(player.position);Vector3 cameraMoveDirection = Vector3.zero;// 2. 检查玩家是否接近视口边缘if (viewportPos.x < edgeOffset) {cameraMoveDirection += Vector3.left;} else if (viewportPos.x > 1f - edgeOffset) {cameraMoveDirection += Vector3.right;}if (viewportPos.y < edgeOffset) {cameraMoveDirection += Vector3.down;} else if (viewportPos.y > 1f - edgeOffset) {cameraMoveDirection += Vector3.up;}// 3. 移动相机Camera.main.transform.position += cameraMoveDirection.normalized * cameraMoveSpeed * Time.deltaTime;
}

这里利用视口坐标系的归一化特性,方便地判断玩家相对于屏幕边缘的位置。


5. 常见面试题与深入思考

5.1 面试问答

  1. 问:请解释局部坐标系和世界坐标系的区别。在 Unity 中,当物体存在父子关系时,transform.positiontransform.localPosition 有何不同?

    • 解析:

      • 局部坐标系: 物体自身的坐标系,原点在物体轴心,轴向与物体自身方向一致。描述物体自身的几何数据。

      • 世界坐标系: 整个场景的全局、固定坐标系,原点在 (0,0,0),轴向固定。描述物体在整个世界中的绝对位置。

      • transform.position 表示物体在世界坐标系中的绝对位置。

      • transform.localPosition 表示物体在父对象局部坐标系中的相对位置。如果物体没有父对象,则 localPosition 等同于 position。当父对象移动或旋转时,子对象的 localPosition 不变,但其 position 会随父对象而改变。

  2. 问:如何在 Unity 中将一个世界坐标的点转换到某个物体的局部坐标系?请举例说明应用场景。

    • 考察点: InverseTransformPoint 的使用及其应用。

    • 解析: 使用 transform.InverseTransformPoint(worldPoint) 方法。

      • 应用场景:

        • 判断一个世界中的目标点相对于当前物体的方位。例如,一个 AI 想要知道玩家在它自身的左侧还是右侧、前方还是后方,就需要将玩家的世界位置转换为 AI 的局部坐标,然后判断 X、Z 分量的正负。

        • 获取一个物体被击中时,局部碰撞点在哪里,这在制作特效(例如粒子效果从特定部位发出)或计算局部伤害时很有用。

  3. 问:请简要描述 MVP 矩阵在 3D 渲染管线中的作用。它们分别负责什么转换?

    • 考察点: 对 3D 图形渲染基础流程的理解,矩阵的抽象作用。

    • 解析:

      • MVP 矩阵是 3D 世界中的点最终如何被渲染到 2D 屏幕上的关键。

      • 模型矩阵 (Model Matrix): 将模型自身的局部坐标转换为世界坐标。它决定了物体在世界中的位置、旋转和缩放

      • 视图矩阵 (View Matrix):世界坐标转换为摄像机(观察者)的局部坐标。它模拟了摄像机的位置和朝向

      • 投影矩阵 (Projection Matrix):摄像机空间中的 3D 点投影到 2D 屏幕(归一化设备坐标),并进行透视变换和裁剪。它定义了摄像机的视野 (FOV)、近远裁剪面,决定了最终画面的透视感或正交感。

    • 总结: 模型矩阵定位物体;视图矩阵选择观察视角;投影矩阵定义如何将 3D 世界映射到 2D 屏幕。

  4. 问:如何在 Unity 中让一个 UI 元素(例如血条)始终跟随一个 3D 角色显示在它的头顶?你会用到哪些坐标系转换?

    • 考察点: 综合运用 WorldToScreenPoint 和 UI 坐标系转换的理解。

    • 解析:

      1. 首先,获取 3D 角色头顶的世界坐标

      2. 使用 Camera.main.WorldToScreenPoint() 将这个世界坐标转换为屏幕坐标(像素坐标)。

      3. 然后,将这个屏幕坐标赋值给 UI 元素的 RectTransform.position

      4. 额外考虑: 需要判断 WorldToScreenPoint 返回的 z 值是否大于 0(在摄像机前方),以及 x, y 是否在屏幕范围内,以决定是否显示 UI 元素,避免显示在屏幕外或角色背后。对于不同 Canvas 渲染模式下的 UI 定位,可能还需要额外的 RectTransformUtility 转换。


总结与展望

本篇教程深入探讨了 3D 游戏开发中至关重要的坐标系变换矩阵

  • 我们详细区分了局部坐标系、世界坐标系、屏幕坐标系和视口坐标系,理解了它们各自的用途。

  • 掌握了 Unity 中局部与世界世界与屏幕/视口之间进行转换的各种 API,让你能够灵活处理位置和方向的转换。

  • 揭示了变换矩阵的底层原理,包括其表示平移、旋转、缩放的能力,以及不满足交换律的重要性。

  • 深入理解了 MVP 矩阵 (模型、视图、投影矩阵) 在 3D 渲染管线中的核心作用,让你对 3D 画面如何呈现在屏幕上有了更清晰的认识。

对坐标系和变换的理解,是你在 Unity 中构建复杂层级结构、实现相机逻辑、处理 UI 交互以及深入图形渲染的基石。

在下一篇《射线与碰撞检测(交互基础篇)》中,我们将结合你已经掌握的向量、旋转、坐标系知识,深入学习如何在 3D 世界中进行精确的交互检测,例如鼠标点击拾取、子弹命中判断以及各种物理碰撞。

现在,你对坐标系和变换矩阵的概念是否已经更加清晰了呢?在 Unity 开发中,你是否曾遇到过因坐标系混淆而导致的问题?

Unity3D数学第一篇:向量与点、线、面(基础篇)

Unity3D数学第二篇:旋转与欧拉角、四元数(核心变换篇)

Unity3D数学第三篇:坐标系与变换矩阵(空间转换篇)

Unity3D数学第四篇:射线与碰撞检测(交互基础篇)

Unity3D数学第五篇:几何计算与常用算法(实用算法篇)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/93930.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/93930.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/93930.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UV安装并设置国内源

文章目录一、UV下载1.官方一键安装2.github下载安装二、更换国内镜像源&#xff08;加速下载&#xff09;方法1&#xff1a;临时环境变量&#xff08;单次生效&#xff09;方法2&#xff1a;永久配置&#xff08;推荐&#xff09;方法3&#xff1a;命令行直接指定源三、验证镜像…

1 前言:什么是 CICD 为什么要学 CICD

什么是 CI/CD 我的资源库网站&#xff1a;https://www.byteooo.cn 在开发阶段&#xff0c;许多编译工具会将我们的源码编译可使用的文件。例如 vue-cli 的项目会被 webpack 打包编译为浏览器的文件&#xff0c;Java 项目会被编译为 .class/jar 文件以供服务器使用。 但是&am…

GitHub 趋势日报 (2025年07月30日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图3579copyparty752supervision664500-AI-Agents-Projects483awesome403prompt-optim…

“非参数化”大语言模型与RAG的关系?

这个问题触及了一个关键的技术细节&#xff0c;两者关系密切&#xff0c;但层面不同&#xff1a; “非参数化”大语言模型是一个更广泛的概念或类别&#xff0c;而RAG&#xff08;Retrieval-Augmented Generation&#xff09;是实现这一概念最主流、最具体的一种技术框架。 您可…

LeetCode Hot 100:15. 三数之和

题目给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。注意&#xff1a;答案中不可以包含重复的三元组。示例 1&…

银行回单识别应用场景剖析

银行回单OCR识别技术通过自动化处理纸质或电子回单中的关键信息&#xff0c;显著提升了金融、企业及个人场景下的数据管理效率。以下是其核心应用场景及价值的详细剖析&#xff1a;一、企业财务场景自动化账务处理对账与记账&#xff1a;OCR自动提取交易日期、金额、账号等信息…

React的介绍和特点

1. React是什么&#xff1f; 1.1. React&#xff1a; 用于构建用户界面的JavaScript库1.2. React的官网文档&#xff1a;https://zh-hans.reactjs.org/ 2. React的特点2.1. 声明式编程&#xff1a; 目前整个大前端开发的模式&#xff1a;Vue、React、Flutter、SwiftUI只需要维护…

内核smmu学习

思考 smmu对外提供功能&#xff0c;设备驱动调用smmu 提供的api来配置页表&#xff0c;那其他设备是如何和smmu交互的&#xff1f;iommu 作为将不同smmu硬件的一个抽象封装&#xff0c;其它设备应该只能看到iommu这个封装层&#xff0c;那么iommu这个子系统是如何进行抽象的&a…

Android Slices:让应用功能在系统级交互中触手可及

引言 在当今移动应用生态中&#xff0c;用户每天要面对数十个甚至上百个应用的选择&#xff0c;如何让自己的应用在关键时刻触达用户&#xff0c;成为开发者面临的重要挑战。Google在Android 9 Pie中引入的Slices技术&#xff0c;正是为了解决这一痛点而生。本文将全面介绍And…

python学智能算法(三十))|SVM-KKT条件的数学理解

【1】引言 前序学习进程中&#xff0c;通过类比力的平衡对KKT条件进行了初步的理解。 今天我们更进一步&#xff0c;常使用数学语言进一步解释KKT条件。 【2】带约束的最小优化问题 首先定义一个即将求解的优化问题&#xff1a; 目标函数&#xff1a;最小化f(x)(x∈Rn)f(x)(…

华为云Flexus+DeepSeek征文|Linux命令实现两种部署的性能捕获+(硅基+Maas)模型添加教学

前引&#xff1a;“在数字化浪潮汹涌澎湃的今天&#xff0c;企业对云计算服务的需求已从基础架构支撑&#xff0c;逐步转向更深层次的AI赋能与业务创新驱动。面对复杂多变的市场环境&#xff0c;选择一个强大、可靠且具备前瞻性的云服务伙伴&#xff0c;无疑是企业实现高速增长…

langchain--1--prompt、output格式、LCEL示例

环境&#xff1a;本地使用ollama部署的deepseek-r1:1.5b模型 本文示例包含: [1] 非LCEL的调用方法[2] LCEL的调用方法[3] prompt template的简单使用&#xff0c;除了PromptTemplate模板&#xff0c;还有一些其它模板&#xff0c;可去查看官网[4] 输出&#xff1a;json格式、py…

【算法】指数滑动滤波器

指数滑动滤波器作用原理特点公式代码优化升级作用 首先这个滤波器能够将一些突变的信号对系统的影响降低&#xff0c;能够平滑输入信号&#xff0c;滤除噪声&#xff0c;减少测量数据的瞬间波动和干扰&#xff0c;就是实现输入信号不能不变&#xff0c;数值不会突然变大&#…

STM32F4—电源管理器

Power supply schemesPower supply supervisorInternal reset ON有PDR_ON pin的MCU&#xff0c;PDR_ON pin被拉高的时候电源监视器被使能。没有PDR_ON pin的MCU默认一直使能。内部集成了power-on reset (POR) / power-down reset (PDR)POR&#xff08;上电复位&#xff09;&…

MySQL锁的分类 MVCC和S/X锁的互补关系

各位看官&#xff0c;大家早安午安晚安呀~~~如果您觉得这篇文章对您有帮助的话欢迎您一键三连&#xff0c;小编尽全力做到更好 欢迎您分享给更多人哦今天我们来学习&#xff1a;MySQL锁的分类 && MVCC和S/X锁的互补关系1.锁分类1.按锁粒度分类&#xff1a;全局锁&#…

第五届智能通信与计算国际学术会议(ICICC 2025)

重要信息 官网&#xff1a;www.ic-icc.org 时间&#xff1a;2025年8月15-16日 地点&#xff1a;中国 南京 第五届智能通信与计算国际学术会议(ICICC 2025&#xff09;定于2025年8月15-16日在中国 南京举行。随着信息技术的飞速发展&#xff0c;智能通信与计算领域的研究与…

基于C#和NModbus4库实现的Modbus RTU串口通信

基于C#和NModbus4库实现的Modbus RTU串口通信&#xff0c;包含完整的界面设计和功能实现&#xff1a;一、项目依赖配置NuGet包安装&#xff1a; Install-Package NModbus4 Install-Package System.IO.Ports窗体控件布局&#xff1a; <!-- 基础控件配置 --> <ComboBox …

想要批量提取视频背景音乐?FFmpeg 和转换器都安排上

你是否遇到过这样的情况&#xff1f;看到一个超赞的短视频&#xff0c;里面的背景音乐特别好听&#xff0c;想单独保存下来当手机铃声或收藏&#xff0c;却不知道怎么把音乐从视频里“抠”出来&#xff1f;别担心&#xff01;今天就为大家分享两种简单易行的方法&#xff0c;无…

为什么MCP协议是AI集成的未来API

一、企业AI应用的核心挑战与架构演进 当前企业AI落地面临三大核心痛点&#xff1a; ​​系统集成困境​​&#xff1a;需对接企业内部业务系统&#xff08;CRM/ERP等&#xff09;​​异构环境兼容​​&#xff1a;需整合第三方AI服务与传统API​​数据孤岛突破​​&#xff1…

Apache Tomcat样例目录session操纵漏洞解读

【漏洞名称】&#xff1a;Apache Tomcat样例目录session操纵漏洞 &#xff08;Apache Tomcat示例目录漏洞&#xff09;【漏洞等级】&#xff1a;中危&#xff0c;5.9分。【漏洞描述】Apache Tomcat默认安装页面中存在examples样例目录&#xff0c;里面存放着Servlets、JSP、Web…