2D Pixel Perfect Camera 설정: 도트 깨짐 없이 픽셀 아트를 선명하게 출력하는 법
2D 픽셀 아트가 흐려지거나 흔들리고 해상도마다 픽셀이 깨지는 원인을 분석합니다. Unity 2D Pixel Perfect Camera와 Godot 4 스케일링 설정으로 정수 배율, 스프라이트 PPU, 텍스처 필터를 맞추는 실전 방법을 정리합니다.

픽셀 아트가 깨지는 주요 원인 중 하나는 텍셀 1개가 화면의 정수 개 픽셀에 대응하지 않는 것입니다. 스프라이트의 PPU(Pixels Per Unit), 카메라의 기준 해상도, 텍스처 필터, 화면 배율을 하나의 픽셀 격자로 맞추고 압축이나 아틀라스 샘플링 문제도 함께 점검합니다.
특히 이동 중 화면이 미세하게 흔들린다면 카메라 또는 오브젝트 좌표가 서브픽셀 위치에 있고 화면이 흐리다면 Bilinear 필터나 비정수 배율이 적용된 경우가 많습니다.
2D Pixel Perfect Camera에서 도트가 깨지는 이유는 무엇일까?
픽셀 아트는 원본 텍스처의 한 픽셀을 화면에서도 또렷한 사각형으로 보여야 합니다. 그러나 확대 배율이 2배, 3배처럼 정수가 아니라 2.5배가 되면 렌더러는 하나의 텍셀을 여러 화면 픽셀에 나누어 배치해야 합니다. 이때 보간이나 샘플 분배가 발생해 가장자리가 흐려지거나 두께가 고르지 않게 보입니다.
화면상 스프라이트 크기는 대략 다음 관계를 가집니다.
Pixel Perfect 출력의 목표는 scale이 정수가 되도록 만드는 것입니다.
| 증상 | 흔한 원인 | 우선 해결책 |
|---|---|---|
| 도트 경계가 흐림 | Bilinear 또는 Trilinear 필터 | Point/Nearest 필터 사용 |
| 이동할 때 배경이 떨림 | 카메라·오브젝트의 서브픽셀 좌표 | 픽셀 격자에 스냅 |
| 해상도에 따라 도트 크기가 들쭉날쭉함 | 기준 해상도와 화면 비율 불일치 | 정수 배율과 레터박스 적용 |
| 타일 경계에 가는 선이 생김 | 텍스처 블리딩, 아틀라스 패딩 부족 | 가장자리 색상 복제와 아틀라스 패딩 점검 |

Pixel Perfect Scaling의 핵심: 기준 해상도와 정수 배율
먼저 게임이 의도한 내부 기준 해상도를 정합니다. 예를 들어 16:9 게임이라면 320×180, 480×270, 640×360처럼 작업 규모에 맞는 해상도를 선택할 수 있습니다. 그다음 실제 창 해상도에서 기준 해상도를 몇 배로 확대할지 계산합니다.
이 식은 창의 너비와 높이가 각각 기준 해상도 이상인 경우에 사용합니다. 더 작은 창에서는 결과가 0이 될 수 있으므로 최소 창 크기를 제한하거나 축소 시의 별도 표시 정책을 정해야 합니다. 예를 들어 기준 해상도가 320×180이고 창이 1920×1080이면 배율은 6입니다. Point 필터와 픽셀 격자 정렬도 맞으면 픽셀을 균일한 크기로 확대할 수 있습니다. 반면 1366×768에서는 창 안에 들어가는 최대 정수 배율이 4이며 남는 영역은 레터박스 또는 필러박스로 처리하는 편이 좋습니다.
PPU는 왜 카메라 설정과 함께 맞춰야 할까?
PPU는 월드 단위 1개에 들어가는 소스 텍스처 픽셀 수입니다. Unity에서 16×16 타일을 1 유닛으로 쓰려면 보통 모든 스프라이트의 Pixels Per Unit을 16으로 통일합니다. 32×32 타일 게임이라면 32를 쓰는 식입니다.
PPU가 제각각이면 같은 월드 좌표에 놓인 스프라이트도 화면 픽셀 격자와 다른 방식으로 맞물립니다. Pixel Perfect Camera의 Asset Pixels Per Unit은 임포트한 스프라이트 PPU와 일치시켜야 합니다.
Unity 2D Pixel Perfect Camera는 어떻게 설정할까?
아래 설정은 Unity 6.0의 URP 2D Renderer를 기준으로 합니다. Pixel Perfect Camera 컴포넌트를 메인 카메라에 추가하고 스프라이트 임포트 설정과 카메라 기준값을 일치시킵니다. Universal 2D 템플릿에는 이 기능이 포함되어 있으며, Built-in Render Pipeline용 별도 2D Pixel Perfect 패키지의 설정과 혼용하지 않습니다. Unity 공식 설정 문서를 참고합니다.
1. 스프라이트 임포트 설정을 통일한다
모든 픽셀 아트 스프라이트에서 다음 값을 확인합니다.
Texture Type:Sprite (2D and UI)Filter Mode:Point (no filter)Compression: 가능하면NoneGenerate Mip Maps: 2D 픽셀 아트라면 비활성화Pixels Per Unit: 프로젝트 규칙값으로 통일. 예:16
압축은 색상 경계에 예기치 않은 변화를 만들 수 있습니다. 메모리가 매우 제한된 플랫폼이 아니라면 UI와 근거리 2D 스프라이트에서는 압축을 끈 상태로 먼저 품질을 확인하는 편이 안전합니다.
2. 카메라의 기준 해상도와 Asset Pixels Per Unit을 입력한다
메인 카메라의 Pixel Perfect Camera에서 다음처럼 설정합니다.
| 항목 | 예시 값 | 의미 |
|---|---|---|
| Asset Pixels Per Unit | 16 | 스프라이트 임포트 PPU와 동일한 값 |
| Reference Resolution X | 320 | 내부 기준 너비 |
| Reference Resolution Y | 180 | 내부 기준 높이 |
| Grid Snapping | Upscale Render Texture | 낮은 해상도의 렌더 텍스처를 거쳐 확대 |
| Crop Frame | Windowbox | 화면 비율이 다르면 가로·세로 여백으로 기준 영역 유지 |
Unity 6.0 URP의 Grid Snapping에서는 None, Pixel Snapping, Upscale Render Texture 중 하나를 선택합니다. Pixel Snapping은 렌더링 위치를 격자에 맞추며 Transform 좌표를 변경하지 않습니다. Upscale Render Texture는 기준 해상도 또는 화면 비율에 따라 그보다 큰 렌더 텍스처를 사용합니다. 따라서 내부 해상도가 항상 기준값과 같다고 가정하지 말고 Crop Frame 설정도 함께 확인합니다. UI가 별도 캔버스에 있거나 후처리를 많이 쓴다면 실제 기기에서 UI와 효과가 함께 선명하게 나오는지 확인해야 합니다.
3. 이동 좌표를 픽셀 격자에 맞춘다
카메라가 Pixel Perfect Camera를 사용하더라도 모든 흔들림이 자동으로 사라지는 것은 아닙니다. Rigidbody2D.interpolation은 물리 갱신 사이의 표시 위치를 추정하므로 물리 위치와 렌더링 위치를 구분해야 합니다. Cinemachine과 스크립트 추적을 사용할 때는 대상의 갱신 시점과 카메라의 갱신 방식도 점검하고, 픽셀 격자에서 벗어난 표시 위치가 생기는지 캡처로 확인합니다.
월드 좌표를 스냅해야 하는 경우에는 월드 유닛당 픽셀 수를 기준으로 반올림합니다. 아래 함수의 pixelsPerUnit에는 0보다 큰 유한한 값을 전달해야 합니다.
using UnityEngine;
public static class PixelSnap
{
public static Vector3 Snap(Vector3 position, float pixelsPerUnit)
{
var unit = 1f / pixelsPerUnit;
position.x = Mathf.Round(position.x / unit) * unit;
position.y = Mathf.Round(position.y / unit) * unit;
return position;
}
}
이 코드는 픽셀 단위 이동이 의도된 오브젝트에만 적용합니다. 부드러운 카메라 추적이나 물리 기반 이동까지 무조건 반올림하면 이동 감각이 거칠어질 수 있습니다.
Godot 4.2 이상에서 픽셀 퍼펙트 스케일링을 설정하는 방법
Godot에서는 프로젝트의 Stretch 설정과 텍스처 필터를 함께 맞춥니다. 아래 예제는 정수 배율 옵션이 추가된 Godot 4.2 이상을 기준으로 내부 렌더 해상도를 낮게 유지하고 확대 시 보간하지 않도록 구성합니다. Godot 해상도 처리 문서를 참고합니다.
1. Project Settings에서 내부 해상도를 정한다
Project Settings > Display > Window에서 기준 크기를 설정합니다.
Viewport Width:320Viewport Height:180Stretch Mode:viewportStretch Aspect: 게임 비율에 맞게keep또는expandStretch Scale Mode: 정수 배율을 우선한다면integer
viewport는 낮은 해상도의 뷰포트에서 렌더한 결과를 확대합니다. canvas_items는 2D 좌표를 확대하되 최종 화면 해상도에서 그리므로 내부 렌더 해상도를 고정하는 방식과 다릅니다. integer 모드는 정수 배율을 유지하는 데 유용합니다. 화면 비율이 맞지 않는 환경에서는 빈 공간이 생길 수 있으므로 이를 의도한 레터박스로 받아들일지 더 넓은 화면을 보여줄지 먼저 결정해야 합니다.
2. 텍스처 필터를 Nearest로 바꾼다
Godot 4에서는 프로젝트 기본 텍스처 필터 또는 개별 CanvasItem의 텍스처 필터를 Nearest로 설정합니다. 스프라이트마다 설정이 섞이지 않도록 프로젝트 기본값을 먼저 정하고 필요한 예외만 개별 오버라이드하는 방식이 관리하기 쉽습니다.
3. Camera2D의 위치와 줌을 점검한다
Camera2D.zoom은 가능하면 정수 관계를 유지합니다. 예를 들어 원본 픽셀을 확대해야 한다면 Vector2(2, 2)처럼 정수 확대를 사용합니다. 타일맵과 캐릭터가 흔들리면 Camera2D와 추적 대상의 위치가 기준 픽셀 격자에 맞는지도 확인합니다.
타일맵 경계의 얇은 선은 어떻게 없앨까?
타일 사이에 보이는 가는 선은 카메라 문제만이 아니라 텍스처 아틀라스 샘플링 문제일 수 있습니다. 이 경우 Point 필터만 바꿔서는 완전히 해결되지 않습니다.
- 타일 원본 주변에 동일 색상 픽셀을 1~2픽셀 복제해 패딩을 만듭니다.
- 아틀라스 생성 도구의 패딩과 가장자리 색상 복제 옵션을 확인합니다. Unity 스프라이트 임포터의
Extrude Edges는 생성되는 스프라이트 메시의 범위에 관한 설정이므로 텍스처 가장자리 색상 복제를 대신하는 옵션으로 취급하지 않습니다. - 타일맵과 카메라가 서브픽셀 좌표에 놓이지 않았는지 확인합니다.
- 후처리 렌더 타깃이 Bilinear로 확대되지 않는지 확인합니다.
특히 셰이더가 UV를 이동시키거나 화면 왜곡 효과를 적용한다면 UV가 타일 바깥 텍셀을 읽지 않도록 클램프와 패딩을 함께 고려해야 합니다.
자주 묻는 질문 (FAQ)
Pixel Perfect Camera를 켜면 모든 오브젝트가 자동으로 선명해지나요?
아닙니다. 텍스처가 Bilinear 필터를 사용하거나 스프라이트 PPU가 불일치하면 여전히 흐릴 수 있습니다. 카메라 설정, 임포트 설정, 화면 배율을 함께 맞춰야 합니다.
픽셀 아트 게임에서 해상도 비율이 다른 모니터는 어떻게 처리하나요?
기준 해상도를 정수 배율로 확대하고 남는 영역은 레터박스 또는 필러박스로 처리하면 기준 화면 구성을 유지할 수 있습니다. 더 넓은 화면을 보여주려면 expand 같은 정책을 사용하되 전투 영역과 UI 배치가 깨지지 않는지 별도로 설계해야 합니다.
Pixel Snapping은 항상 켜야 하나요?
픽셀 단위 이동을 우선하는 게임에는 유용하지만 부드러운 추적 카메라나 보간 애니메이션에서는 움직임이 계단처럼 느껴질 수 있습니다. 실제 플레이 화면에서 켠 경우와 끈 경우를 비교해 선택하는 것이 좋습니다.
마무리
2D 픽셀 퍼펙트 렌더링은 특정 컴포넌트 하나를 추가하는 작업이 아닙니다. Point/Nearest 필터, 통일된 PPU, 기준 해상도, 정수 배율, 서브픽셀 좌표 관리를 같은 규칙으로 맞추면 도트의 선명도와 이동 안정성을 함께 확보할 수 있습니다.
새 해상도와 새로운 화면 비율을 지원할 때는 먼저 기준 해상도에서 캡처를 비교하세요. 설정 문제를 먼저 확인하면 불필요하게 스프라이트를 다시 제작하는 일을 줄이는 데 도움이 됩니다.



