---
title: "판을 화면이 아니라 씬에 놓는다"
description: "Panel Settings 의 render mode 를 World Space 로 바꾸면 UI 판이 씬 안의 오브젝트가 됩니다. Pixels Per Unit 으로 크기를 정하고, 기준점을 아홉 자리 중에 고르고, 카메라와의 거리로 순서가 정해지고, 입력은 물리 레이로 갑니다."
author: "유니얼"
pubDate: 2026-09-20
category: "game-dev/unity/ui"
tags: ["Unity", "UI", "UI Toolkit"]
canonical: https://blog.unialgames.com/posts/uitk-world-space/
---
[해상도 대응은 씬이 아니라 에셋 한 장에 적힌다](/posts/uitk-panel-settings/)에서 3D 안에 UI 를 붙이는 방법으로 Target Texture 를 썼습니다. 렌더 텍스처에 그린 다음 그 텍스처를 메시에 붙이는 방식이었습니다.

그게 전부가 아니었습니다. **유니티 6.2 부터 판을 씬에 직접 놓을 수 있습니다.** 화면에 얹는 대신 씬 좌표에 놓고, 다른 오브젝트처럼 옮기고 돌리고 키웁니다.

## render mode 하나를 바꾸면 판이 씬으로 나갑니다

시작은 Panel Settings 입니다. **render mode 를 World Space 로** 바꾸면 됩니다. 문서 표현으로 이렇게 됩니다.

> "In a World Space UI, you can position, rotate, and scale UI elements just like any other 2D or 3D object."

<figure class="diagram">
<svg viewBox="0 0 680 236" role="img" aria-label="화면에 얹기와 렌더 텍스처를 거쳐 메시에 붙이기와 씬에 직접 놓기 세 가지 방법 비교">
<text x="24" y="24" font-size="13" fill="var(--text)">3D 안에 UI 를 놓는 방법 세 가지</text>
<text x="24" y="50" font-size="10.5" fill="var(--text-muted)" font-family="var(--font-mono)">Screen Space Overlay</text>
<rect x="24" y="60" width="196" height="108" rx="8" fill="var(--bg-subtle)" stroke="var(--border)"></rect>
<rect x="38" y="74" width="168" height="32" rx="5" fill="var(--accent)" fill-opacity="0.18" stroke="var(--accent)"></rect>
<text x="122" y="95" font-size="9.5" fill="var(--text)" text-anchor="middle">UI</text>
<text x="122" y="132" font-size="9.5" fill="var(--text-muted)" text-anchor="middle">3D 는 그 뒤에 있습니다</text>
<text x="122" y="152" font-size="9.5" fill="var(--text-muted)" text-anchor="middle">섞을 수 없습니다</text>
<text x="122" y="190" font-size="10" fill="var(--text-muted)" text-anchor="middle">화면에 얹습니다</text>
<text x="242" y="50" font-size="10.5" fill="var(--text-muted)" font-family="var(--font-mono)">Target Texture</text>
<rect x="242" y="60" width="196" height="108" rx="8" fill="var(--bg-subtle)" stroke="var(--border)"></rect>
<rect x="256" y="74" width="76" height="40" rx="5" fill="var(--accent2)" fill-opacity="0.18" stroke="var(--accent2)"></rect>
<text x="294" y="98" font-size="9" fill="var(--text)" text-anchor="middle">텍스처</text>
<line x1="336" y1="94" x2="352" y2="94" stroke="var(--text-muted)" stroke-width="1"></line>
<polygon points="358,94 348,89 348,99" fill="var(--text-muted)"></polygon>
<rect x="362" y="74" width="62" height="40" rx="5" fill="var(--bg)" stroke="var(--border)"></rect>
<text x="393" y="98" font-size="9" fill="var(--text-muted)" text-anchor="middle">메시</text>
<text x="340" y="140" font-size="9.5" fill="var(--text-muted)" text-anchor="middle">한 단계 돌아갑니다</text>
<text x="340" y="158" font-size="9.5" fill="var(--text-muted)" text-anchor="middle">텍스처 해상도를 직접 정합니다</text>
<text x="340" y="190" font-size="10" fill="var(--text-muted)" text-anchor="middle">그려서 붙입니다</text>
<text x="460" y="50" font-size="10.5" fill="var(--accent)" font-family="var(--font-mono)">World Space (6.2~)</text>
<rect x="460" y="60" width="196" height="108" rx="8" fill="var(--accent)" fill-opacity="0.08" stroke="var(--accent)"></rect>
<rect x="482" y="78" width="120" height="44" rx="5" fill="var(--accent)" fill-opacity="0.2" stroke="var(--accent)" transform="rotate(-9 542 100)"></rect>
<text x="542" y="105" font-size="9.5" fill="var(--text)" text-anchor="middle" transform="rotate(-9 542 100)">UI 판</text>
<text x="558" y="140" font-size="9.5" fill="var(--accent)" text-anchor="middle">판이 씬 안의 물건입니다</text>
<text x="558" y="158" font-size="9.5" fill="var(--text-muted)" text-anchor="middle">돌리고 키우고 옮깁니다</text>
<text x="558" y="190" font-size="10" fill="var(--accent)" text-anchor="middle">씬에 직접 놓습니다</text>
<text x="24" y="222" font-size="11" fill="var(--text-muted)">가운데는 4편에서 쓴 방법이고, 오른쪽이 이번 편입니다</text>
</svg>
<figcaption>중간에 텍스처를 거치지 않으니 해상도를 따로 정할 일도 없습니다.</figcaption>
</figure>

그 순간 화면에 얹히던 것이 씬 안의 물건이 됩니다. 카메라가 돌면 판도 비스듬히 보이고, 멀어지면 작아집니다. Target Texture 방식이 "텍스처에 그려서 메시에 붙이기" 였다면 이쪽은 **판 자체가 씬에 있는 것** 입니다.

바뀌는 것이 또 있습니다. Target Texture 방식은 텍스처 해상도를 직접 정해야 했고 그 해상도가 곧 UI 의 픽셀 수였습니다. World Space 에서는 그 중간 단계가 없어서 **판의 픽셀이 바로 월드 크기로 환산됩니다.** 그 환산율을 정하는 값이 따로 하나 생깁니다.

## 픽셀과 유닛을 잇는 값이 하나 있습니다

`Pixels Per Unit` 입니다. 기본값이 100 이고, **패널 픽셀 몇 개가 월드 1 유닛인지** 를 정합니다.

<x-ppu>
<script type="application/json">
{"label":"같은 패널이 월드에서 몇 유닛이 되는가","note":"사람 키를 1.8 유닛으로 잡고 그렸습니다. 판 크기를 가늠하는 기준일 뿐입니다.","default":{"ppu":1,"width":0}}
</script>
</x-ppu>

[클릭은 콜라이더가 받고 UI 는 월드에 놓여 있다](/posts/ngui-input-world/)에서 NGUI 의 `UIRoot` 가 루트 스케일을 `2 / 화면높이` 로 맞춘다고 했습니다. 하는 일이 같습니다. **픽셀로 적은 값을 월드 크기로 옮기는 환산율** 이 어딘가에 하나 있어야 하고, NGUI 는 화면 높이에서 자동으로 뽑았고 UI Toolkit 은 사람이 직접 적습니다.

직접 적는 쪽이 이 경우에는 맞습니다. 벽에 붙은 큰 화면과 손에 든 단말기는 같은 uxml 이어도 월드에서의 크기가 달라야 하는데, 화면 해상도와는 상관없는 값이기 때문입니다.

## 크기와 기준점을 정합니다

World Space 로 바꾸면 Panel Settings 에 항목이 몇 개 더 붙습니다.

| 항목 | 고르는 것 |
| --- | --- |
| `Size Mode` | `Dynamic`(내용에 맞춰 늘어남) / `Fixed`(정해 둔 크기 유지) |
| `Pivot Reference Size` | `Bounding Box` / `Layout` |
| `Pivot` | 모서리부터 가운데까지 아홉 자리 |

`Pivot` 이 중요한 이유는 **내용이 늘어날 때 어느 쪽으로 늘어나느냐** 를 정하기 때문입니다. 가운데를 기준점으로 두면 위아래로 같이 퍼지고, 왼쪽 가운데로 두면 오른쪽으로만 퍼집니다.

<figure class="diagram">
<svg viewBox="0 0 680 256" role="img" aria-label="기준점 아홉 자리와, 기준점에 따라 내용이 늘어나는 방향이 달라지는 그림">
<text x="24" y="24" font-size="13" fill="var(--text)">기준점이 늘어나는 방향을 정합니다</text>
<text x="24" y="50" font-size="11" fill="var(--text-muted)">Pivot 아홉 자리</text>
<rect x="24" y="60" width="180" height="140" rx="8" fill="var(--bg-subtle)" stroke="var(--border)"></rect>
<circle cx="44" cy="80" r="3.5" fill="var(--text-muted)"></circle>
<circle cx="106" cy="80" r="3.5" fill="var(--text-muted)"></circle>
<circle cx="168" cy="80" r="3.5" fill="var(--text-muted)"></circle>
<circle cx="44" cy="122" r="3.5" fill="var(--text-muted)"></circle>
<circle cx="106" cy="122" r="5" fill="var(--accent)"></circle>
<circle cx="168" cy="122" r="3.5" fill="var(--text-muted)"></circle>
<circle cx="44" cy="164" r="3.5" fill="var(--text-muted)"></circle>
<circle cx="106" cy="164" r="3.5" fill="var(--text-muted)"></circle>
<circle cx="168" cy="164" r="3.5" fill="var(--text-muted)"></circle>
<text x="114" y="220" font-size="9.5" fill="var(--text-muted)" text-anchor="middle">모서리부터 가운데까지</text>
<text x="244" y="50" font-size="11" fill="var(--accent)">Center 로 두면</text>
<rect x="244" y="60" width="180" height="140" rx="8" fill="var(--bg-subtle)" stroke="var(--border)" stroke-dasharray="4 3"></rect>
<rect x="264" y="112" width="140" height="36" rx="5" fill="var(--accent)" fill-opacity="0.2" stroke="var(--accent)"></rect>
<rect x="264" y="82" width="140" height="96" rx="5" fill="none" stroke="var(--accent)" stroke-dasharray="3 3"></rect>
<circle cx="334" cy="130" r="4" fill="var(--accent)"></circle>
<polygon points="334,74 329,86 339,86" fill="var(--accent)"></polygon>
<polygon points="334,186 329,174 339,174" fill="var(--accent)"></polygon>
<text x="334" y="220" font-size="9.5" fill="var(--accent)" text-anchor="middle">위아래로 같이 퍼집니다</text>
<text x="464" y="50" font-size="11" fill="var(--accent2)">Left Center 로 두면</text>
<rect x="464" y="60" width="180" height="140" rx="8" fill="var(--bg-subtle)" stroke="var(--border)" stroke-dasharray="4 3"></rect>
<rect x="484" y="112" width="90" height="36" rx="5" fill="var(--accent2)" fill-opacity="0.2" stroke="var(--accent2)"></rect>
<rect x="484" y="112" width="140" height="36" rx="5" fill="none" stroke="var(--accent2)" stroke-dasharray="3 3"></rect>
<circle cx="484" cy="130" r="4" fill="var(--accent2)"></circle>
<polygon points="636,130 624,125 624,135" fill="var(--accent2)"></polygon>
<line x1="578" y1="130" x2="626" y2="130" stroke="var(--accent2)" stroke-width="1"></line>
<text x="554" y="220" font-size="9.5" fill="var(--accent2)" text-anchor="middle">오른쪽으로만 퍼집니다</text>
<text x="24" y="244" font-size="11" fill="var(--text-muted)">내용이 길어질 때 판이 어느 쪽으로 자라는지가 여기서 정해집니다</text>
</svg>
<figcaption>지도 마커라면 마커 자리가 고정이어야 하니 한쪽을 기준점으로 잡습니다.</figcaption>
</figure>

문서가 상황 셋을 예로 들어 뒀습니다. 그대로 옮기면 이렇습니다.

| 상황 | Size Mode | Pivot Reference Size | Pivot | 이유 |
| --- | --- | --- | --- | --- |
| 튜토리얼 안내 | Dynamic | Layout | Left Center | "ensures vertical expansion occurs from the center, avoiding unexpected shifts" |
| 조작 가능한 단말기 | Fixed | Layout | Center | "ensuring consistency regardless of content length or complexity" |
| 지도 마커 | Dynamic | Bounding Box | Left Center | "allowing content to expand upward and away from the in-world elements" |

가운데 줄이 알아 둘 만합니다. 글자 길이에 따라 판 크기가 변하면 안 되는 것에는 **`Fixed`** 를 씁니다. [짧은 글자일수록 번역에서 더 길어진다](/posts/unity-ui-localization/)에서 본 문제가 월드에서는 더 눈에 띕니다. 벽에 붙은 화면이 언어에 따라 커졌다 작아졌다 하면 이상합니다.

한 Panel Settings 에 UI Document 를 여럿 붙일 수 있고, 각각 크기와 자리를 따로 잡습니다. 판 설정은 공유하고 위치만 다르게 두는 식입니다. 위치와 크기는 `rootVisualElement` 의 uss `size` 와 `position` 으로 정합니다.

## 순서는 카메라와의 거리입니다

4편에서 판이 여럿일 때 `Sort Order` 숫자로 앞뒤를 정한다고 했습니다. World Space 에서는 그 자리에 다른 것이 들어옵니다.

> "z-distance from the camera determines the sorting order of root UI Documents"

**카메라에서 먼 것이 뒤입니다.** 3D 오브젝트와 같은 규칙이니 당연하다면 당연한데, 화면 UI 를 만들던 습관으로 숫자를 찾으면 안 나옵니다.

따라오는 것이 하나 있습니다. 팝업을 다른 판 앞에 두려면 **숫자를 올리는 게 아니라 카메라 쪽으로 당겨야** 합니다. 그리고 카메라가 돌아가면 앞뒤가 바뀔 수 있습니다. 화면 UI 에서는 없던 일입니다.

## 입력은 월드 레이로 갑니다

화면에 얹힌 판이면 마우스 좌표가 곧 패널 좌표였습니다. 씬에 놓인 판은 그럴 수 없습니다. 카메라에서 레이를 쏴서 어느 판의 어디에 맞았는지를 구해야 합니다.

그 설정을 맡는 것이 `Panel Input Configuration` 컴포넌트입니다.

| 항목 | 문서 설명 |
| --- | --- |
| `Interaction Layers` | "Select one or more Physics layers to cast World Space rays and determine pointer event targets" |
| `Max Interaction Distance` | 기본은 제한 없음. "for XR or performance needs" 에 맞춰 줄입니다 |
| `Default Event Camera Is Main Camera` | 메인 카메라로 화면 좌표를 월드 레이로 바꿀지 |
| `Event Cameras` | 메인 카메라를 안 쓸 때 쓸 카메라들 |
| `Panel Input Redirection` | uGUI EventSystem 이 패널 입력을 넘겨줄지. 세 가지 모드 |
| `Auto Create Panel Components` | Panel Event Handler, Panel Raycaster, World Document Raycaster 를 자동으로 만들지 |

첫 줄을 다시 읽어 볼 값어치가 있습니다. **물리 레이어를 골라서 월드 레이를 쏩니다.** [앞 편](/posts/ngui-input-world/)에서 본 NGUI 의 `UICamera` 와 거의 같은 구조입니다. 그쪽은 `cullingMask & eventReceiverMask` 였고 이쪽은 `Interaction Layers` 입니다.

2011년에 UI 를 월드 오브젝트로 만들었더니 물리로 입력을 받게 됐고, 2025년에 UI Toolkit 이 UI 를 월드에 놓기로 했더니 같은 자리로 왔습니다. **UI 를 씬에 놓으면 입력이 물리를 타는 것은 체계와 상관없는 결론** 인 셈입니다.

XR 쪽 지원도 문서가 언급합니다. 컨트롤러 레이로 UI 를 가리키는 것이 이 구조 위에서 그대로 됩니다.

## 세 체계가 월드에 UI 를 놓는 방법

정리하면 이렇습니다.

| 체계 | 방법 | 특징 |
| --- | --- | --- |
| uGUI | Canvas 의 Render Mode 를 World Space 로 | 캔버스가 씬의 사각형이 됩니다 |
| NGUI | 원래부터 월드에 있습니다 | 화면 UI 쪽이 오히려 카메라로 맞춘 것입니다 |
| UI Toolkit | Panel Settings 의 render mode 를 World Space 로 (6.2 이후) | 그 전에는 Target Texture 를 거쳐야 했습니다 |

NGUI 줄이 재미있습니다. 셋 중 유일하게 **월드가 기본이고 화면이 예외** 입니다. 나머지 둘은 화면이 기본이고 월드가 선택입니다. 같은 기능을 어느 쪽에서 출발해 만들었느냐의 차이입니다.

고르는 기준은 간단합니다. 씬 안에 놓이는 UI 가 필요하고 유니티 6.2 이상이면 World Space 가 제일 곧은 길입니다. 그보다 낮은 버전이면 4편의 Target Texture 방식이 남아 있습니다.

## 정리

- Panel Settings 의 **render mode 를 World Space** 로 바꾸면 판이 씬 안의 오브젝트가 됩니다
- `Pixels Per Unit`(기본 100) 이 **패널 픽셀과 월드 유닛을 잇습니다.** NGUI 의 `2 / 화면높이` 와 같은 자리입니다
- `Size Mode` 로 내용에 맞출지 고정할지 정하고, `Pivot` 으로 **어느 쪽으로 늘어날지** 를 정합니다
- 글자 길이에 크기가 흔들리면 안 되는 것에는 `Fixed` 입니다. 번역에서 길어지는 문제가 월드에서는 더 눈에 띕니다
- 앞뒤는 `Sort Order` 가 아니라 **카메라와의 거리** 입니다. 카메라가 돌면 바뀔 수 있습니다
- 입력은 `Panel Input Configuration` 의 `Interaction Layers` 로 **물리 레이어를 골라 월드 레이를 쏩니다**
- UI 를 씬에 놓으면 입력이 물리를 타는 것은 NGUI 와 같습니다. 체계와 상관없는 결론입니다