---
title: "Pitfalls: rendering & captures"
slug: /workflows/pitfalls-rendering/
markdown: /workflows/pitfalls-rendering.md
section: pitfalls
tier: 2
summary: "Zeroed shader globals, motion vectors, capture cameras."
sources: ['pitfalls/rendering.md']
canonical: https://unityworkflowlibrary.dev/workflows/pitfalls-rendering/
read_first: /read-first.md
---

> Read first, on every prompt: [non-destructive rules](/read-first.md).

# Pitfalls: rendering & captures

> Zeroed shader globals, motion vectors, capture cameras.

Generalized pitfalls from shipped and active projects. Record your own project's traps the same way: [Keeping a project pitfall file](/workflows/pitfall-file/). All entries LOCKED evidence. Status: locked (empirical, seen in shipped/active projects).

- **SHADER-GLOBALS-DEFAULT-TO-ZERO — an HLSL global nobody set from C# is zero, not the value you imagined.** Check: set every global at startup (or design so 0 is neutral). Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (SHADER-GLOBALS-DEFAULT-TO-ZERO): A tint global meant to default to white rendered everything black until a system pushed it.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **MANUAL-DRAWS-NEED-PREVIOUS-MATRICES — a mesh drawn by hand without a previous object-to-world matrix writes no motion vectors.** Check: pass the previous matrix (`RenderParams` / `prevObjectToWorld`) for moving manual draws. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (MANUAL-DRAWS-NEED-PREVIOUS-MATRICES): An animated falling object smeared/ghosted under TAA/upscalers.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **INCREMENTAL-UPDATES-FOR-INSTANCED-SETS — one change must not re-upload the whole instance buffer and reset motion history.** Check: dirty ranges update only changed instances. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (INCREMENTAL-UPDATES-FOR-INSTANCED-SETS): Every harvest or tile arrival rebuilt and re-uploaded a whole species' instance buffer, costing frames and resetting motion vectors.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **PIPELINE-SHADERS-ARE-NOT-ASMDEF-GATED — gating C# for one render pipeline with asmdef define constraints does not stop its `.shader` files compiling for the other pipeline.** Why: Unity compiles every shader in the project for the active target. Check: pipeline-specific shaders live in a package/folder excluded from the other pipeline's projects. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (PIPELINE-SHADERS-ARE-NOT-ASMDEF-GATED): HDRP-only shaders in a shared package broke/slowed a URP player build.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **OVERLAY-SHADERS-MUST-BE-REFERENCED — shaders used only via `Shader.Find` are stripped from player builds.** Check: add them to Always Included Shaders or reference a material. See also SHADER-VARIANTS-STRIP-IN-THE-PLAYER (the rendering page). Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (OVERLAY-SHADERS-MUST-BE-REFERENCED): Debug overlays rendered pink/nothing in a player.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **ONE-QUAD-PER-CELL-FOR-TERRAIN-OVERLAYS — a terrain overlay built as one large quad per sector floats or clips over relief.** Check: overlay meshes follow terrain cells (one quad per cell, sampled height). Status: locked (empirical, seen in shipped/active projects).
- **NO-CAMERA-PER-SHOT — do not create a camera + RenderTexture per screenshot.** Check: reuse one capture camera and target. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (NO-CAMERA-PER-SHOT): An HDRP capture loop allocated per-camera history buffers each shot and exhausted memory.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **SCENEVIEW-IS-NOT-QA — SceneView captures are smeared by its own temporal effects and debug settings.** Check: QA stills come from a game camera with production settings. Status: locked (empirical, seen in shipped/active projects).
- **WRONG-SCENE-WRONG-DIAGNOSIS — verify a look in the scene that owns it; other scenes carry their own lights and volumes.** Check: name the scene and active volume profile in every look report. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (WRONG-SCENE-WRONG-DIAGNOSIS): An orange wash investigated as a map bug came from a different scene's warm lighting/volume.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **VOLUME-PROFILES-ARE-SELF-CONTAINED — volume profiles must embed their component sub-assets; empty/null component slots break scene/game views.** Check: a validator flags null components in profiles. See also HDRP-ATMOSPHERICS-READ-AS-BUGS. Status: locked (empirical, seen in shipped/active projects).
- **CAMERA-FAR-CLIP-FITS-THE-BACKDROP — skybox/backdrop geometry must sit well inside the camera far clip.** Check: backdrop radius < far clip with margin; planetary-scale cameras raise far clip and keep a sane near. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (CAMERA-FAR-CLIP-FITS-THE-BACKDROP): A large backdrop sphere near the far plane looked like fog cutting off mid-screen.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **DIRECTIONAL-LIGHT-CANNOT-LIGHT-A-SYSTEM-MAP — a directional light aimed at the camera lights only camera-facing sides of bodies around a central star.** Check: use a point light at the star (or per-body light direction) for maps with bodies all around the source. Status: locked (empirical, seen in shipped/active projects).
- **HALF-WIRED-EFFECTS-STAY-OFF — an atmosphere/corona effect with a missing material or mesh draws as a glitched shell.** Check: optional effects default off until every input is valid; validate inputs at enable. Status: locked (empirical, seen in shipped/active projects).
- **CPU-TIMING-OF-RENDER-IS-NOT-GPU-COST — `Camera.Render` timing measures CPU submission; GPU work runs asynchronously.** Check: measure GPU time (profiler GPU module or a fence/readback). Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (CPU-TIMING-OF-RENDER-IS-NOT-GPU-COST): A benchmark "proved" a million-instance path fast.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **AN-EMPTY-RENDER-IS-FASTER-THAN-NOTHING — a renderer path that draws nothing measures faster than the baseline and looks like a win.** Check: every perf comparison asserts visible output (pixel check or draw count) first. Status: locked (empirical, seen in shipped/active projects).
- **SETTINGS-ON-DOES-NOT-MEAN-WORKING — a pipeline feature enabled in the asset (e.g. GPU Resident Drawer) proves nothing about it being active.** Check: confirm via frame debugger/stats that the feature's path is used. Status: locked (empirical, seen in shipped/active projects).
