feat: Sketchfab-to-game character pipeline, FP/TP animated views, client-auth netcode, audio system
Character pipeline (tools/): - sketchfab_import.py: search/download via Sketchfab Download API with license/attribution tracking (SKETCHFAB_API_TOKEN) - autorig.py: headless Blender auto-rig — fits a Mixamo-named skeleton to unrigged humanoids, binds automatic weights - merge_animations.py: merges the shared Mixamo-skeleton animation library onto any rigged character, strips root motion, canonical names - pipeline.py: one command chains download -> rig -> animate -> register In-game skin system: - SkinManager autoload reads skins.json (auto-written by the pipeline) - SkinnedPlayerModel rewritten: canonical clips with fallback chains, blend times, speed-scaled locomotion, weapon bone attachment - First-person: full animated body for the owner, head hidden via SkeletonModifier3D; third-person: full model for other players - Skin selector in main menu; skin id synced in multiplayer - Fixed GLBLoader crash (GLTFDocument.get_animation_count doesn't exist) Multiplayer sync overhaul: - Movement is now client-authoritative: the owning peer simulates locally (no input round-trip), server keeps health/kills/death - Remote players interpolate synced_position/velocity with extrapolation and snap-on-teleport - Knockback/impulses routed to the simulating peer Audio: - AudioManager autoload: SFX/Weapons/Footsteps/UI/Music buses, pooled 3D players, variation + pitch randomization, auto-registration from assets/sounds Docs: 3D_ASSET_PIPELINE.md rewritten end-to-end, new ASSET_SOURCES.md (non-procedural animation/map/sound sources) and SOUND_DESIGN.md. Verified with debug/spawn_smoke_test.gd (headless: 24/24 checks pass). Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
552338112e
commit
d05477c135
+117
-44
@@ -1,52 +1,125 @@
|
||||
# 3D Asset Pipeline for Papaya-Shooter
|
||||
# Character Pipeline: Sketchfab → Rigged → Animated → In-Game
|
||||
|
||||
## Blender Setup
|
||||
- Blender 5.0.1 installed system-wide
|
||||
- Blender MCP addon at ~/.config/blender/5.0/scripts/addons/blender_mcp/
|
||||
- Bridge: ~/blender-mcp/blender_bridge.py (socket port 9876)
|
||||
- Start: xvfb-run -a blender --python ~/blender-mcp/blender_server.py &
|
||||
One command turns a Sketchfab model into a playable character skin:
|
||||
|
||||
## Export Workflow
|
||||
1. Write Blender Python script (generate model, rig, animate)
|
||||
2. Run: blender --background --python script.py
|
||||
3. Export as .glb to assets/ subdirectory
|
||||
4. Godot auto-imports on editor open
|
||||
```bash
|
||||
python tools/pipeline.py --uid <sketchfab-uid> --name space_marine
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
- assets/characters/skins/ — player skin models
|
||||
- assets/characters/animations/ — animation clips
|
||||
- assets/weapons/models/ — weapon meshes
|
||||
- assets/weapons/skins/ — weapon skin textures
|
||||
- assets/props/ — level props
|
||||
That downloads the model, auto-rigs it in Blender, merges the shared
|
||||
animation library onto it, writes `assets/characters/skins/space_marine.glb`,
|
||||
and registers it in `skins.json`. Restart the game — the skin is in the main
|
||||
menu dropdown, fully animated in first AND third person, synced in multiplayer.
|
||||
|
||||
## Character System
|
||||
- HumanoidModel: characters/humanoid_model.gd
|
||||
- Procedural rig: torso, head, 4 arms, 4 legs with pivot nodes
|
||||
- States: idle, run, crouch, slide, air, wall_run, wall_cling, grapple, dash, death
|
||||
- Color: @export var color (StandardMaterial3D)
|
||||
- shadows_only for local player (don't see own model)
|
||||
- Weapon attach: set_weapon(script_path) → root_pivot child
|
||||
## Prerequisites (one-time setup)
|
||||
|
||||
## Loadout System
|
||||
- LoadoutManager: globals/loadout_manager.gd (autoload)
|
||||
- 5 slots, each: primary_1, primary_2, special, melee
|
||||
- Save: user://loadouts.json
|
||||
1. **Sketchfab API token** — from <https://sketchfab.com/settings/password>.
|
||||
Put it in the env var `SKETCHFAB_API_TOKEN`, or in a file named
|
||||
`.sketchfab_token` in the project root (gitignored).
|
||||
2. **Blender 3.6+** — on PATH, or set `BLENDER_PATH` to `blender.exe`.
|
||||
3. **Animation library** — fill `assets/characters/animations/` with one clip
|
||||
per file on the Mixamo skeleton. This is done ONCE and reused for every
|
||||
character forever. See "Building the animation library" below.
|
||||
|
||||
## Weapon System
|
||||
- WeaponManager: weapons/weapon_manager.gd
|
||||
- 1st person: SubViewport + vm_camera (layer 20)
|
||||
- 3rd person: HumanoidModel.set_weapon()
|
||||
## The pipeline, step by step
|
||||
|
||||
## Skin System (NEW)
|
||||
- Store skin metadata in loadout or player settings
|
||||
- Each skin: display_name, model_path, texture_path, color_tint
|
||||
- Apply by replacing HumanoidModel mesh nodes or swapping material
|
||||
- For full model replacement: load GLB scene, reparent to player
|
||||
Each step is also runnable on its own:
|
||||
|
||||
## Godot 4.2.1 Compatibility
|
||||
- absf() → abs()
|
||||
- fog_sky_affinity → remove
|
||||
- is not Type → not (x is Type)
|
||||
- lerpf → lerp
|
||||
- := from untyped arrays → explicit type
|
||||
- preload() on parse-error scripts → load()
|
||||
| Step | Tool | What it does |
|
||||
|---|---|---|
|
||||
| 1. Find | `python tools/sketchfab_import.py search "anime robot" --rigged` | Search downloadable models (license shown per result) |
|
||||
| 2. Download | `python tools/sketchfab_import.py download <uid>` | GLB + license/attribution JSON into `assets/characters/incoming/` |
|
||||
| 3. Auto-rig | `blender --background --python tools/autorig.py -- in.glb out.glb` | Fits a Mixamo-named skeleton, binds automatic weights |
|
||||
| 4. Animate | `blender --background --python tools/merge_animations.py -- rigged.glb assets/characters/animations out.glb` | Merges the shared clip library, strips root motion, canonical names |
|
||||
| 5. Register | (automatic in pipeline.py) | Copies to `skins/`, adds entry to `skins.json` |
|
||||
|
||||
`tools/pipeline.py` chains all of it. Useful flags:
|
||||
|
||||
- `--input file.glb` instead of `--uid` for local files (GLB/FBX/OBJ).
|
||||
- `--rigged` — skip auto-rig for models that already have a skeleton
|
||||
(Mixamo/AccuRig/Tripo output). Bones get renamed to Mixamo convention
|
||||
automatically when recognizable.
|
||||
- `--height 1.6` — target character height in meters.
|
||||
|
||||
## Auto-rigging: what to use when
|
||||
|
||||
Mixamo has **no public API** (and Adobe has said one isn't coming), so full
|
||||
automation needs an alternative. In order of preference:
|
||||
|
||||
1. **Built-in autorig (`tools/autorig.py`)** — heuristic skeleton fit +
|
||||
Blender automatic weights, fully automated, zero cost. Works well for
|
||||
normal-proportioned upright humanoids. Weakest on flowing
|
||||
dresses/capes/extreme proportions.
|
||||
2. **Mixamo web (manual, ~2 min/model)** — upload FBX/OBJ at
|
||||
<https://www.mixamo.com>, place 7 markers, download rigged FBX "without
|
||||
animations", then `pipeline.py --input rigged.fbx --rigged --name x`.
|
||||
Best weight quality for the effort.
|
||||
3. **Reallusion AccuRig** (free desktop app) — better auto-weights than
|
||||
Mixamo for tricky meshes; export FBX and feed with `--rigged`.
|
||||
4. **UniRig / Tripo AI / Meshy / Anything World** — ML auto-riggers. UniRig is
|
||||
open source (VAST/Tripo); Tripo, Meshy, and Anything World offer paid HTTP
|
||||
APIs if you ever want a fully hosted rigging step with no Blender at all.
|
||||
|
||||
All roads lead to the same place: a GLB with Mixamo bone names, which is what
|
||||
`merge_animations.py` and the game expect.
|
||||
|
||||
## Building the animation library (once)
|
||||
|
||||
The library lives in `assets/characters/animations/` — one clip per file,
|
||||
filename = clip name (`idle.fbx` → `Idle`, `crouch_walk.fbx` → `CrouchWalk`).
|
||||
|
||||
**Recommended: Mixamo clips.** Go to mixamo.com, pick the X Bot character,
|
||||
download each clip as *FBX Binary, Without Skin, 30 fps* (use "In Place"
|
||||
variants where offered):
|
||||
|
||||
| File | Mixamo search |
|
||||
|---|---|
|
||||
| `idle.fbx` | Rifle Idle (or Idle) |
|
||||
| `walk.fbx` | Walking (In Place) |
|
||||
| `run.fbx` | Rifle Run / Fast Run (In Place) |
|
||||
| `sprint.fbx` | Sprint (In Place) |
|
||||
| `jump.fbx` | Jump |
|
||||
| `fall.fbx` | Falling Idle |
|
||||
| `crouch_idle.fbx` | Crouch Idle |
|
||||
| `crouch_walk.fbx` | Crouch Walk (In Place) |
|
||||
| `slide.fbx` | Running Slide |
|
||||
| `wall_run.fbx` | (see note) Run variant works fine |
|
||||
| `dash.fbx` | Sprint or Dive |
|
||||
| `death.fbx` | Dying |
|
||||
|
||||
CC0 alternative: **Quaternius Universal Animation Library** (quaternius.com,
|
||||
500+ clips, Mixamo-compatible skeleton) or **Kenney character assets** —
|
||||
both free for commercial use, no attribution required.
|
||||
|
||||
Missing clips are fine: the game falls back along sensible chains
|
||||
(`Slide → CrouchIdle → Idle`, `WallRun → Run`, etc. — see
|
||||
`CLIP_FALLBACKS` in `characters/skinned_player_model.gd`). A model with just
|
||||
Idle/Walk/Run still animates in every movement state.
|
||||
|
||||
## How it works in-game
|
||||
|
||||
- **`SkinManager` (autoload)** reads `assets/characters/skins/skins.json` at
|
||||
boot. Selected skin persists per-user and is synced to other players via
|
||||
`synced_skin_id`.
|
||||
- **`SkinnedPlayerModel`** loads the GLB at runtime, maps canonical clip
|
||||
names, sets loop modes, blends between clips (0.15 s), and scales
|
||||
locomotion playback speed to actual movement speed.
|
||||
- **First person (owner):** full body visible and animated; the head bone is
|
||||
shrunk via a `SkeletonModifier3D` so you never see your own face — you DO
|
||||
see your legs, arms and shadow.
|
||||
- **Third person (everyone else):** the full model, driven by the synced
|
||||
movement state, with the current weapon attached to the right-hand bone.
|
||||
- **Licensing:** every Sketchfab download writes `<name>.license.json`.
|
||||
CC-BY models require crediting the author — keep these files and surface
|
||||
them in your credits screen before shipping.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- *Model T-poses in game* — the GLB has no animations; re-run
|
||||
`merge_animations.py` and check it printed `Merged N clips`.
|
||||
- *Mesh deforms badly at shoulders/hips* — heuristic rig didn't fit; rig via
|
||||
Mixamo web or AccuRig and re-run with `--rigged`.
|
||||
- *Character slides while walking* — clips exported with root motion; re-run
|
||||
without `--keep-root-motion` (stripping is the default).
|
||||
- *Skin missing in exported build* — raw `.glb` files must be included in the
|
||||
export: Project → Export → Resources → include filter `*.glb, *.json`.
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# Asset Sources — Replacing Procedural Content
|
||||
|
||||
Goal: move away from procedurally generated animations, maps, and sounds.
|
||||
Everything below is free for commercial use unless marked otherwise.
|
||||
**CC0 = no attribution needed. CC-BY = must credit the author.**
|
||||
|
||||
## Animations
|
||||
|
||||
| Source | License | Notes |
|
||||
|---|---|---|
|
||||
| [Mixamo](https://www.mixamo.com) | Free (Adobe account) | 2500+ humanoid clips, the de-facto standard skeleton this pipeline targets. No API — download clips manually once. |
|
||||
| [Quaternius Universal Animation Library](https://quaternius.com) | CC0 | 500+ clips on a Mixamo-compatible rig. Drop straight into `assets/characters/animations/`. |
|
||||
| [Kenney Character Assets](https://kenney.nl/assets) | CC0 | Simple rigged characters + basic clips. |
|
||||
| Sketchfab (filter: animated + downloadable) | per-model | Many characters ship with their own baked animations; `pipeline.py --rigged` keeps them. |
|
||||
|
||||
## Character models
|
||||
|
||||
| Source | License | Notes |
|
||||
|---|---|---|
|
||||
| [Sketchfab downloads](https://sketchfab.com/search?features=downloadable&type=models) | per-model (shown by our search tool) | Primary source — use `tools/sketchfab_import.py search`. |
|
||||
| [Quaternius](https://quaternius.com) | CC0 | Stylized low-poly packs, many pre-rigged. |
|
||||
| [KayKit](https://kaylousberg.itch.io) | CC0 | Character + dungeon packs, rigged, game-ready. |
|
||||
| [PolyPizza](https://poly.pizza) | mostly CC0/CC-BY | Searchable low-poly aggregator. |
|
||||
|
||||
## Maps / environments (replace the procedural arena)
|
||||
|
||||
| Source | License | Notes |
|
||||
|---|---|---|
|
||||
| [Kenney kits](https://kenney.nl/assets) (City, Prototype, Platformer) | CC0 | Modular kits — greybox with Prototype textures, dress with City kits. |
|
||||
| [KayKit Dungeon/City packs](https://kaylousberg.itch.io) | CC0 | Modular, snaps to grid, ideal for arena shooters. |
|
||||
| [Sketchfab scenes](https://sketchfab.com) | per-model | Whole environments exist; check poly counts before importing. |
|
||||
| [ambientCG](https://ambientcg.com) | CC0 | PBR materials/textures for level surfaces. |
|
||||
|
||||
Workflow: block out in Godot with CSG/GridMap for movement flow first, then
|
||||
replace geometry with kit pieces. Movement (wall-run surfaces, slide ramps)
|
||||
should drive layout, not the other way around.
|
||||
|
||||
## Sounds
|
||||
|
||||
See [SOUND_DESIGN.md](SOUND_DESIGN.md) for the full plan. Short list:
|
||||
|
||||
| Source | License | Notes |
|
||||
|---|---|---|
|
||||
| [Sonniss GDC Bundles](https://sonniss.com/gameaudiogdc) | Royalty-free | 100+ GB of pro game audio, free, commercial OK. THE first stop. |
|
||||
| [Kenney Audio packs](https://kenney.nl/assets?q=audio) | CC0 | UI, impacts, footsteps, sci-fi weapons. |
|
||||
| [Freesound](https://freesound.org) (filter CC0) | CC0/CC-BY | Searchable; check license per file. |
|
||||
| [BOOM Library free packs](https://www.boomlibrary.com/free-sound-effects/) | Royalty-free | Cinematic-quality freebies. |
|
||||
| [99Sounds](https://99sounds.org) | Royalty-free | Weapon/impact packs. |
|
||||
|
||||
## Attribution bookkeeping
|
||||
|
||||
- Sketchfab: `tools/sketchfab_import.py` writes `<model>.license.json` next to
|
||||
every download; the pipeline copies it beside the final skin GLB.
|
||||
- Anything CC-BY (models or sounds) must appear in a credits screen.
|
||||
Grep for license files before shipping: `ls assets/**/*.license.json`.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Sound Design Plan
|
||||
|
||||
The current sounds are procedurally generated sine/noise blends
|
||||
(`generate_sounds.py`) — functional, but robotic. This doc is the path to
|
||||
real sound design with zero budget.
|
||||
|
||||
## What's in place now
|
||||
|
||||
`AudioManager` (autoload, `globals/audio_manager.gd`) provides the plumbing
|
||||
good sound design needs:
|
||||
|
||||
- **Bus layout**: `Master ← SFX ← {Weapons, Footsteps, UI}`, `Master ← Music`
|
||||
— created automatically at boot, so volume sliders and effects (EQ,
|
||||
compression, reverb zones) can target categories.
|
||||
- **Variation playback**: drop `footstep_01.wav`, `footstep_02.wav`,
|
||||
`footstep_03.wav` into `assets/sounds/` and `AudioManager.play_3d("footstep", pos)`
|
||||
picks one at random.
|
||||
- **Pitch randomization**: every playback is pitched ±6% by default — the
|
||||
single cheapest trick to stop repeated sounds sounding fake.
|
||||
- **Pooled 3D players**: `play_3d()` is safe to call every frame; no node
|
||||
churn, no cut-off management.
|
||||
|
||||
```gdscript
|
||||
# anywhere in gameplay code:
|
||||
AudioManager.play_3d("ak47_fire", muzzle.global_position)
|
||||
AudioManager.play_ui("hit_confirm")
|
||||
```
|
||||
|
||||
## Replacing the procedural sounds (priority order)
|
||||
|
||||
Sound is ~50% of "game feel" in an FPS. Replace in this order:
|
||||
|
||||
1. **Weapon fire** (heard constantly): layered = body (low thump) + crack
|
||||
(mid transient) + tail (room reflection). Sonniss GDC packs have complete
|
||||
layered gunshots. One file per weapon is fine to start; add `_01.._03`
|
||||
variations later.
|
||||
2. **Hit confirm + kill confirm**: short, bright, satisfying (this is the
|
||||
"touchdown" pillar in the design doc).
|
||||
3. **Footsteps**: 4+ variations minimum, quieter than you think, on the
|
||||
`Footsteps` bus so they can be ducked while firing.
|
||||
4. **Movement verbs**: slide (cloth+concrete scrape), dash (air whoosh),
|
||||
wall-run loop, jump/land (land intensity scaled by fall speed).
|
||||
5. **Ambience**: a quiet room tone per map kills the "dead air" feeling.
|
||||
6. **UI**: menu hover/click/equip from a Kenney UI pack.
|
||||
|
||||
Where to get files: see [ASSET_SOURCES.md](ASSET_SOURCES.md#sounds) —
|
||||
Sonniss GDC bundles first, Kenney CC0 packs second, Freesound (CC0 filter)
|
||||
for gaps.
|
||||
|
||||
## Conventions
|
||||
|
||||
- Files: `assets/sounds/<event>[_NN].wav` — 44.1 kHz, 16-bit, mono for 3D
|
||||
positional sounds, stereo only for UI/music.
|
||||
- Ids are auto-registered from filenames at boot (`ak47_fire.wav` →
|
||||
`"ak47_fire"`). Names containing `fire`/`reload` route to the Weapons bus,
|
||||
`footstep` to Footsteps, everything else to SFX
|
||||
(see `BUS_HINTS` in audio_manager.gd).
|
||||
- Keep source loudness consistent: normalize weapon shots to about -6 dBFS
|
||||
peak, footsteps/foley around -18 dBFS.
|
||||
|
||||
## Later polish (cheap wins, in order)
|
||||
|
||||
1. Distance low-pass on the Weapons bus (far gunfire sounds muffled).
|
||||
2. A short duck (sidechain) on Footsteps/ambience when local weapon fires.
|
||||
3. Reverb `AudioEffectReverb` per-map on SFX for indoor spaces.
|
||||
4. Surface-dependent footsteps: raycast down, map material → sound id
|
||||
(`footstep_metal`, `footstep_concrete`).
|
||||
Reference in New Issue
Block a user