Set up, diagnose, and fix pixel perfect 2D rendering in Unity projects.
⚠️ There Are Two Completely Separate Implementations
Pixel perfect rendering in Unity is not one system — it is two separate, incompatible implementations, one per render pipeline. Always detect the pipeline before writing or diagnosing any code.
| URP | Built-in |
|---|
| Component | UnityEngine.Rendering.Universal.PixelPerfectCamera
| UnityEngine.U2D.PixelPerfectCamera
|
| Package | Built into URP — no extra install | com.unity.2d.pixel-perfect
v6.0.0+ |
| API style | Enums (, ) | Booleans (, , ) |
Do not install com.unity.2d.pixel-perfect
in a URP project.
→ Always call first (
references/pipeline-detection.cs
), then branch your setup, diagnostics, and fixes based on the result.
When NOT to use this skill
- HD 2D or high-resolution 2D games — pixel snapping and point filtering will make smooth art look wrong
- UI-only scenes — use Canvas Scaler instead
- HDRP projects — Pixel Perfect Camera is not supported
Critical Reminders
⚠️ Detect the render pipeline first — URP and Built-in use different Pixel Perfect Camera components that are not interchangeable.
⚠️ Filter Mode = Point is the #1 fix — bilinear filtering is Unity's default and is almost always the cause of blurry sprites.
⚠️ Anti-Aliasing must be disabled — in Quality Settings and on the camera. AA actively blurs pixel edges.
Key Principles
1. Pipeline Detection & Camera Component Selection
See the two-path comparison table at the top of this file. Assembly name note: the standalone Built-in package installs into a
folder, but the asmdef
field is
— no
suffix. HDRP is unsupported — see the HDRP fallback section under Common Issues.
→ Code: references/pipeline-detection.cs
—
,
GetPixelPerfectCameraType()
, and migration mismatch check.
2. Diagnostic-First Approach
Always diagnose before making changes. Report findings, then fix only what is broken.
3. Work in the correct scope
Default to scene scope. Scan project-wide only when the user explicitly requests it.
Diagnostic Checklist
Sprite import settings:
→ Code: references/sprite-settings.cs
—
and
FixSpriteImportSettings()
.
Editor snap settings:
Camera setup:
→ Code: references/camera-setup-urp.cs
— full URP camera + PP Camera configuration.
→ Code: references/camera-setup-builtin.cs
— Built-in standalone configuration.
Project quality settings:
API Reference
Full property/method tables,
and
enum values, and recommended configurations:
→ references/api-reference.md
— read this when writing or reviewing camera setup code.
Quick enum summary:
:
·
(standard) ·
(authentic low-res; incompatible with post-processing and UI text)
:
·
·
·
(safest default) ·
Reference Resolution
Choose before building any assets. Never change after asset production starts.
| Reference resolution | 1080p | 1440p | 4K |
|---|
| 320 × 180 | 6× | 8× | 12× |
| 480 × 270 | 4× | ~5.3× | 8× |
| 640 × 360 | 3× | 4× | 6× |
320×180 is the safest general choice. For screens with no integer fit (e.g. 1366×768), use
to add black bars rather than stretching to a fractional scale.
Migration & Compatibility
URP project with the Built-in standalone component
Symptom:
returns URP but camera has
UnityEngine.U2D.PixelPerfectCamera
. Symptoms are subtle because the standalone component has
conditional code.
Fix:
- Remove
com.unity.2d.pixel-perfect
from Package Manager
- Remove
UnityEngine.U2D.PixelPerfectCamera
from each camera
- Add
UnityEngine.Rendering.Universal.PixelPerfectCamera
- Reconfigure — booleans (, , ) become enums (, )
→ Detection code: references/pipeline-detection.cs
(bottom of file).
Old URP namespace (pre-Unity 2022 / URP pre-13.x)
Symptom: Compiler errors referencing
UnityEngine.Experimental.Rendering.Universal
.
Fix: Replace
using UnityEngine.Experimental.Rendering.Universal;
with
using UnityEngine.Rendering.Universal;
. Update any assembly-qualified type strings. The
attribute handles serialization automatically — components on GameObjects survive the upgrade.
Common Issues & Solutions
Blurry sprites
Fix: Set Filter Mode to Point on all in-scope sprites, disable Mip Maps, disable AA in Quality Settings.
→ Code: references/sprite-settings.cs
Tilemap gaps between tiles
Work through in order — workarounds like negative cell gap or PPU = 31.99 break when the camera moves.
| # | Check | Fix |
|---|
| 1 | Sprite Atlas with Tight Packing off, Padding ≥ 4, Sprite Packer Mode enabled? | Enable Sprite Packer Mode in Editor settings; on the atlas set Padding ≥ 4 and turn Tight Packing off |
| 2 | Mipmaps disabled on tileset textures and atlas? | Disable Generate Mip Maps |
| 3 | AA = 0, MSAA off on camera? | Disable AA globally |
| 4 | Compression = None? | RGBA 32-bit uncompressed |
| 5 | All tile sprites have even pixel dimensions? | Odd dimensions cause 0.5px grid offset |
| 6 | PPU = tile pixel width? (16×16 → PPU 16) | PPU mismatch leaves physical gaps |
| 7 | Gaps only during camera movement after all above pass? | Use PP Camera pixel snapping; do not use |
Cinemachine conflict
Cause: Both Cinemachine and the Pixel Perfect Camera write to orthographic size every frame.
Fix: Add
extension via the Add Extension dropdown on each Virtual Camera. Do not add it via
in code.
Known limitations:
- Camera blends between virtual cameras are not pixel-perfect during transitions
- reduces valid pixel-perfect ortho sizes, which may cause framing to deviate
- Target Group + Framing Transposer causes visible choppiness (no fix available)
Post-processing blur with
Cause: Post-processing runs after the PP Camera upscales the render texture.
Simple fix: Disable
. Post-processing then runs at native screen resolution.
Advanced fix (Unity 6 URP): Inject a
ScriptableRendererFeature2D
at
RenderPassEvent2D.AfterRenderingPostProcessing
. Use 2D-specific base classes —
ScriptableRendererFeature
(3D base class) is silently ignored in a URP 2D renderer.
UI text blurry with
Status: Known Unity bug, declined to fix (still present Unity 6, 2025).
Root causes: (A) Canvas renders into the low-res buffer and is upscaled with the scene. (B) TMP's SDF gradient threshold is miscalibrated at low reference resolutions.
Fixes in order of reliability:
- on Canvas — bypasses the camera, renders at native resolution
- Dedicated UI camera with no PP Camera component, mode
- Unity 6 only:
Font Material → Debug Settings → Sharpness = 1
(mitigates B, not A)
Physics / render desync (micro-stutter)
Cause: Physics runs at a fixed timestep; interpolated positions produce fractional values that snap to different pixels each frame.
Fix:
- Enable
Rigidbody2D.interpolation = RigidbodyInterpolation2D.Interpolate
on physics-driven sprites
- Set
Time.fixedDeltaTime = 1f / 60f
to match target frame rate
- Keep camera tracking in , not
Non-integer scaling / pixel decimation
Cause: Screen resolution is not a clean integer multiple of the reference resolution.
Fix: Choose a reference resolution from the table above. Use
when no integer fit exists.
Missing URP 2D Renderer
Fix:
Assets > Create > Rendering > URP 2D Renderer Data
- Assign it to your URP Asset under Renderer List
- Requires
com.unity.render-pipelines.universal
12.0+
HDRP fallback
Pixel Perfect Camera is unsupported in HDRP.
Built-in / Unity 5.x: Use
+
with
.
Unity 6 URP: Use
ScriptableRendererFeature2D
+
injected at
RenderPassEvent2D.AfterRendering
with
. Note:
and
are incompatible with Unity 6's render graph.