Files
settled-reach/renderer/README.md
T
jpmschweitzerandClaude Opus 4.8 dae1498a6f docs(assets): ratify 3D asset direction (D-244); repurpose sprite-gen as 2D-artwork generator
D-244 ratifies what the character architecture (D-159..D-164, runtime
CharacterVisualDescriptor compositing) and the Trellis env pipeline already implied
but no decision had recorded: the in-world view renders 3D objects directly; the only
flattened 2D content is textures + flat 2D artwork (paintings/flags/billboards/signage).
There is no per-object sprite layer.

Roots out the drift: the early-spike 3D->2D sprite pipeline (#541) and the sprite-centric
docs/assets/visual catalog were never cleaned out when the project went 3D, so the
2026-06-12 fable-ous audit read them as live and re-injected the dead sprite model into
T-1049/T-1050. Fix:
- docs/assets/visual/README.md + docs/assets/README.md re-scoped to 3D models + textures
  + flat artwork (dropped the sprites/tilesets-as-entities framing).
- /sprite-gen + renderer/README repurposed as the 2D-artwork generator (paintings/flags/
  billboards/signage), not the in-world object format; legacy 4-direction object-sprite
  mode flagged as retired.
- T-961/T-1049/T-1050 already held in backlog pending this.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 22:36:13 +02:00

121 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Settled Reach — 2D Artwork Render Pipeline
> **Repurposed (D-244).** This offline Godot renderer is **not** the in-world object
> format. Per [D-244] the in-world view renders 3D objects directly (props via Trellis
> `.glb` / `/glb-gen`; characters via the Quaternius pipeline + `CharacterVisualDescriptor`);
> the only flattened 2D content is **textures** and **flat 2D artwork** (paintings, flags,
> billboards, signage). This pipeline began as the #541 3D-to-2D *sprite* spike and now
> serves that flat artwork. The "render every entity/object/wall to sprites" framing below
> is **legacy** (the retired object-sprite use); the camera / lighting / resolution mechanics
> remain usable for flat-artwork rendering.
Offline Godot 4 renderer. Produces flat 2D artwork (and, in its legacy mode, 3D-to-2D sprites) at three resolutions from a fixed camera angle, with outlines applied at working resolution.
## Camera Specification (D-019)
- **Angle**: -72.5° from horizontal (= 17.5° from vertical, the midpoint of the 15-20° from vertical range)
- **Projection**: Orthographic (`size = 1.4`)
- **Position**: `(0, 3, 1)` — above and slightly in front of the model origin
- **Godot Transform3D**: `Transform3D(1, 0, 0, 0, 0.30071, 0.95372, 0, -0.95372, 0.30071, 0, 3, 1)`
This is "the angle" per D-019 amendment (2026-02-12). All entity, object, and wall sprites for v0.1 are rendered at this angle. The Godot gameplay camera is purely orthographic — this tilt is an art convention expressed through the 3D render.
## Lighting Rig
Three-point studio rig. All lights have `shadow_enabled = false` — sprites are shape templates, no baked shadows or directional lighting. The Godot runtime PointLight2D pipeline provides all scene lighting at runtime (D-043).
| Light | Energy | Direction | Purpose |
|-------|--------|-----------|---------|
| KeyLight | 1.0 | Matches camera angle (-72.5° from horizontal) | Main illumination; ensures front face is lit as the camera sees it |
| FillLight | 0.4 | 45° from right side (-45° pitch, +90° yaw) | Fills shadow opposite the key; no deep-black patches on right face |
| RimLight | 0.3 | 45° from behind (-45° pitch, +180° yaw) | Back-edge accent; defines silhouette boundary for outline processing |
**Rationale**: Even 3-light coverage ensures no black patches on a convex mesh, keeping surface colors flat and readable for the outline processing step.
## Resolution Chain (D-043, D-044)
```
1024×1024 — source PNG, full fidelity for outline processing
↓ bilinear resize
256×256 — working PNG, outline applied at 4-8px, color #333340
↓ bilinear resize
64×64 — runtime PNG, deployed to client/assets/sprites/
```
Outline implementation: alpha-mask dilation + flat color fill. Outline width in `render_export.gd`: `outline_width_px = 4` (at 256px = 1px effective at 64px).
## Entity Footprint Spec (D-044, D-066)
- Entity sprites occupy a **24×32px footprint** within the 64×64 visual tile
- Entities render across a **2×2 sim tile sprite footprint** (D-066)
- Visual tile = 64×64px at runtime; sim tile = 32×32px (0.5m)
- **NPC model scale**: `CapsuleMesh(radius=0.25, height=0.62)` at camera size 1.4 produces ~24×32px apparent size in the 64px output tile
## Usage
### Command Line
```bash
# From the repository root
godot --path renderer/ --headless --quit-after 1200 res://render_scene.tscn -- <model_name>
```
The `/sprite-gen` skill wraps this command and handles output placement.
### Adding a New Model
1. Create `renderer/models/<model_name>.tscn` — root node is a `MeshInstance3D` (or `Node3D` with children)
2. Center the mesh at the origin
3. Use a flat `StandardMaterial3D` (no baked shadows — just albedo color + roughness)
4. Run: `godot --path renderer/ --headless --quit-after 1200 res://render_scene.tscn -- <model_name>`
5. Output: 12 PNGs in `renderer/output/` (4 directions × 3 resolutions)
6. Runtime sprites: copy 64px variants to `client/assets/sprites/`
### Material Guidelines
- **Entity sprites**: neutral flat material (albedo Color(0.5, 0.5, 0.5)). D-033 relationship color tinting applied at runtime by the client's entity renderer. Outline color (#333340 per D-043) is compatible with all D-033 tint colors — the dark blue-grey outline remains visible against teal, green, amber, and red entity tints.
- **Structural sprites**: use zone-appropriate texture (`textures/wall_institutional_era1.png`, etc.)
- No specularity: `metallic = 0.0`, `roughness = 0.9`
- No emission, no normal maps — shape is the signal
## Models
| Model | File | Type | Notes |
|-------|------|------|-------|
| `wall_structural` | `models/wall_structural.tscn` | Structure | 1.0×0.8×0.2 box, institutional era-1 texture |
| `wall_bar_green` | `models/wall_bar_green.tscn` | Structure | 1.0×0.8×0.2 box, green panel texture (model only — no sprites rendered yet) |
| `npc_generic` | `models/npc_generic.tscn` | Entity | Capsule silhouette, neutral grey, 24×32px footprint. Rotationally symmetric — north/south and east/west pairs are near-identical by design (asymmetric silhouettes come from named NPC models with identifying features per D-044). |
## Output Naming Convention
```
<model_name>_<direction>_<resolution>.png
wall_structural_north_64.png
npc_generic_south_256.png
```
Directions: `north`, `east`, `south`, `west` (model rotated 0°, 90°, 180°, 270° around Y axis).
## Runtime Sprite Path
64px sprites are deployed to: `client/assets/sprites/`
Naming convention at the client side matches the pipeline output: `<model_name>_<direction>_64.png`. The 1024 and 256 variants stay in `renderer/output/` as pipeline intermediates (gitignored).
## Design Constraints
- **No baked lighting**: sprites are shape templates. Lighting is applied at runtime by Godot's PointLight2D per D-046.
- **No baked shadows**: shadow direction would conflict with runtime point lights at arbitrary positions.
- **No baked mood**: flat materials, three-point neutral rig. Zone atmosphere comes from runtime CanvasModulate.
- **Outline applied at 256px, not 64px**: ensures outline is crisp after bilinear downscale.
- **Transparent background**: `SubViewport.transparent_bg = true` — sprites are PNG with alpha, composited at runtime.
## Cross-References
- D-019: Camera angle spec and amendment
- D-043: Art direction — "functional warmth," resolution chain, outline color
- D-044: Visual hierarchy, entity footprint spec
- D-049: Z-level rendering stack (sprites land on layers 2-3)
- D-066: Dual-scale grid, 2×2 sim tile entity footprint