Everything texture-related in one place: how the bake turns a model’s materials into the one atlas the game renders, every knob that shapes the result, the complete failure catalog (each entry hit for real), and the runtime re-skin system. Written after the Universal Tank’s “pale tank” saga (2026-07-27), in which a perfectly textured Sketchfab model shipped washed-out three separate ways at once — every cause is now either fixed in the tooling or a one-checkbox recipe below.
At bake time, each source material’s albedo is extracted to
Assets/FactorySource/<Model>/<Model>_matNN_<matname>_albedo.png (Blender-side, from the GLB/FBX’s textures).
The baker then packs all of them into one atlas (<Model>_Atlas), remaps every submesh’s UVs into its
material’s rect, merges the submeshes, and compresses to DXT1 (alpha is discarded — see the BLEND caveat).
The game renders exactly this atlas; the source textures never ship. Anything wrong at any stage — extraction,
packing, matching, remapping, post-processing — shows up as “the texture looks wrong” with very different
root causes, which is why the failure catalog below leads with symptoms.
| Knob | What it really does | Recipe guidance |
|---|---|---|
| Atlas size | The packed atlas’s max dimension. | Budget ~texture-area per material: 100 materials in a 512 = ~50px each = mush. A multi-material vehicle wants 2048. Cost: 2048 DXT1 ≈ 2.7 MB in the bundle. |
| Material mode | Single collapses everything to one material; Auto/Multi keep slots for per-material atlas rects. | Multi-material sources need Auto/Multi. NOTE: on the animated path, Multi rebuilds the mesh and needs tangents (see Animated-Models). |
| Keep black (glass/cockpit) | OFF (default) replaces every near-black texel (<32,32,32) with pale grey-blue (160,160,168) — a rescue for models whose “glass” is solid black. | Dark/camo models MUST turn this ON — otherwise every shadow, dark camo spot and rubber part paints pale grey-blue (“the washed-out tank”). |
| Albedo brightness / saturation | Post-multipliers on the packed atlas. | Leave 1/1 unless the source is uniformly too dark/garish; they cannot fix mapping problems. |
| Keep extracted texture (reuseExtracted) | The Blender step does NOT regenerate the extracted albedos. | Required whenever you hand-edit an extracted file (e.g. the white-swatch recipe below) — otherwise the next bake overwrites your edit. |
| Height-based UVs / Convert grid | Static-path shading/import options. | Static models only; see Factory-Manual. |
| Texture file (Unit Retexture) | Runtime hot-loaded PNG replacing the baked atlas. | See “Runtime re-skins” below. |
Washed-out / pale grey-blue wash over dark areas → the Keep black substitution (see knob above). The substitute color is literally (160,160,168); if your “damage” is that exact pale blue-grey, this is it.
One part samples another part’s texture (silver wheels, collaged panels) → the atlas rect-matcher
prefix-collision bug — FIXED 2026-07-27 (UniversalBaker). History for archaeology: extraction keys carry a
matNN_ prefix that the name simplifier mangled into a leading index, so the EXACT name match could never fire
for any material; everything fell to a Contains fallback where prefix families collide first-hit
(‘tank_tracks’ sampled ‘tank_tracks_13’’s rect). It was latent in every multi-material bake ever made —
most models survived because their material names don’t prefix-collide. A rebake inherits the fix.
A whole part renders flat white → the source material has no texture and no color (glTF’s default
base color is white; Sketchfab’s auto-generated ‘Merged_materials’ is the classic case). The extractor honestly
writes a tiny white swatch. Recipe: overwrite the swatch file
(<Model>_matNN_<name>_albedo.tga/png) with a flat fill of a plausible color — the average of a sibling
texture works well (flat color = UV-proof) — then bake with Keep extracted texture ✓.
Blurry/mushy everywhere but correctly mapped → atlas too small for the material count. Raise Atlas size.
Texture vanishes or renders flat although Blender shows it fine → UVs parked in a non-[0,1] integer tile
relying on texture wrap. The static path’s glbconv integer-shifts them back; the animated path folds each UV
into [0,1) at remap time. Diagnose via the OBJ’s vt range or a GLB accessor scan — if UVs span e.g.
[3.0..4.0], this was it (pre-fix bakes).
Subtle washed “dirt” layer differs from the source render → the source material is alphaMode=BLEND (Sketchfab layering: dirt/decals in alpha, blended over the layer beneath). The bake is opaque albedo-only and DXT1 drops alpha, so semi-transparent texels show raw RGB. Usually acceptable; no fix shipped yet (candidate: composite low-alpha texels over the texture’s opaque-average at atlas time).
Preview looks wrong but you suspect the bake is fine → previews flatten materials and can hold persisted
wrong texture bindings: Unity resolves FBX auto-material textures BY NAME SEARCH in the folder subtree and
writes the remap into the import settings. Two rules: (1) never place foreign FBXs inside a model’s
FactorySource folder (the raw scrubber caches live in the shared FactorySource/raw/ tree for exactly this
reason); (2) if a preview got poisoned, moving the intruder out is NOT enough — rebake the entry to
regenerate the import. The game renders baked assets, not previews: when in doubt, the in-game look is truth.
Portraits/UI images are a different system entirely — Amplitude references them by nibble-swapped
{a,b,c,d} GUIDs, which makes their path irrelevant. Since 2026-07-28 they ALL live in
Assets/Resources/Images/ (portraits of every size, tech/constructible icons, event JPGs — in-game
verified), keeping the Resources root a pure bake-output namespace. If a card ever renders magenta, the
sprite reference broke: recover the file WITH its original .meta (same GUID) — a fresh import gets a new
GUID and stays <Missing>.
Reskin an existing unit at runtime: hot-load a PNG over the baked atlas, or grey/desaturate/tint — isolated per pawn descriptor, FREE on the vertex budget (shares the mesh). Works on custom model entries too (the PNG replaces the baked atlas; adjust-only is a no-op there). Hot-loaded PNGs need a mip chain or they sparkle at distance. The window can also dump a unit’s atlas to disk — the fastest way to see exactly what the game is sampling, and the starting point for hand-painted variants.
Assets/Resources/<Model>_Atlas) — is the damage in
the atlas itself (extraction/post-processing) or only on the model (mapping)?Editor.log, lines submesh N 'mat' -> rect[N] 'matNN_name') — mismatched
names = mapping; matched names + wrong look = the texel data.FactorySource/<Model>/ — a 274-byte file is a swatch
(untextured source material); real textures are 100KB+.baseColorTexture present? alphaMode?) before blaming
the pipeline — some models are genuinely untextured or alpha-layered at the source.Cross-references: Factory-Manual.md (the windows and bake flow), Animated-Models.md (multi-material on the animated path, tangents), Animation-Pitfalls.md (the engine contract; previews lie), Vertex-Budget.md (why texture size is nearly free but meshes are not).