Add tracked AI skills for Blender assets and release QA
This commit is contained in:
1 parent
e4e1566e55
commit
724e8b183f
13 files changed
+1124
-25
No files matched your search
@@ -0,0 +1,139 @@
|
||||
# Asset Contract Reference
|
||||
|
||||
This is a working summary. The authoritative sources remain
|
||||
`docs/blender-assets.md`, `docs/asset-tooling.md`, ADR-0013, the tests in
|
||||
`src/test/tests/` and the constants in `tools/blender_assets.py` /
|
||||
`tools/npc_pipeline.py`.
|
||||
|
||||
## Library inventory
|
||||
|
||||
- **Character variants (8):** `npc_casual`, `npc_jacket`, `npc_coat`,
|
||||
`npc_vest`, `npc_dress`, `npc_hoodie`, `npc_firefighter`, `npc_guard`.
|
||||
- **Frozen fallback:** `npc_base` / `assets/models/generated/npc_base.glb`.
|
||||
- **Gear:** 18 attach-space pieces covering head, back, chest and hand items.
|
||||
- **Library props:** 20 Blender-authored props plus 6 generated props.
|
||||
- **Venues:** procedural venues in `src/game/world_builder.gd`; Blender venue
|
||||
geometry follows the same budgets and collision/provenance rules.
|
||||
|
||||
## Skeleton and geometry
|
||||
|
||||
The contract skeleton has 13 bones:
|
||||
|
||||
```text
|
||||
Head, Spine, Neck,
|
||||
HipL, HipR,
|
||||
KneeL, KneeR,
|
||||
ShoulderL, ShoulderR,
|
||||
ElbowL, ElbowR,
|
||||
HandL, HandR
|
||||
```
|
||||
|
||||
Requirements:
|
||||
|
||||
- `npc_base` mesh node exists and is skinned under `Rig`.
|
||||
- Limb node names stay stable for `NpcAvatar` and tests.
|
||||
- Front is Blender −Y / Godot +Z.
|
||||
- Feet are grounded at approximately y = 0; no floating origin.
|
||||
- Units are metres; character height is approximately 1.8 m.
|
||||
- No zero-area/duplicate degenerate faces in the exported mesh.
|
||||
- Every character has UVs in [0,1] unless a planned UDIM/atlas change is
|
||||
explicitly accepted.
|
||||
|
||||
## Material slots
|
||||
|
||||
Exactly these five tint slots:
|
||||
|
||||
```text
|
||||
skin, cloth, pants, accessory, hair
|
||||
```
|
||||
|
||||
- Neutral albedo is authored in Blender; runtime tinting is authoritative.
|
||||
- Slot names are contract values; do not rename or add a sixth slot casually.
|
||||
- The procedural fallback (`NpcAvatar._build_body`) must keep working when the
|
||||
GLB is missing.
|
||||
|
||||
## Budgets
|
||||
|
||||
| Asset | Limit |
|
||||
| --- | --- |
|
||||
| Library character | 8,000 triangles / 8,000 glTF vertices |
|
||||
| `npc_base` fallback | 6,000 triangles / 4,000 vertices |
|
||||
| Gear piece | 1,500 triangles |
|
||||
| Prop | 4,000 triangles |
|
||||
| Library prop/venue total | must stay inside the venue tests and library budget |
|
||||
|
||||
`CHAR_MAX_TRIS`, `CHAR_MAX_VERTS`, `GEAR_MAX_TRIS`, `PROP_MAX_TRIS` and related
|
||||
constants live in `tools/blender_assets.py`. The budget is per character, not an
|
||||
average. Measure after every mesh change. Do not lower the cap to make a diff
|
||||
pass.
|
||||
|
||||
## Gear and hand items
|
||||
|
||||
- Gear is authored in the attach-point space documented by `GEAR` /
|
||||
`GEAR_ATTACH` / `ATTACH_BLENDER`.
|
||||
- `blender_assets.py fit` measures gear boxes against the character's head band,
|
||||
clothing radius and back clearance.
|
||||
- Runtime offsets are intentional:
|
||||
- `NpcAvatar.GEAR_OFFSETS = {"lanyard": Vector3(0,0,0.04),
|
||||
"firefighter_helmet": Vector3(0,0.03,0)}`
|
||||
- `NpcAvatar.HAND_ITEM_FORWARD = Vector3(0,0,0.04)`
|
||||
- An offset is **not** an authored-asset change; do not bake it into the GLB
|
||||
without a separate contract decision.
|
||||
- Open-palm grip (no finger-curl rig) is the accepted stylized limit.
|
||||
|
||||
## Textures and AO
|
||||
|
||||
- NPC maps are 256² albedo + normal + packed ORM.
|
||||
- `TEX_SIZE = 256` in `tools/npc_pipeline.py`.
|
||||
- Fabric UV scale is `Materials.NPC_FABRIC_UV_SCALE = Vector3(4,4,1)`.
|
||||
- Cloth/pants skip the per-character baked AO; skin/hair/gear keep it. This
|
||||
avoids the large blotchy magnification that appeared at 256².
|
||||
- Gear/props may have their own AO maps; `tools/bake_ao.py` writes
|
||||
`<name>_ao.png` next to the GLB and Godot wires it into the AO channel.
|
||||
- Never overwrite an existing committed image; use a new `-vN` candidate and
|
||||
promote only after review.
|
||||
- Run `python3 tools/asset_pipeline.py audit <path>` and the relevant
|
||||
`npc_pipeline.py audit` before committing map changes.
|
||||
|
||||
## File map
|
||||
|
||||
| Path | Role |
|
||||
| --- | --- |
|
||||
| `tools/blender_assets.py` | Catalogue, builders, audit/fit/inspect/texels/sheet. |
|
||||
| `tools/npc_pipeline.py` | `npc_base` builder, texture preparation and audit. |
|
||||
| `tools/bake_ao.py` | Blender AO bake into `<name>_ao.png`. |
|
||||
| `tools/npc_proportions.py` | Exported-GLB proportion audit (no Blender). |
|
||||
| `tools/npc_baseline.py` | Contact sheets/comparisons (no Blender). |
|
||||
| `assets/models/blender/manifest.json` | Generated asset manifest. |
|
||||
| `assets/models/blender/**/*.glb` | Committed library assets. |
|
||||
| `assets/models/generated/npc_base.glb` | Frozen NPC fallback. |
|
||||
| `assets/textures/npc/*_{albedo,normal,orm}.png` | Committed NPC maps. |
|
||||
| `src/test/capture_npc_baseline.gd` | 48-frame neutral baseline. |
|
||||
| `src/test/capture_npc_review.gd` | 96-frame final-context review. |
|
||||
|
||||
## Provenance and source rules
|
||||
|
||||
- Procedural Blender assets are project-owned.
|
||||
- External/CC assets need ADR-0015 clearance: CC0 preferred, CC-BY only with
|
||||
attribution in `CREDITS.md`; no service assets with redistribution limits.
|
||||
- Editable `.blend` files under `assets/models/blender_src/` are gitignored;
|
||||
only exported `.glb`, AO maps, manifests and committed preview sheets ship.
|
||||
- AI-generated source images are development inputs, not shipped assets. Keep
|
||||
raw generations under gitignored paths until picked, checked and credited.
|
||||
- Do not copy a downloaded/Street View/AI reference into a committed asset
|
||||
without the licence and provenance review.
|
||||
|
||||
## Verification invariants
|
||||
|
||||
The asset pass is not complete unless:
|
||||
|
||||
1. `python3 tools/blender_assets.py audit` exits 0.
|
||||
2. `python3 tools/blender_assets.py fit` exits 0 and the report is reviewed.
|
||||
3. `python3 tools/npc_proportions.py report` passes the stylized guide.
|
||||
4. `python3 tools/npc_pipeline.py audit` passes when the base/textures changed.
|
||||
5. The 48-frame baseline and 96-frame final-context review are captured, with no
|
||||
blank frames.
|
||||
6. The 24-NPC budget smoke is inside its frame budget.
|
||||
7. The full Godot suite and Python tooling tests pass.
|
||||
8. No runtime contract, renderer or dependency changed except the rebuilt
|
||||
assets and their generated metadata.
|
||||
@@ -0,0 +1,123 @@
|
||||
# Verification Matrix
|
||||
|
||||
Run from the repository root. Stop and fix the first failure before continuing.
|
||||
|
||||
## Environment
|
||||
|
||||
```bash
|
||||
godot --version
|
||||
flatpak run org.blender.Blender --version | head -3
|
||||
git status --short
|
||||
```
|
||||
|
||||
Expected: Godot 4.7.2; Blender 5.2 LTS flatpak; clean or intentionally scoped
|
||||
working tree. Blender's flatpak cwd is `/app/blender`; all paths passed to
|
||||
Blender must be absolute.
|
||||
|
||||
## Asset checks
|
||||
|
||||
| Check | Command | Expected |
|
||||
| --- | --- | --- |
|
||||
| Contract audit | `python3 tools/blender_assets.py audit` | exit 0, no `BAD` assets |
|
||||
| Gear fit | `python3 tools/blender_assets.py fit` | exit 0; review head band/clothing/back clearances |
|
||||
| Texture/texel density | `python3 tools/blender_assets.py texels` | authored 40–400 px/m; fabric ≥250 px/m |
|
||||
| NPC base | `python3 tools/npc_pipeline.py audit` | exit 0, contract bones/slots/maps |
|
||||
| Proportions | `python3 tools/npc_proportions.py report` | all eight inside the stylized guide |
|
||||
| Single incoming GLB | `flatpak run org.blender.Blender --background --python "$PWD/tools/blender_assets.py" -- inspect --file "$PWD/path.glb" --category <cat> --json` | contract result and measurements |
|
||||
| Prop audit | `python3 tools/model_pipeline.py audit` | exit 0 when generated props changed |
|
||||
| Texture audit | `python3 tools/asset_pipeline.py audit assets/textures/ai/game_ready` | exit 0 when textures changed |
|
||||
|
||||
## Build/bake
|
||||
|
||||
```bash
|
||||
# one library asset
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/blender_assets.py" -- build --only npc_guard
|
||||
|
||||
# bake AO for the same asset
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/bake_ao.py" -- --only npc_guard
|
||||
|
||||
# NPC base material maps/base
|
||||
python3 tools/npc_pipeline.py prepare
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/npc_pipeline.py" -- build
|
||||
python3 tools/npc_pipeline.py audit
|
||||
```
|
||||
|
||||
Only run `prepare` when AI fabric inputs changed. Do not run a full library
|
||||
rebuild just to hide a small diff; build the affected asset and its AO map.
|
||||
|
||||
## Import and tests
|
||||
|
||||
```bash
|
||||
godot --headless --path . --import
|
||||
godot --headless --path . --script res://src/test/test_runner.gd
|
||||
python3 -m unittest discover -s tools/tests -t tools -p 'test_*.py'
|
||||
python3 tools/check_docs.py
|
||||
```
|
||||
|
||||
Expected: Godot suite passes; Python tooling suite passes; docs check OK. The
|
||||
project uses its own headless runner, not GUT.
|
||||
|
||||
## Capture gates
|
||||
|
||||
```bash
|
||||
# neutral studio baseline: 48 frames (8 characters x 6 views)
|
||||
godot --path . --script res://src/test/capture_npc_baseline.gd \
|
||||
-- --out=res://tmp/npc-baseline-after
|
||||
|
||||
# final-context: 96 frames (8 models x 3 distances x 2 venues x day/night)
|
||||
godot --path . --script res://src/test/capture_npc_review.gd \
|
||||
-- --out=res://tmp/npc-review-after
|
||||
|
||||
# optional hand close-up: 8 frames
|
||||
godot --path . --script res://src/test/capture_npc_baseline.gd \
|
||||
-- --out=res://tmp/npc-hands --view=hand
|
||||
```
|
||||
|
||||
Raw frames stay under `tmp/` and are never committed. Compare with:
|
||||
|
||||
```bash
|
||||
python3 tools/npc_baseline.py compare \
|
||||
--before tmp/npc-baseline --after tmp/npc-baseline-after \
|
||||
--out docs/blender_previews/sheet_npc_baseline_compare-<topic>.jpg
|
||||
```
|
||||
|
||||
Do not replace the committed baseline sheet until the change is accepted.
|
||||
|
||||
## Budget/performance
|
||||
|
||||
```bash
|
||||
godot --headless --path . --script res://src/test/smoke_npc_budget.gd
|
||||
```
|
||||
|
||||
Expected report: 24 avatars / 168 meshes / 131,616 triangles (current baseline)
|
||||
inside the 50 ms budget. Record the actual frame time; do not copy an old number
|
||||
without measuring.
|
||||
|
||||
## Visual review criteria
|
||||
|
||||
For each changed variant, inspect at least:
|
||||
|
||||
- 2 m portrait: eyes, mouth, ears, neck/shoulder, hair/headgear clearance.
|
||||
- 4.2 m conversation: hands, gear contact, clothing silhouette.
|
||||
- 8 m crowd: readable silhouette and LOD/impostor swap.
|
||||
- Day and night/LATE final-context frames.
|
||||
- Front, three-quarter and profile for a shape change.
|
||||
|
||||
Accepted stylized limits are in `docs/npc-visual-review.md` and
|
||||
`docs/known-limitations.md`. Do not turn an accepted limit into an unreviewed
|
||||
contract change.
|
||||
|
||||
## Final diff review
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
git status --short
|
||||
git diff --stat
|
||||
```
|
||||
|
||||
Check that only intended `.glb`, AO/maps, manifest, tests and docs changed. If a
|
||||
`.blend`, raw capture, generated AI input or temporary sheet is staged, stop and
|
||||
remove it. Commit one coherent asset family per commit.
|
||||
Reference in new issue
Block a user