news 2026/4/22 4:29:38

游戏坐标变换:平移、旋转、缩放全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
游戏坐标变换:平移、旋转、缩放全解析

文章摘要

坐标变换=在不同“参考系”里看同一个点/物体。
具体干的三件事:

  • 平移:整体挪个位置;
  • 旋转:整体转个角度;
  • 缩放:整体放大缩小。

在数学里,这是解析几何 + 线性代数的核心;
在游戏里(Unity / UE / 自研引擎),
你看到的一切移动、转身、镜头、骨骼动画、相机跟随,
背后都是无数次“坐标变换”的组合。

下面我用大白话 + 具体游戏例子,把这件事从直觉讲到公式,再讲到代码和实际用法。


一、先弄清楚:为啥要“坐标变换”?

1.1 同一个东西,在不同“参考系”里,坐标是不一样的

想象一个简单场景:

  • 你站在房间中间;
  • 房间在地图上的位置也有个坐标;
  • 摄像机在天花板上看你;
  • 小地图也在俯视整个房间。

问题来了:
“你这个人”,到底坐标是多少?

要看是谁在说:

  • 以“整个地图”为参考:
    • 你的位置是“世界坐标”:例如 (100, 0, 50);
  • 以“房间”为参考:
    • 你的位置也可以写成“相对于这个房间”的局部坐标:例如 (3, 0, 2);
  • 以“你自己”为参考:
    • 你的手、脚的位置,是“相对于你的身体”的局部坐标,比如手在 (0.5, 1.2, 0)。

同一个点在不同坐标系下的坐标值是不一样的。
坐标变换干的,就是在这些坐标系之间“翻译”

1.2 游戏里的典型场景:父子节点 + 世界坐标

在 Unity 里:

  • 一个 GameObject 有 transform:
    • localPosition / localRotation / localScale(相对父物体);
    • position / rotation / lossyScale(世界坐标下)。

你经常会做的事:

  • 把一个武器挂在角色手上(武器坐标相对手骨骼);
  • 再把角色放到世界任意一个位置(角色坐标相对世界);
  • 角色再旋转、移动,武器会自然跟着走、跟着转;

这背后就是父子层级的坐标变换

  • 子物体坐标 = 在父坐标系下的局部坐标;
  • 要渲染、做物理时,必须把这些局部坐标转换成世界坐标。

二、三大基本操作:平移、旋转、缩放,用生活话说一遍

2.1 平移:整体搬家

平移 = 整体挪个位置,不改变方向和大小。

类比一下:

  • 你把一张画从桌子上拿到地上;
  • 画上的所有点的位置都变了,但图案形状没变。

数学上:

  • 原点 P=(x, y, z);
  • 平移向量 T=(tx, ty, tz);
  • 平移后的点 P’ = P + T。

Unity 里:

transform.position+=newVector3(1,0,0);// 向世界 x 方向平移 1

这就是一次最直观的坐标变换:
加一个向量

2.2 旋转:绕某个点/轴转一圈

旋转 = 改变方向,但不改变长度。

生活里:

  • 你手里拿着一支笔,笔尖在空中画圆;
  • 你转动手机,屏幕画面旋转 90°;
  • 你开车转弯,从面朝北变成面朝东。

数学上:

  • 在 2D:绕原点旋转 θ,
    点 P(x, y) 变成 P’(x’, y’):

    x' = x cosθ - y sinθ y' = x sinθ + y cosθ

    这可以写成矩阵乘法(后面讲矩阵会说,但你现在只要知道“旋转就是变换公式”)。

  • 在 3D:绕 x/y/z 轴旋转,有对应的 3×3 矩阵,或者用四元数。

Unity 里你写:

transform.Rotate(0,90,0);

就是在把物体绕 y 轴旋转 90 度。

2.3 缩放:放大 / 缩小

缩放 = 改变大小,不改变方向(如果缩放比例为正)。

  • 点 P(x, y, z);
  • 缩放比例 S=(sx, sy, sz);
  • 缩放后 P’=(sx * x, sy * y, sz * z)。

如果 sx=sy=sz,这叫“等比缩放”,物体不会变形,只是整体变大/变小。

Unity 里:

transform.localScale=newVector3(2,2,2);// 放大 2 倍

这会让物体在三个轴上都放大两倍。


三、从点的视角看:坐标怎么一步步被“变换”?

想象有一个点 P,它经历了这几件事:

  1. 在原点附近画出来;
  2. 整体往右挪了 3 米(平移);
  3. 绕原点旋转了 90 度(旋转);
  4. 再整体放大 2 倍(缩放)。

每动一次,它的坐标就会变一次:

  • 原始:P0(x, y);
  • 平移后:P1 = P0 + T;
  • 旋转后:P2 = R * P1;
  • 缩放后:P3 = S * P2。

坐标变换 = 对坐标做一系列算术操作:加、乘矩阵、乘比例。


四、再具体一点:用矩阵把平移+旋转+缩放统一管理(略带点线性代数)

不用矩阵也能理解坐标变换,但在游戏/图形这行,你迟早要面对矩阵。
我用最少的数学,把这件事说清楚。

4.1 为什么要矩阵?——因为变换多了,手动算会疯

你可以这样想:

  • 平移:P’ = P + T;
  • 旋转:P’ = R * P;
  • 缩放:P’ = S * P;

问题来了:

  • 如果你对一个点先缩放,再旋转,再平移,怎么写?
  • 如果场景里有 10 个祖孙层级物体,每层都有自己的平移、旋转、缩放,你要怎么把最里层点的最终世界坐标算出来?

手动一层层代入,会很噩梦。
矩阵的作用就是:

把“平移+旋转+缩放”这些操作统一写成一个 4×4 矩阵 M,
点用“齐次坐标”写成 4×1 列向量,
这样所有变换都可以写成:
P’ = M * P。

多次变换叠加,就是多个矩阵相乘:
M_total = M3 * M2 * M1。

Unity 中transform.localToWorldMatrix就是一个典型的 4×4 变换矩阵。

4.2 不用死记矩阵形式,只要知道:矩阵=“打包变换”

你现在不需要把每个矩阵的元素背下来,只要记住一句关键话:

在图形/游戏世界里:
一个“4×4 变换矩阵”通常就是:
“先缩放、再旋转、再平移”的打包结果。

因此,只要你有了一个 transform(里边有 position/rotation/scale),
引擎就能帮你生成一个矩阵 M:

  • 把任何子点的“局部坐标”乘上这个矩阵 M,就能得到“世界坐标”。

通俗点说:

矩阵 = 一个物体“从自己空间到世界空间”的翻译官。


五、游戏案例 1:角色移动——本地坐标 vs 世界坐标

5.1 问题:按 W 键,角色到底往哪走?

在第三人称 / FPS 游戏里:

  • 你按 W 键,角色“向前走”;
  • 如果角色没转身,“前”是世界的某个方向;
  • 如果角色已经转向了,“前”是角色面朝的方向,而不是世界的 Z 轴。

这里就涉及一个核心概念:

“前”是哪个方向?
要以谁为参考?

5.2 以世界为参考:简单粗暴的移动

最简单的写法:

// 世界坐标系下,向 z 轴正方向移动transform.position+=newVector3(0,0,1)*speed*Time.deltaTime;

这表示:

  • 不管你角色面朝哪,只要按 W,就朝世界 z 正方向走。
  • 适合“固定摄像机”或者“顶视 RTS”类游戏,但不适合“角色跟随摄像机转身”的 3D 动作游戏。

5.3 以角色自己为参考:本地坐标移动

大多数 3D 动作/FPS,需要的是:

角色按 W,一直朝自己的“前方”移动。

在 Unity 里:

  • transform.forward:表示角色在世界坐标系中的“前方方向”(一个单位向量)。

所以移动写成:

transform.position+=transform.forward*speed*Time.deltaTime;

这里,transform.forward是一个典型的“坐标变换”结果:

  • 在角色自己的局部坐标里,“前”是 (0, 0, 1);
  • 通过角色的旋转矩阵,把 (0, 0, 1) 转换到世界坐标系中,就得到了一个新的向量transform.forward
  • 再用它来移动,就相当于:在世界空间里沿着“角色的前方方向”移动。

你可以这样理解:

“局部方向”+“旋转变换” → “世界方向”;
这是最核心的方向坐标变换。


六、游戏案例 2:武器绑定手上——父子坐标变换

6.1 需求:手动一摆,武器跟着走

在角色身上挂武器,常见做法:

  • 在角色的骨骼上,有一个“Hand_R”骨骼节点;
  • 武器作为 Hand_R 的子物体;
  • 设置武器的localPositionlocalRotation来调整握持姿势;
  • 之后角色播放动画时,骨骼变换会带动武器一起动。

6.2 数学视角:局部坐标 + 父矩阵 = 世界坐标

设:

  • 武器在手坐标系中的局部坐标(位置和旋转) = Pw_local;
  • 手骨骼的世界变换矩阵 = M_hand;
  • 武器自身的局部变换矩阵 = M_weapon_local;
  • 武器的世界矩阵 = M_weapon_world;

则:

M_weapon_world = M_hand * M_weapon_local

再换成点的视角:

P_weapon_world = M_hand * P_weapon_local

理解成日常话就是:

“武器在手心这里相对偏一点点(局部),
再加上手整体在世界的位置和旋转,
就能算出武器到底在世界什么位置、朝向哪里。”

Unity 里你几乎不用管这些矩阵细节,只要:

weapon.transform.parent=handTransform;weapon.transform.localPosition=offsetPosition;weapon.transform.localRotation=offsetRotation;

之后所有坐标变换会自动完成。


七、游戏案例 3:摄像机跟随与绕点旋转

7.1 摄像机跟着角色走:平移 + 旋转的组合

典型的第三人称视角:

  • 摄像机永远在角色后上方一段距离;
  • 角色前进,摄像机跟着平移;
  • 鼠标左右移动,摄像机绕角色旋转(角色也可跟着转身)。

设定:

  • 角色位置:P;
  • 角色朝向方向:forward;
  • 摄像机相对角色的“局部偏移”:
    • 比如在角色背后 5 米,上方 3 米。
    • 可以在角色坐标系中写成 offset_local = (0, 3, -5)。

真正的相机位置要在世界坐标系里算:

// 把局部偏移变换到世界空间Vector3offset_world=characterTransform.TransformDirection(offset_local);// 或更严格:TransformPoint,把原点也平移进来camera.position=characterTransform.position+offset_world;

这里用到的 Unity 函数:

  • TransformDirection(vec):把一个“局部方向向量”变换到世界方向(只考虑旋转和缩放,不加平移);
  • TransformPoint(point):把局部坐标点变换到世界坐标(包括平移)。

你可以理解为:

offset_local 是“在角色自己的轴里,摄像机该在哪”;
TransformDirection/TransformPoint 做了一次“从角色空间到世界空间”的坐标变换;
得到真正的世界坐标位置。

7.2 绕角色旋转相机:以角色为中心旋转坐标系

鼠标左右移动时,你希望相机绕角色转,而不是角色绕相机转。

简化版逻辑:

  1. 记录一个“相机相对角色的球坐标”(极坐标):

    • 距离 r;
    • 水平角 yaw;
    • 俯仰角 pitch;
  2. 鼠标左右动修改 yaw,鼠标上下动修改 pitch;

  3. 再把 (r, yaw, pitch) 转回 3D 直角坐标(就是一个坐标变换),得到 offset_local;

  4. 再像刚才那样,把 offset_local 转成世界坐标。

这个过程,本质就是:

我们用了一种更适合描述“绕着一个点转圈”的坐标系(极坐标/球坐标),
再把它转换回直角坐标系,用来画图、渲染。


八、游戏案例 4:缩放——角色变大变小、UI 自适应、攻击判定

缩放看起来简单,但实战用途挺多。

8.1 Boss 变大:整体缩放模型

有些游戏里,Boss 激怒后会突然变大:

boss.transform.localScale=newVector3(2,2,2);// 放大 2 倍

效果:

  • 模型坐标系里的所有点,都乘以 2;
  • 所有子物体、武器、挂在身上的特效,也跟着放大。

有几点需要注意:

  • 碰撞体(Collider)是否同步缩放?

    • Unity 大部分 Collider 会受 localScale 影响(Box、Sphere 等),
      但有时需要手动调整参数以保证准确。
  • 攻击范围 / 判定圆 / 触发器是否同步放大?

    • 常常在代码里根据 scale 调整半径:

      floatscaledRadius=baseRadius*transform.lossyScale.x;// 假设等比缩放

8.2 UI 缩放:屏幕分辨率变了,UI 如何适配?

UI 系统里,坐标一般在“屏幕空间”坐标系下工作:

  • 屏幕宽度从 1920 变 2560;
  • UI 元素的 anchor / pivot 决定它如何缩放、对齐;
  • RectTransform 的坐标变换里,也隐含着平移+缩放。

比如一个血条在屏幕左上角:

  • 可用相对屏幕宽高的比例来确定它的位置;
  • 当分辨率变化时,通过 Canvas Scaler + RectTransform 自动做缩放和平移的坐标变换,让它保持在视觉上的“同一位置”。

本质还是:

“屏幕像素坐标系”和“UI 布局坐标系”之间的变换。


九、父子层级里的“坐标变换链”:骨骼动画的本质

再稍微往进阶一点,这个思想在骨骼动画里体现得淋漓尽致。

9.1 每块骨骼都有自己的局部变换

一个角色骨骼层级大致是:

  • Root
    • Spine
      • Shoulder
        • Arm
          • Forearm
            • Hand
              • Weapon

每个骨骼都有:

  • localPosition(相对父骨骼);
  • localRotation;
  • localScale。

当你播放一段跑步动画时:

  • 动画系统在每一帧更新每块骨骼的局部变换;
  • 然后从 Root 开始,一层层做“局部→父→世界”的矩阵乘法;
  • 得到每块骨骼在世界坐标系下的最终变换;
  • 再驱动蒙皮网格(SkinMesh)里的每个顶点做相应的坐标变换。

这是一条典型的“坐标变换链”:

P_world = M_root * M_spine * M_shoulder * M_arm * M_forearm * M_hand * P_local

你不需要在代码里手写这堆运算,引擎会帮你做完;
但理解这件事有助于你:

  • 调试骨骼问题;
  • 做一些 IK(反向动力学)效果(比如脚贴地);
  • 实现攻击判定(通过骨骼位置计算武器路径)。

十、再往“数学一点”:组合变换顺序很重要

平移 + 旋转 + 缩放的组合,有一个非常关键的坑:

变换顺序不一样,结果会不一样。

简单举个 2D 例子:

  • 先平移再旋转 VS 先旋转再平移。

10.1 先平移再旋转:绕世界原点转圈

假设点 P0=(1,0),操作:

  1. 平移 T=(1,0) → P1 = (2,0);
  2. 再绕原点旋转 90° → P2 = (0,2)。

画出来你会发现:
这个点是在“先从右边往外挪一点,再绕原点转”的。

视觉效果:
绕世界原点旋转。

10.2 先旋转再平移:绕自身局部原点平移

同样起点 P0=(1,0),操作:

  1. 先绕原点旋转 90° → P1=(0,1);
  2. 再平移 T=(1,0) → P2=(1,1)。

视觉效果:
先把形状转好,再整体平移。

这两个结果不同。
在矩阵里表现为:

  • M_total = T * R ≠ R * T。

在游戏中,这也极其常见:

  • 有时候你想“绕物体自身中心旋转再移动”;
  • 有时候你想“先移动到某个位置,再绕世界原点旋转”。

理解顺序的重要性,能帮你避免很多“相机绕圈绕错中心”“物体旋转古怪”的 BUG。


十一、把整篇压成一张“坐标变换小抄”

最后,用一张“脑内小抄”的形式,把关键点帮你捋一下。以后做游戏/看代码/学数学,都能快速想起来。

11.1 概念层面

  1. 坐标系 = 给点编号码的规则:

    • 世界坐标系:整个场景的统一参考系;
    • 局部坐标系:某个物体/骨骼自己的参考系。
  2. 坐标变换 = 在不同坐标系之间翻译:

    • 局部 → 世界;
    • 世界 → 摄像机;
    • 屏幕 → UI;
    • 等等。
  3. 三大基本操作:

    • 平移:加一个向量(位置变化);
    • 旋转:乘一个旋转矩阵/四元数(方向变化);
    • 缩放:乘一个缩放矩阵(大小变化)。

11.2 数学/实现层面

  • 平移:

    P' = P + T
  • 旋转(2D 例子):

    x' = x cosθ - y sinθ y' = x sinθ + y cosθ
  • 缩放:

    P' = (sx * x, sy * y, sz * z)
  • 组合变换:

    • 用 4×4 矩阵一次性打包;
    • 多层变换通过矩阵相乘叠加;
    • 顺序很重要:M_total = M3 * M2 * M1。

11.3 游戏应用层

  • 角色移动:

    • 世界方向移动:直接加(0,0,1)
    • 角色“前方向”移动:加transform.forward
  • 武器绑定手上:

    • 武器的 localPosition/localRotation 相对于手骨骼;
    • 手骨骼变换再通过矩阵链传到世界。
  • 摄像机跟随 / 绕角色旋转:

    • 使用“局部偏移 + 坐标变换”得出世界位置。
  • 缩放:

    • Boss 变大、技能范围变大;
    • UI 自适应屏幕;
    • 碰撞范围依据 scale 调整。
  • 骨骼动画、IK:

    • 一连串父子变换链;
    • 每帧把局部变换算到世界空间。

十二、一句真正能记住的话收尾

把这篇东西浓缩到一句最大白话里:

所谓“坐标变换:平移 + 旋转 + 缩放”,
就是告诉你:
同一个点/物体,在不同“参考系”下坐标不一样,
我们用平移、旋转、缩放的组合,
把这些坐标在各种坐标系之间来回“翻译”。

数学上,这是解析几何 + 矩阵运算;
游戏里,它就是:

  • 角色能走能转;
  • 武器能跟着手一起挥;
  • 摄像机能跟着你转圈;
  • UI 能适配不同分辨率;
  • 骨骼动画能让模型活起来。

当你下次写出:

transform.position+=transform.forward*speed*Time.deltaTime;weapon.parent=hand;camera.position=character.position+character.TransformDirection(offset);

可以在心里补一句:

“哦,这几行,就是在做坐标变换——
平移 + 旋转 + 缩放的组合,让虚拟世界动起来。”

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 2:38:52

20、复合动态系统轨迹扩展原理与Krotov函数应用

复合动态系统轨迹扩展原理与Krotov函数应用 1. 复合动态系统运动描述 复合动态系统(CDS)子系统沿包含中央和侧分支的分支轨迹运动,其动力学由以下方程描述: [ \dot{\beta x}=\beta f(\beta x, \beta u, t), t \in [t_{\beta}^{ }, t_{\beta}] ] 其中,(\beta x \in …

作者头像 李华
网站建设 2026/4/17 22:11:57

Vue PDF组件终极指南:5分钟学会vue-pdf-embed快速集成

Vue PDF组件终极指南:5分钟学会vue-pdf-embed快速集成 【免费下载链接】vue-pdf-embed PDF embed component for Vue 2 and Vue 3 项目地址: https://gitcode.com/gh_mirrors/vu/vue-pdf-embed 在现代Web应用中,PDF文档预览已成为不可或缺的功能需…

作者头像 李华
网站建设 2026/4/19 5:50:30

25、Samba 网络中的名称解析与浏览指南

Samba 网络中的名称解析与浏览指南 在网络环境中,名称解析和网络浏览是非常重要的功能,它们能够帮助用户更方便地找到共享资源。本文将详细介绍 Samba 中的名称解析和网络浏览相关内容,包括 WINS 服务器配置、名称解析方法以及网络浏览机制等。 1. WINS 服务器配置 WINS(…

作者头像 李华
网站建设 2026/4/16 20:20:56

39、Google Maps与Google Talk使用指南

Google Maps与Google Talk使用指南 一、Google Maps使用攻略 Google Maps是一款功能强大的地图工具,能帮助我们完成多种任务,下面为你详细介绍其使用方法。 (一)路线规划 备选路线 :当你规划路线时,若遇到主要道路施工等情况,可点击Google计算出的备选路线链接,切…

作者头像 李华
网站建设 2026/4/20 22:33:54

44、Google Apps集成使用指南

Google Apps集成使用指南 1. 使用iGoogle集成Google应用程序 iGoogle是Google账户提供的高度可定制主页,你可以将其设置为任何浏览器的主页。具体操作步骤如下: 1. 确保已登录Google账户。 2. 从Google主页,选择页面右上角显示的“iGoogle”链接。选择该链接后,iGoogle…

作者头像 李华
网站建设 2026/4/15 19:45:44

37、UNIX基础与vi编辑器入门指南

UNIX基础与vi编辑器入门指南 1. UNIX基础 1.1 环境变量 在UNIX系统中,shell变量可以从命令行重新赋值。有些变量,如 TERM ,重新赋值后需要导出,以便所有shell进程都能使用。例如: $ TERM=tvi925; export TERM # 告诉UNIX我正在使用Televideo 925终端你还可以定义自己…

作者头像 李华