---
title: "행렬: 크기 · 회전 · 이동을 한 번에 담는 표"
description: "부모를 돌리면 자식도 같이 도는 것은 엔진이 꼭짓점마다 행렬을 곱하기 때문입니다. 행렬이 무엇인지부터, 행렬 × 벡터가 열을 섞는 계산이라는 것, 크기 · 회전 · 이동을 TRS 순서로 합치는 이유까지 작은 숫자로 따라갑니다."
author: "유니얼"
pubDate: 2026-11-05
category: "game-dev/math"
tags: ["Unity", "기초"]
canonical: https://blog.unialgames.com/posts/math-matrix-trs/
---
부모 오브젝트를 돌리고 키우면 자식들이 모두 같이 돌고 커집니다. 캐릭터 모델의 꼭짓점 수천 개도 매 프레임 캐릭터를 따라 자리를 옮깁니다.
엔진은 이 일을 **행렬**로 합니다. 행렬은 숫자를 가로세로 칸에 늘어놓은 표로, 칸이 가로 2, 세로 2 면 2×2 행렬이라고 부릅니다. 크기, 회전, 이동을 행렬 하나에 담아 두고, 점마다 그 행렬을 **곱합니다.**

> **행렬은 "축이 어디로 가는지" 를 세로줄(열)마다 적어 둔 표입니다. 2×2 행렬의 첫째 열은 x 축 (1, 0) 이 옮겨 가는 자리, 둘째 열은 y 축 (0, 1) 이 옮겨 가는 자리입니다.
> 행렬 × (x, y) = x × 첫째 열 + y × 둘째 열 입니다.
> 크기 · 회전 · 이동을 하나로 합칠 때는 순서가 결과를 바꾸고, 유니티는 크기 → 회전 → 이동 순서(TRS)를 씁니다.**

## 행렬 × 벡터는 열을 섞는 것이다

x 축은 오른쪽으로 1 칸인 화살표 (1, 0), y 축은 위로 1 칸인 화살표 (0, 1) 입니다.
벡터, 곧 방향과 길이를 가진 화살표 (2, 1) 은 "x 축 방향으로 2 칸, y 축 방향으로 1 칸" 입니다. 곧 `2 × (1, 0) + 1 × (0, 1)` 입니다.

숫자 × 벡터는 칸마다 그 숫자를 곱하는 것이라 2 × (1, 0) = (2, 0) 입니다. 방향은 그대로, 길이만 2 배입니다. 벡터 + 벡터는 같은 칸끼리 더하는 것이라 (2, 0) + (0, 1) = (2, 1), 두 화살표를 이어 붙인 끝입니다.

행렬은 이 두 축을 다른 화살표로 바꿔치기합니다. **첫째 열이 새 x 축, 둘째 열이 새 y 축**입니다.
그래서 행렬 × (2, 1) 은 `2 × 새 x 축 + 1 × 새 y 축` 입니다. 숫자 (2, 1) 은 그대로 두고, 그 숫자로 섞는 축만 바뀌는 것입니다.

두 행렬을 표로 적으면 이렇습니다. 세로로 읽은 줄이 열입니다.

```text
x 두 배          90° 회전
| 2  0 |         | 0  −1 |
| 0  1 |         | 1   0 |
```

| 행렬 | 새 x 축 (첫째 열) | 새 y 축 (둘째 열) | (2, 1) 이 가는 곳 |
| --- | --- | --- | --- |
| x 두 배 | (2, 0) | (0, 1) | **(4, 1)** |
| 90° 회전 | (0, 1) | (−1, 0) | **(−1, 2)** |

x 두 배는 2 × (2, 0) + 1 × (0, 1) = (4, 1), 90° 회전은 2 × (0, 1) + 1 × (−1, 0) = (−1, 2) 입니다.
90° 회전 행렬의 열을 보면, x 축 (1, 0) 이 위 (0, 1) 로, y 축 (0, 1) 이 왼쪽 (−1, 0) 으로 갑니다. 둘 다 반시계 방향으로 90° 돈 것입니다.

<x-vec>
<script type="application/json">
{
  "label": "행렬이 축을 바꾸면 벡터도 따라간다",
  "view": [-2, -1, 5, 3],
  "cases": [
    {
      "name": "x 두 배",
      "steps": [
        {
          "caption": "원래 축 x = (1, 0), y = (0, 1). 벡터 (2, 1) 은 x 축 2 개와 y 축 1 개를 이어 붙인 것입니다.",
          "items": [
            { "id": "i", "from": [0, 0], "to": [1, 0], "color": "accent2", "label": "x 축", "labelAt": [0.5, -0.4] },
            { "id": "j", "from": [0, 0], "to": [0, 1], "color": "warn", "label": "y 축", "labelAt": [-0.5, 0.6] },
            { "id": "a", "type": "line", "from": [0, 0], "to": [2, 0], "color": "accent2" },
            { "id": "b", "type": "line", "from": [2, 0], "to": [2, 1], "color": "warn" },
            { "id": "v", "from": [0, 0], "to": [2, 1], "label": "(2, 1)", "labelAt": [2.5, 1.3] }
          ]
        },
        {
          "caption": "행렬의 첫째 열 (2, 0) 이 새 x 축입니다. x 축이 두 배로 늘어났고, y 축 (0, 1) 은 그대로입니다.",
          "items": [
            { "id": "i", "from": [0, 0], "to": [2, 0], "color": "accent2", "label": "새 x 축 (2, 0)", "labelAt": [1, -0.4] },
            { "id": "j", "from": [0, 0], "to": [0, 1], "color": "warn", "label": "y 축", "labelAt": [-0.5, 0.6] },
            { "id": "a", "type": "line", "from": [0, 0], "to": [2, 0], "color": "accent2" },
            { "id": "b", "type": "line", "from": [2, 0], "to": [2, 1], "color": "warn" },
            { "id": "v", "from": [0, 0], "to": [2, 1], "color": "muted" }
          ]
        },
        {
          "caption": "같은 숫자 (2, 1) 로 새 축을 섞습니다. 2 × (2, 0) + 1 × (0, 1) = (4, 1). 벡터가 가로로 두 배 늘어났습니다.",
          "items": [
            { "id": "i", "from": [0, 0], "to": [2, 0], "color": "accent2", "label": "새 x 축 (2, 0)", "labelAt": [1, -0.4] },
            { "id": "j", "from": [0, 0], "to": [0, 1], "color": "warn", "label": "y 축", "labelAt": [-0.5, 0.6] },
            { "id": "a", "type": "line", "from": [0, 0], "to": [4, 0], "color": "accent2" },
            { "id": "b", "type": "line", "from": [4, 0], "to": [4, 1], "color": "warn" },
            { "id": "v", "from": [0, 0], "to": [4, 1], "label": "(4, 1)", "labelAt": [4.4, 1.4] }
          ]
        }
      ]
    },
    {
      "name": "90° 회전",
      "steps": [
        {
          "caption": "원래 축과 벡터 (2, 1).",
          "items": [
            { "id": "i", "from": [0, 0], "to": [1, 0], "color": "accent2", "label": "x 축", "labelAt": [0.5, -0.4] },
            { "id": "j", "from": [0, 0], "to": [0, 1], "color": "warn", "label": "y 축", "labelAt": [-0.5, 0.6] },
            { "id": "a", "type": "line", "from": [0, 0], "to": [2, 0], "color": "accent2" },
            { "id": "b", "type": "line", "from": [2, 0], "to": [2, 1], "color": "warn" },
            { "id": "v", "from": [0, 0], "to": [2, 1], "label": "(2, 1)", "labelAt": [2.5, 1.3] }
          ]
        },
        {
          "caption": "회전 행렬의 열 (0, 1) 과 (−1, 0) 이 새 축입니다. 두 축이 같이 반시계로 90° 돌았습니다.",
          "items": [
            { "id": "i", "from": [0, 0], "to": [0, 1], "rigid": true, "color": "accent2", "label": "새 x 축", "labelAt": [0.6, 0.8] },
            { "id": "j", "from": [0, 0], "to": [-1, 0], "rigid": true, "color": "warn", "label": "새 y 축", "labelAt": [-1, -0.4] },
            { "id": "v", "from": [0, 0], "to": [2, 1], "color": "muted" }
          ]
        },
        {
          "caption": "2 × (0, 1) + 1 × (−1, 0) = (−1, 2). 새 x 축으로 2 칸, 새 y 축으로 1 칸. 벡터 전체가 90° 돌았습니다.",
          "items": [
            { "id": "i", "from": [0, 0], "to": [0, 1], "color": "accent2", "label": "새 x 축", "labelAt": [0.6, 0.8] },
            { "id": "j", "from": [0, 0], "to": [-1, 0], "color": "warn", "label": "새 y 축", "labelAt": [-1, -0.4] },
            { "id": "a", "type": "line", "from": [0, 0], "to": [0, 2], "color": "accent2" },
            { "id": "b", "type": "line", "from": [0, 2], "to": [-1, 2], "color": "warn" },
            { "id": "v", "from": [0, 0], "to": [-1, 2], "label": "(−1, 2)", "labelAt": [-1.3, 2.4] }
          ]
        }
      ]
    }
  ]
}
</script>
</x-vec>

90° 가 아닌 각도도 같은 방법으로 만듭니다. 길이 1 인 화살표를 각 θ 만큼 돌리면 끝이 (cos θ, sin θ) 에 옵니다. cos 는 그때의 가로, sin 은 세로입니다.
그래서 θ 만큼 돌리는 행렬의 첫째 열은 x 축을 돌린 (cos θ, sin θ), 둘째 열은 y 축을 돌린 (−sin θ, cos θ) 입니다.
θ = 90° 면 cos 가 0, sin 이 1 이라 위 표의 (0, 1), (−1, 0) 이 그대로 나옵니다. 유니티 2D 에서 Rotation 의 z 를 90 으로 둔 것이 이 회전입니다.

교과서에서는 이 계산을 **행 곱하기 열**로 가르칩니다. 표의 가로 한 줄이 행, 세로 한 줄이 열입니다. 행렬의 윗줄(첫째 행)을 (x, y) 와 짝지어 곱해 더하면 결과의 첫 숫자, 아랫줄을 그렇게 하면 둘째 숫자입니다.

```text
| a  b |   | x |   | a × x + b × y |
| c  d | × | y | = | c × x + d × y |
```

90° 회전에 (2, 1) 을 넣으면 (0 × 2 + (−1) × 1, 1 × 2 + 0 × 1) = (−1, 2) 로, 열을 섞은 결과와 같습니다.
**계산은 행으로 하고, 뜻은 열로 읽는다**고 기억하면 됩니다.

## 순서를 바꾸면 결과가 바뀐다

크기를 바꾸는 행렬 S(x 두 배)와 회전 행렬 R(90°)을 둘 다 쓰면, 어느 것을 먼저 하느냐에 따라 결과가 다릅니다. (1, 1) 에 두 순서로 적용한 결과입니다.

| 순서 | 1 단계 | 2 단계 |
| --- | --- | --- |
| 크기 → 회전 | S (1, 1) = (2, 1) | R (2, 1) = **(−1, 2)** |
| 회전 → 크기 | R (1, 1) = (−1, 1) | S (−1, 1) = **(−2, 1)** |

<x-vec>
<script type="application/json">
{
  "label": "(1, 1) 에 크기와 회전을 순서만 바꿔 적용",
  "view": [-3, -1, 3, 3],
  "cases": [
    {
      "name": "크기 → 회전",
      "steps": [
        {
          "caption": "출발점 (1, 1).",
          "items": [ { "id": "v", "from": [0, 0], "to": [1, 1], "label": "(1, 1)", "labelAt": [1.3, 1.4] } ]
        },
        {
          "caption": "먼저 x 두 배. (2, 1). 물체 자기 축 기준으로 옆으로 늘어난 것입니다.",
          "items": [ { "id": "v", "from": [0, 0], "to": [2, 1], "label": "(2, 1)", "labelAt": [2.3, 1.4] } ]
        },
        {
          "caption": "그다음 90° 회전. (−1, 2). 늘어난 모양 그대로 돌았습니다.",
          "items": [ { "id": "v", "from": [0, 0], "to": [-1, 2], "rigid": true, "color": "accent2", "label": "(−1, 2)", "labelAt": [-1.3, 2.4] } ]
        }
      ]
    },
    {
      "name": "회전 → 크기",
      "steps": [
        {
          "caption": "같은 출발점 (1, 1).",
          "items": [ { "id": "v", "from": [0, 0], "to": [1, 1], "label": "(1, 1)", "labelAt": [1.3, 1.4] } ]
        },
        {
          "caption": "먼저 90° 회전. (−1, 1).",
          "items": [ { "id": "v", "from": [0, 0], "to": [-1, 1], "rigid": true, "label": "(−1, 1)", "labelAt": [-1.3, 1.4] } ]
        },
        {
          "caption": "그다음 x 두 배. (−2, 1). 이번에는 돌아간 뒤의 월드 x 방향으로 늘어나서, 크기 → 회전 과 다른 자리 (−2, 1) 에 섰습니다.",
          "items": [ { "id": "v", "from": [0, 0], "to": [-2, 1], "color": "warn", "label": "(−2, 1)", "labelAt": [-2.3, 1.4] } ]
        }
      ]
    }
  ]
}
</script>
</x-vec>

**행렬 곱은 순서를 바꾸면 값이 달라집니다.** 수학에서는 AB ≠ BA 라고 씁니다. 보통 숫자 곱셈(2 × 3 = 3 × 2)과 가장 다른 점입니다.
행렬을 곱해서 하나로 합칠 때는 **오른쪽에 있는 것이 먼저 적용**됩니다. `R × S × v` 는 `R × (S × v)`, 곧 v 에 가장 가까이 붙은 S 가 먼저 v 를 받고 그 결과에 R 을 곱한 것입니다.

두 행렬을 미리 곱해 둔 `R × S` 도 행렬 하나이고, 그 열은 **S 의 열을 R 에 넣은 결과**입니다. R × (2, 0) = (0, 2), R × (0, 1) = (−1, 0) 입니다.
여기에 (1, 1) 을 넣으면 1 × (0, 2) + 1 × (−1, 0) = (−1, 2) 로, 두 번 나눠 곱한 결과와 같습니다.

키우기, 돌리기, 옮기기처럼 점을 다른 자리로 옮기는 규칙을 변환이라고 하는데, 여러 변환을 행렬 하나로 접어 둘 수 있다는 것이 행렬을 쓰는 가장 큰 이유입니다. 꼭짓점이 1000 개라도 행렬을 미리 합쳐 두면 점마다 곱셈 한 번이면 됩니다.

크기를 회전보다 먼저 하는 이유는 위 결과에 있습니다. 물체를 **자기 모양 그대로** 키우고 싶다면 아직 돌기 전에 키워야 합니다.
돈 다음에 키우면 물체의 축이 아니라 월드의 축 방향으로 늘어나 모양이 비틀립니다.
x, y, z 를 똑같이 키우는 크기(균일한 크기)라면 어느 쪽이 먼저든 결과가 같습니다.

## 이동은 2×2 로는 못 한다

2×2 행렬에 (0, 0) 을 넣으면 어떤 행렬이든 (0, 0) 이 나옵니다. 열을 0 배씩 섞기 때문입니다. 모든 좌표를 재기 시작하는 자리 (0, 0) 을 **원점**이라고 하는데, 원점이 움직이지 않으니 **옮기기(이동)는 2×2 로 표현할 수 없습니다.**

그래서 숫자 하나를 덧붙입니다. 2D 점은 (x, y, **1**), 방향은 (x, y, **0**) 으로 쓰고 3×3 행렬을 씁니다.
셋째 열에 이동량을 넣으면 그 열이 덧붙인 숫자만큼 섞입니다. **점은 1 배라 이동하고, 방향은 0 배라 이동하지 않습니다.**

(3, 1) 만큼 옮기는 행렬입니다. 앞의 두 열은 x 축과 y 축을 그대로 두고, 셋째 열이 이동량 (3, 1) 을 들고 있습니다.

```text
| 1  0  3 |
| 0  1  1 |
| 0  0  1 |
```

같은 (2, 1) 이라도 점으로 넣으면 옮겨지고, 방향으로 넣으면 그대로입니다.

<x-vec>
<script type="application/json">
{
  "label": "(3, 1) 이동 행렬에 넣은 (2, 1)",
  "view": [-1, -1, 6, 3],
  "cases": [
    {
      "name": "점 (2, 1, 1)",
      "steps": [
        {
          "caption": "앞의 두 열로 섞으면 2 × (1, 0) + 1 × (0, 1) = (2, 1). 아직 제자리입니다.",
          "items": [
            { "id": "v", "from": [0, 0], "to": [2, 1], "color": "muted" },
            { "id": "p", "type": "point", "at": [2, 1], "color": "accent", "label": "(2, 1)", "labelAt": [2.1, 1.5] }
          ]
        },
        {
          "caption": "덧붙인 숫자가 1 이라 셋째 열 (3, 1) 이 1 배 더해집니다. (2, 1) + (3, 1) = (5, 2). 점이 옮겨졌습니다.",
          "code": "1 × (3, 1) 을 더함",
          "items": [
            { "id": "v", "from": [0, 0], "to": [2, 1], "color": "muted" },
            { "id": "t", "from": [2, 1], "to": [5, 2], "color": "warn", "label": "+ (3, 1)", "labelAt": [3.3, 2.0] },
            { "id": "p", "type": "point", "at": [5, 2], "color": "accent", "label": "(5, 2)", "labelAt": [5.1, 2.5] }
          ]
        }
      ]
    },
    {
      "name": "방향 (2, 1, 0)",
      "steps": [
        {
          "caption": "앞의 두 열로 섞으면 똑같이 (2, 1).",
          "items": [
            { "id": "v", "from": [0, 0], "to": [2, 1], "color": "accent", "label": "(2, 1)", "labelAt": [2.1, 1.5] }
          ]
        },
        {
          "caption": "덧붙인 숫자가 0 이라 셋째 열은 0 배, 곧 아무것도 더해지지 않습니다. 방향은 (2, 1) 그대로입니다. 방향에는 자리가 없으니 옮길 것도 없습니다.",
          "code": "0 × (3, 1) 을 더함",
          "items": [
            { "id": "v", "from": [0, 0], "to": [2, 1], "color": "accent2", "label": "(2, 1) 그대로", "labelAt": [2.1, 1.5] }
          ]
        }
      ]
    }
  ]
}
</script>
</x-vec>

유니티에서 로컬 점을 월드 점으로 옮기는 `TransformPoint` 는 이동까지 적용하고, 로컬 벡터를 옮기는 `TransformVector` 는 이동을 빼는 것이 이 덧붙인 숫자 하나의 차이입니다.
3D 에서는 같은 이유로 (x, y, z, 1) 과 **4×4 행렬**을 씁니다. 이렇게 숫자를 하나 덧붙여 쓰는 방식을 **동차좌표**라고 부릅니다.

## TRS: 크기 → 회전 → 이동

유니티 Inspector 의 Transform 에 있는 Position · Rotation · Scale 세 칸이 위치(Translation) · 회전(Rotation) · 크기(Scale) 입니다. 엔진은 이것을 **TRS 행렬** 하나로 합칩니다.
`M = T × R × S` 라서 오른쪽부터, 곧 **크기 → 회전 → 이동** 순서로 적용됩니다.

크기 x 두 배, 회전 90°, 이동 (3, 1) 인 오브젝트의 로컬 점 (1, 1) 은 S, R, T 를 차례로 지나 월드 자리에 갑니다. 로컬 점은 오브젝트 자신을 기준으로 적은 자리이고, 월드 자리는 씬 전체를 기준으로 적은 자리입니다.

<x-vec>
<script type="application/json">
{
  "label": "로컬 점 (1, 1) 이 TRS 를 지나 월드로",
  "view": [-2, -1, 5, 4],
  "steps": [
    {
      "caption": "로컬 점 (1, 1). 오브젝트를 아직 아무것도 하지 않은 상태입니다.",
      "code": "local = (1, 1)",
      "items": [
        { "id": "v", "from": [0, 0], "to": [1, 1], "color": "muted" },
        { "id": "p", "type": "point", "at": [1, 1], "color": "accent", "label": "(1, 1)", "labelAt": [1.3, 1.5] }
      ]
    },
    {
      "caption": "S: x 두 배. (2, 1).",
      "code": "S × (1, 1) = (2, 1)",
      "items": [
        { "id": "v", "from": [0, 0], "to": [2, 1], "color": "muted" },
        { "id": "p", "type": "point", "at": [2, 1], "color": "accent", "label": "(2, 1)", "labelAt": [2.3, 1.5] }
      ]
    },
    {
      "caption": "R: 90° 회전. (−1, 2). 원점을 중심으로 돌았습니다. 아직 원점은 그대로입니다.",
      "code": "R × (2, 1) = (−1, 2)",
      "items": [
        { "id": "v", "from": [0, 0], "to": [-1, 2], "rigid": true, "color": "muted" },
        { "id": "p", "type": "point", "at": [-1, 2], "color": "accent", "label": "(−1, 2)", "labelAt": [-1.2, 2.5] }
      ]
    },
    {
      "caption": "T: (3, 1) 만큼 이동. (2, 3). 원점에 있던 오브젝트의 중심이 (3, 1) 로 갔고, 점도 같이 갔습니다. 이것이 월드 좌표입니다.",
      "code": "T × (−1, 2) = (2, 3)",
      "items": [
        { "id": "v", "from": [3, 1], "to": [2, 3], "color": "muted" },
        { "id": "o", "type": "point", "at": [3, 1], "color": "muted", "label": "중심 (3, 1)", "labelAt": [3.9, 0.6] },
        { "id": "p", "type": "point", "at": [2, 3], "color": "warn", "label": "(2, 3)", "labelAt": [2.3, 3.5] }
      ]
    }
  ]
}
</script>
</x-vec>

**이동을 마지막에 하는 이유**도 보입니다. 회전은 원점을 중심으로 돌기 때문에, 먼저 옮겨 버리면 오브젝트가 제자리에서 돌지 않고 원점을 중심으로 크게 휘돕니다.

코드에서는 이렇게 씁니다.

```csharp
Matrix4x4 m = Matrix4x4.TRS(position, rotation, scale);

// 점: 크기 · 회전 · 이동 전부
Vector3 worldPoint = m.MultiplyPoint3x4(localPoint);

// 방향: 크기와 회전만. 이동은 빼고
Vector3 worldDir = m.MultiplyVector(localDir);
```

`transform.localToWorldMatrix` 는 부모까지 모두 곱해 둔 그 오브젝트의 월드 행렬입니다. 부모가 없으면 자기 TRS 와 같습니다.
`transform.TransformPoint` 는 이 행렬을 곱하는 일을 대신 해 줍니다.

## 부모와 자식은 행렬을 곱해 이어진다

자식의 월드 행렬은 **부모의 월드 행렬 × 자식의 TRS 행렬**입니다. 오른쪽이 먼저라서, 자식의 점은 먼저 자식의 크기 · 회전 · 이동을 거치고, 그 결과가 다시 부모의 것을 거칩니다.
그래서 부모를 돌리면 자식이 따라 돌고, 부모를 키우면 자식의 위치와 크기도 따라 커집니다.

| 부모 | 자식 (로컬) | 자식의 월드 결과 |
| --- | --- | --- |
| 크기 2 | 위치 (1, 0, 0) | 위치 (2, 0, 0) |
| y 로 90° 회전 | 위치 (1, 0, 0) | 위치 (0, 0, −1) |
| 위치 (5, 0, 0) | 위치 (1, 0, 0) | 위치 (6, 0, 0) |

유니티 3D 에서 y 축으로 +90° 는 위에서 내려다볼 때 **시계 방향**입니다. 그래서 +x 쪽에 있던 자식이 −z 쪽으로 갑니다.

조심할 것이 둘 있습니다.

- **부모를 한 방향으로만 늘리고 자식을 돌리면 자식이 비틀립니다.** 자식이 돈 다음에 부모의 늘이기가 적용되어, 위에서 본 "회전 → 크기" 와 같은 일이 생깁니다.
  자식이 도는 오브젝트는 부모의 크기를 x, y, z 똑같이 둡니다
- **크기를 0 으로 만들면 되돌릴 수 없습니다.** 모든 점이 한 점으로 뭉쳐서, 거꾸로 "월드 점이 로컬의 어디였나" 를 구하는 계산(역행렬, 행렬이 한 일을 되돌리는 행렬)이 정의되지 않습니다.
  안 보이게 하려면 크기 대신 `SetActive(false)` 나 렌더러를 끕니다

## 정리

- 행렬은 숫자를 가로세로로 늘어놓은 표이고, 각 열은 축이 옮겨 가는 자리입니다
- 행렬 × 벡터는 그 열들을 벡터의 숫자만큼 섞는 것입니다. 계산은 행 곱하기 열로 하고, 뜻은 열로 읽습니다
- θ 회전 행렬의 열은 (cos θ, sin θ) 와 (−sin θ, cos θ) 입니다
- 행렬 곱은 순서를 바꾸면 결과가 달라집니다. 합친 행렬은 오른쪽부터 적용되고, 여러 변환을 행렬 하나로 접어 둘 수 있습니다
- 이동은 2×2(3D 는 3×3)로 못 해서 숫자 하나를 덧붙입니다(동차좌표). 점은 1, 방향은 0 이라 점만 이동합니다
- 유니티는 TRS, 곧 크기 → 회전 → 이동 순서로 합칩니다. 자기 모양대로 키우고, 제자리에서 돌린 뒤 옮기기 위해서입니다
- 자식의 월드 행렬은 부모의 월드 행렬 × 자식의 TRS 입니다
- 부모의 크기는 축마다 같게 두고, 크기 0 은 피합니다