BlueGit

golden-age paperdoll-renderer

Overview

Activity

NovDecJanFebMarAprMayJunJulAugSepOctNov

225 contributions in the last 12 months

LessMore

Commits, merge requests and comments.

paperdoll-renderer
NameLast commitLast update
assets 9f/9g: narrow fixed per-sex depth range (schema 5, .ppda v2 depth_near/far/encoding, clamp+report); light hold from raw pointer state 7 days ago
docs 9b: 60 views, per-map atlases + .ppda, Preview2d via .ppda, fps default 4; docs 7 days ago
examples 9i: result folder renders/<sex>-<settype>-atlas (newest only); build in inprogress-*, verified atomic swap, recovery; preview ignores run-* 7 days ago
packaging feat: restore live preview and build the project editor workflow 7 days ago
presets 9f/9g: narrow fixed per-sex depth range (schema 5, .ppda v2 depth_near/far/encoding, clamp+report); light hold from raw pointer state 7 days ago
renders 9f/9g: narrow fixed per-sex depth range (schema 5, .ppda v2 depth_near/far/encoding, clamp+report); light hold from raw pointer state 7 days ago
scripts Display and export static OBJ / unskinned glTF/FBX bodies 7 days ago
src 9h: Render alles queue (bodies then equipment per applicable sex), skip diagnostics, resume, cancel, summary 7 days ago
tests Atlas reader tests, cross-check helper, examples on 60 views + atlases 7 days ago
.gitattributes feat: restore live preview and build the project editor workflow 7 days ago
.gitignore ignore renders in git 7 days ago
blue-ci-cd.yml feat: restore live preview and build the project editor workflow 7 days ago
build.rs feat: restore live preview and build the project editor workflow 7 days ago
Cargo.lock feat: restore live preview and build the project editor workflow 7 days ago
Cargo.toml feat: restore live preview and build the project editor workflow 7 days ago
character.ppd 9f/9g: narrow fixed per-sex depth range (schema 5, .ppda v2 depth_near/far/encoding, clamp+report); light hold from raw pointer state 7 days ago
design.md design: narrower bounds-derived + configurable per-sex depth range (t984u) 7 days ago
LICENSE feat: add the Paperdoll Renderer foundation shell 7 days ago
README.md 9h: Render alles queue (bodies then equipment per applicable sex), skip diagnostics, resume, cancel, summary 7 days ago
rust-toolchain.toml feat: add the Paperdoll Renderer foundation shell 7 days ago
README.md

Paperdoll Renderer

Desktopeditor voor .ppd-projecten, bone-gebonden equipment en geanimeerde 3D-preview, met productie-export naar paperdoll-maps.

Starten

Rust 1.96.0 staat in rust-toolchain.toml. Op Debian/Ubuntu gebruik je voor bouwen en het venster pkg-config, libxcb1-dev, libx11-dev, libxkbcommon-dev, libxkbcommon-x11-dev en libgl1-mesa-dev. De native filepicker gebruikt XDG Desktop Portal met een GTK/KDE-backend, of Zenity. Live 3D vereist OpenGL 3.3.

cargo run
cargo run -- "/pad met spaties/character.ppd"
cargo run -- --preview-fixture
cargo run -- --status

Project en bodies

Het startvenster biedt Project laden en Nieuw project, beide met een systeembestandkiezer. Nieuw project maakt character.ppd en de mappen assets/body/, assets/equipment/, presets/, cache/ en renders/. De CC0-testlichamen worden in assets/body/ voorbereid. --preview-fixture maakt een tijdelijk voorbeeldproject en opent de mannelijke body.

De eerste projectweergave toont de bodies. Kies man / Kies vrouw selecteert een model. Een extern bestand wordt naar de projectmap gekopieerd; bij een bestaande naam krijgt de kopie een eigen naam. Modellen met bijbestanden kun je met hun relatieve mappenstructuur in de projectmap zetten en daar selecteren. Importoverzicht toont meshes, materialen, textures, joints en clips van glTF/GLB, FBX en OBJ+MTL. FBX-lichamen worden bij het laden één keer genormaliseerd (rechtshandig Y-up, meters) en daarna net als glTF/GLB in de live 3D-preview en de productierender getekend, met al hun animatiestacks als clips.

Open man / Open vrouw opent de body. Een geskind glTF/GLB- of FBX-model, of een statisch lichaam (zie hieronder), is in de live preview zichtbaar:

  • Sleep om te orbiten. Vast renderkader tonen toont het gele orthografische exportkader; stel per man/vrouw Vaste renderhoogte, Centrum Y (beeldcentrum) en Pivot Y (orbitpunt) in en sla op. Zonder handmatige pivot gebruikt de editor de rustpose-nekhoogte (of een fallback met diagnose); Auto nek wist een handmatige override. Body en equipment delen exact dezelfde camera. Uitvinken geeft vrije perspectief-preview met scrollzoom; die zoom verandert de export niet. Een echte 24-bits depthbuffer houdt voorste oppervlakken vooraan.
  • Kies een animatieclip en gebruik Pauze / Speel.
  • Yaw − / Yaw + volgen twaalf hoeken van 30°; pitch -60 / -30 / 0 / 30 / 60 kiezen de hoogte. Yaw 0 kijkt naar de voorkant van de testlichamen (−Z).
  • Render alle hoeken rendert alle animaties × alle frames op project-fps × 60 hoeken (5 pitches × 12 yaws). Na de losse maps schrijft hij per maptype een atlas plus een .ppda-bestand (zie Atlassen en .ppda). De preview wordt direct vervangen door iedere voltooide pass: highres → detail → target/diffuse → depth → normal → specular. Alle passes behouden hun aspect met gecentreerde letterboxing en nearest-neighbor weergave. Voortgang telt echte passes; Annuleer render behoudt geldige gedeeltelijke uitvoer. Live 3D keert terug naar het model; een volgende voltooide renderpass kan de preview weer vervangen.
  • Stel breedte, hoogte en fps in de Bodies-weergave in. Nieuwe projecten beginnen op 4 fps; een bestaand .ppd houdt zijn opgeslagen fps.
  • Zoek onderbroken runs (ook in de equipment-editor) toont geannuleerde, mislukte of afgebroken runs van dezelfde body/equipmentset met het aantal vastgelegde PNG's. Hervat gaat alleen verder als bronbestanden en instellingen exact gelijk zijn aan die run; anders staat erbij wat er verschilt. Na annuleren verschijnt de run direct in deze lijst. Zie Hervatten hieronder.

!Bodyweergave met animatie- en camerabediening

Statische lichamen (OBJ, glTF/FBX zonder skin)

Een lichaam zonder skin kan ook als man- of vrouwmodel gekozen worden: OBJ+MTL (met PNG-textures naast het model), glTF/GLB zonder skins en FBX zonder skin deformer. Zo'n lichaam wordt getoond en gerenderd zoals het is opgeslagen, zonder skelet of animatie:

  • OBJ en FBX lopen door dezelfde rigide lezer als equipment (FBX met dezelfde as-/eenheidsnormalisatie, één keer); bij glTF worden de node-transformaties van de scène één keer in de geometrie verwerkt (gespiegelde transformaties draaien de driehoeksvolgorde om). Animaties in een glTF zonder skin worden niet toegepast; de melding noemt hoeveel.
  • De bodyweergave meldt dat het lichaam statisch is. De animatiekeuze en Speel/Pauze zijn uitgeschakeld.
  • Pivot Y: zonder nekbot gebruikt de camera Centrum Y als orbitpunt (diagnose Statisch lichaam zonder skeleton); een handmatige Pivot Y werkt zoals bij geskinde lichamen. Vaste renderhoogte/zoom per lichaam blijft gelijk.
  • Render alle hoeken maakt één bindpose-sample clip000-bind × 60 hoeken met dezelfde vier maps (diffuse als onbelichte albedo, normal, depth, specular) op doelresolutie, plus atlassen en .ppda; de set opent via export_set en de 2D-preview.
  • Equipment heeft een bot nodig: in de equipment-editor zijn Skeleton / botten en Render equipment · alle hoeken uitgeschakeld met uitleg, en de live view tekent geen equipment op een statisch lichaam. Een equipmentrender op een statisch lichaam wordt geweigerd.

2D-preview

Vanuit Body of de bodyweergave opent 2D-preview de gerenderde compositor over de resultaatmappen renders/<geslacht>-<settype>-atlas/. De preview leest iedere export via zijn .ppda en de vier atlassen (gevalideerd, zie Atlassen en .ppda), niet via de losse PNG's. Runs zonder geldige .ppda worden overgeslagen; het aantal staat onder de exportteller, met de reden bij hover. De gedecodeerde atlassen van de huidige selectie blijven in het geheugen tot je een andere selectie kiest of Vernieuw exportsets gebruikt.

  • Kies Man / Vrouw. Alleen exportsets met dezelfde project-/rig-/exportcontract (CompatKey) zijn combineerbaar; equipment verschijnt als multiselect wanneer die contracten overeenkomen.
  • Kies een clip uit de body-exportinventaris. Speel / Pauze, snelheid en export-fps sturen een looping frame-tijd (elapsed × fps); ontbrekende maps/frames tonen een diagnose in plaats van een stille vervanging.
  • Yaw − / Yaw + wrappen over 0…330° (stap 30). Pitch − / Pitch + kiezen −60 / −30 / 0 / +30 / +60 met klemmen (start op 0). Hoekwijzigingen behouden de animatietijd.
  • Kies weergavestand Resultaat (standaard; belichte compositie), Alleen diffuse, Alleen normal map, Alleen depth map of Alleen specular map. Mapstanden tonen de diepte-gecompositeerde winnende laag onbelicht (depth als grijswaarde, normal als opgeslagen RGB). Playback, hoek en equipment werken in elke stand; licht alleen in Resultaat.
  • Houd Azimut / Elevatie ingedrukt voor continue lichtrotatie in °/s (delta-time); azimut wrapt over 360° zonder klem, elevatie blijft −80…+80. De knoppen volgen de echte muisknopstatus, dus ze blijven draaien zolang je vasthoudt (ook langer dan een seconde). Loslaten, van de knop af bewegen, focusverlies of de pointer die het venster verlaat stopt de beweging. Belichting is alleen voor Resultaat; opgeslagen diffuse blijft unlit albedo.
  • Playback loopt over exact frames / fps seconden, zodat ieder geëxporteerd frame (inclusief het laatste) even lang duurt (1/fps).
  • Het samengestelde frame gebruikt nearest-neighbor weergave met uniforme schaal en gecentreerde letterboxing, gelijk aan de productie-passpreviews.

!2D-preview op pitch +60 met een echte FBX-export via .ppda en atlassen

# Native GUI-smoke (Xvfb): synthetische export, losse PNG's verwijderd, preview via .ppda/atlassen
cargo run --example preview2d_smoke --locked -- /tmp/preview2d-smoke
# Zelfde smoke op een bestaand project met echte exports
cargo run --example preview2d_smoke --locked -- /tmp/preview2d-real /tmp/fbx-live

Equipment en opslaan

Vanuit een body opent Equipment de lijst. Kies een definitie of Nieuw.

1. Geef een unieke naam van maximaal 64 kleine letters/cijfers/-/_, zonder spaties; body is gereserveerd. 2. Kies Man / Vrouw voor het lichaam dat je bekijkt; Geldig voor bepaalt op welke geslachten het preset van toepassing is. 3. Onderdeel toevoegen (OBJ/FBX) opent de systeembestandkiezer. Rigide OBJ-onderdelen worden inclusief MTL en relatieve PNG-bijbestanden ingesloten. Rigide (niet-geskinde) FBX-onderdelen krijgen dezelfde as- en eenheidsnormalisatie als FBX-lichamen; in de FBX ingebedde PNG-textures en relatieve PNG-textures naast het model worden in het preset ingesloten. Een gekoppelde diffuse texture vervangt de FBX-diffusekleur. Geskinde FBX-meshes, morph targets en niet-PNG-textures worden met een melding geweigerd. De preview gebruikt diffuse kleur/texture en alpha-cutout (grens 0,5). Bronbestanden mogen de modelmap niet verlaten. 4. Vouw Skeleton / botten uit en kies het doelbot. Stel relatieve positie XYZ en rotatie XYZ in graden in (Rz·Ry·Rx). Het onderdeel beweegt met dat bot tijdens walk/attack of een andere geïmporteerde bodyclip. Iedere sekse heeft een eigen botbinding; de numerieke offsets zijn gedeeld. 5. Kies shinymap (PNG) moduleert de instelbare glanssterkte. Wis shinymap keert terug naar een uniforme glanssterkte. Vul desgewenst Herkomst / licentie in. Meerdere onderdelen kunnen verschillende botten gebruiken. 6. Opslaan bewaart het project plus zelfbevattende binaire .ppe-snapshots in presets/ (geometrie, bronpayloads, materialen/textures, transformaties, bindingen, seksevlaggen en herkomst). Er worden geen bronpaden buiten het project nodig om die opnieuw te laden.

Preset importeren leest een .ppe uit bijvoorbeeld een ander project. Bij een andere rig moet je de botten opnieuw kiezen; er wordt niet stil geretarget. Onvolledige configuraties kunnen worden opgeslagen, maar onopgeloste onderdelen worden niet op een gegist bot getekend. Verwijder onderdeel haalt een onderdeel uit het werkpreset; Verwijder equipmentdefinitie haalt de definitie uit de projectlijst. Oude project-snapshots blijven voor herstel bewaard. Opslaan vereist een bestandssysteem met hardlinks; bij een fout wordt een bestaande snapshot niet overschreven.

Een preset is begrensd op 32 MiB, 32 onderdelen/bestanden en textures van maximaal 2048×2048. Een project heeft maximaal 64 presets en 64 MiB aan presetbestanden. De volledige containerbeschrijving staat in design.md.

# Zelfbevattend CC0-zwaardvoorbeeld in een nieuw tijdelijk project
cargo run --example equipment_fixture --locked

!Werkelijke equipment-editor met geanimeerd lichaam en handgebonden OBJ

Bij sluiten of Ander project / Nieuw project met wijzigingen kies je Opslaan, Niet opslaan of Annuleren. Als opslaan mislukt, blijft het project open. Annuleren in de bestandkiezer behoudt je huidige werk.

Productie-output

Render alles

Render alles in het Body-scherm rendert het hele project in één wachtrij: eerst het mannelijke en vrouwelijke lichaam (als ingesteld), daarna ieder equipment-preset voor elk geslacht waarvoor het geldt. Elk item krijgt de volledige export (alle clips × frames × 60 hoeken, vier maps, atlassen + .ppda) naar zijn eigen renders/<geslacht>-<settype>-atlas/. De voortgang toont item k/n plus de gewone passtelling; Annuleer render stopt de wachtrij (het lopende item blijft hervatbaar, de rest staat als niet gestart). Heeft een item een passende onderbroken run, dan wordt die hervat in plaats van opnieuw begonnen. Items die niet kunnen (geen lichaam, equipment niet geconfigureerd of zonder onderdelen, ongeldige instellingen) worden met reden overgeslagen en de wachtrij gaat door. Na afloop staat een samenvatting met wat gerenderd, overgeslagen, mislukt of niet gestart is.

De bodyknop rendert alleen het lichaam; Render equipment alle hoeken in de equipment-editor rendert het geselecteerde preset, geanimeerd op het gekozen lichaam maar zonder body-occlusie of bodypixels. De vaste camera van dat geslacht blijft gelijk, ook als je in de live preview vrij hebt ingezoomd.

Per beeld worden alleen vier target-res PNGs opgeslagen: diffuse, normal, depth, specular. Diffuse is onbelichte albedo (basiskleur/texture × vertexkleur, alpha behouden), nooit ingebakken lighting/schaduw/glans. Depth is lineaire 16-bit grayscale+alpha binnen een vast, smal dieptebereik per geslacht rond het orbitpunt: near/far = 10 m ∓ R, met R = halve renderhoogte + |pivot Y − centrum Y| (minimaal 0,5 m); bij 2,6 m hoogte en nekpivot 1,46 m dus ca. 8,24–11,76 m. Alle clips, frames, hoeken en equipment van dat geslacht delen hetzelfde bereik; afstand = near + (grijs/65535)·(far − near). Geometrie buiten het bereik wordt geklemd (niet weggeknipt) en gemeld in de voortgang en in complete.json (depth_clamped); normal is view-space RGB+alpha; specular is lineaire sterkte (body nul, equipment inclusief ingestelde shinymap). Highres en detail zijn uitsluitend zichtbare hulpstappen en worden niet opgeslagen.

renders/male-body-atlas/male/body/clip001-walk/f000012/p-60_y330_diffuse.png
renders/male-body-atlas/male-body-diffuse-atlas.png   (en -normal, -depth, -specular)
renders/male-body-atlas/male-body-atlas.ppda

Per geslacht en settype is er één resultaatmap renders/<geslacht>-<settype>-atlas/ met alleen de nieuwste volledige render. Een render wordt opgebouwd in een tijdelijke map renders/inprogress-<tijd>-<pid>-<geslacht>-<settype>/. Pas als die volledig is en de atlassen/.ppda gecontroleerd zijn, wordt de vorige resultaatmap opzijgezet (.replaced-…), de nieuwe op zijn plaats hernoemd en de oude verwijderd. Bij annuleren, een fout of een crash blijft de laatste goede resultaatmap dus staan. Een onderbroken wissel wordt bij de volgende render hersteld: een opzijgezette oude map komt terug, en een voltooide maar nog niet geplaatste render wordt alsnog geplaatst. Oude run-*-mappen van eerdere versies worden niet automatisch verwijderd; de 2D-preview negeert ze met een melding. render.json (schema 5; met depth_near, depth_far, depth_encoding) beschrijft projectidentiteit, bronfingerprints (SHA-256 van bodybestand en optioneel encoded equipment), camera/pivot/sample/materiaalcontract (pitches −60…+60, yaws 0…330), clipinventaris en telling. Alleen complete.json (zelfde schema, met per-PNG SHA-256 en de namen en SHA-256 van atlassen en .ppda) betekent een volledige set. Exports met een ouder schema (o.a. schema 4 met het oude globale bereik 0,05–40 m) worden door de lezers geweigerd en niet gemengd; render die opnieuw. cancelled.json/failed.json markeren een gedeeltelijke run zonder compleet-marker. De bibliotheekmodule export_set opent uitsluitend voltooide runs met overeenkomende identiteit en geverifieerde checksums, en leest de echte RGBA8-/depth16-maps met strikte pad-/formaatvalidatie. De map-/camera-/pixelcontracten staan in design.md.

Atlassen en .ppda

Als alle losse maps klaar en geverifieerd zijn, ook na hervatten, schrijft de render per maptype één atlas in de (tijdelijke) runmap: <geslacht>-<settype>-<maptype>-atlas.png (bijv. male-sword-normal-atlas.png). Daarna volgt <geslacht>-<settype>-atlas.ppda, en pas daarna complete.json.

  • Een cel is exact de doelresolutie, zonder rand of schaling. Iedere rij is één (clip, frame) in bronvolgorde. De 60 kolommen zijn pitch −60→+60 en daarbinnen yaw 0→330. De vier atlassen hebben dezelfde celcoördinaten. Diffuse houdt het sRGB-kenmerk; depth blijft 16-bit grijs+alpha.
  • De atlassen worden rij voor rij uit de geverifieerde losse PNG's opgebouwd, atomair gepubliceerd en overschrijven niets. Staat er na een crash al een atlas, dan blijft die staan als hij byte-gelijk is aan de nieuwe; anders wordt hij als .corrupt-aNNN-K bewaard en opnieuw geschreven.
  • Wordt een atlas groter dan 16384 pixels in breedte of hoogte, dan weigert de render vóór de start met een duidelijke melding (verlaag fps, resolutie of animatieduur). Atlassen worden nooit gesplitst.
  • .ppda (PaPerDollAtlas) is strikte UTF-8 JSON met format_version 2, sex, settype, project (id/naam), identity (body- en equipment-SHA-256, framing, pivotbron, near/far, cameraafstand, normal- en depthcodering), fps, depth_near/depth_far (meters bij grijs 0 / 65535) en depth_encoding, cell_width/cell_height, pitches, yaws, maps (per maptype bestandsnaam, SHA-256, breedte, hoogte) en clips (bronindex, naam, token, frame_count, duration en per frame alle 60 hoeken als {pitch, yaw, x, y, w, h} in atlaspixels).
  • De bibliotheeklezer atlas::AtlasSet weigert onbekende velden of versies, bestandsnamen die niet de verwachte naam in dezelfde map zijn, symlinks, afwijkende atlasafmetingen of kleurtypes, celcoördinaten die niet op het raster liggen en SHA-256-fouten. load() decodeert de vier atlassen met dezelfde pixelregels als de losse maps; cell() knipt één hoek eruit. atlas::cross_check_run vergelijkt iedere atlascel met de losse PNG.

Hervatten

Een hervatte run schrijft verder in dezelfde tijdelijke inprogress-*-map; de resultaatmap blijft onaangeroerd tot de run klaar is.

  • Elke run houdt progress.jsonl bij: per gepubliceerde PNG het pad en de SHA-256. run.lock voorkomt dat twee renders tegelijk in dezelfde run schrijven.
  • Hervatten kan alleen als render.json exact overeenkomt met wat de huidige job zou schrijven: project, geslacht/set, SHA-256 van body en equipment, target, fps, framing/pivot, camera, clips en maps. Een voltooide, vergrendelde of afwijkende run wordt geweigerd.
  • Vóór het renderen wordt iedere geplande PNG gecontroleerd. Bestanden met een kloppende checksum blijven ongewijzigd en worden niet opnieuw gerenderd. Ontbrekende bestanden worden opnieuw gemaakt. Beschadigde bestanden worden hernoemd naar <naam>.corrupt-aNNN-K en daarna opnieuw gemaakt; ze worden niet verwijderd. Een bestaand bestand zonder journalregel (crash tussen schrijven en vastleggen) blijft staan als de opnieuw gerenderde bytes gelijk zijn. Achtergebleven .part-*-bestanden worden niet aangeraakt.
  • Na de losse maps worden de atlassen en .ppda geschreven (zie hierboven).
  • De voortgang begint bij het werk dat al klopt; overgeslagen beelden heten al aanwezig, checksums kloppen. Je kunt opnieuw annuleren en later weer hervatten. Een vorige cancelled.json/failed.json wordt bewaard als attempt-NNN-…json, en resume.jsonl legt per poging vast wat geverifieerd, ontbrekend en in quarantaine gezet is. Pas als alles klopt, wordt complete.json met alle checksums geschreven.

!Onderbroken run hervatten in de bodyweergave

2D depth-compositor (bibliotheek)

De module compositor combineert een body-export met nul of meer compatibele equipment-exports (zelfde project-id, geslacht, body-fingerprint, target, fps, framing, near/far en clipinventaris, gelezen uit export_set of uit de .ppda). Per pixel wint het dichtstbijzijnde geldige oppervlak (depth gray dichterbij = kleiner; epsilon DEPTH_EPSILON_U16 = 1 depthcode; bij gelijke diepte wint de laagste laagindex — geef body eerst, daarna equipment op vaste naamvolgorde). Diffuse, normal en specular komen altijd uit dezelfde winnende laag. Soft alpha van die winnaar blijft behouden; verliezende lagen mixen niet mee (single-depth kan geen willekeurige doorschijnendheid reconstrueren).

relight / compose_and_relight past lineaire ambient + Lambert diffuse + Blinn-Phong specular toe. De lichtvektor staat al in view-space, gelijk aan de geëxporteerde normal maps. Er is geen randlicht: de preview toont alleen deze relight in stand Resultaat. Opgeslagen diffuse blijft elders onbelichte albedo.

use paperdoll_renderer::compositor::{
    assert_compatible, compose_and_relight, LayerMaps, Light,
};
use paperdoll_renderer::export_set::ExportRun;

let body = ExportRun::open(&body_run_dir)?;
let sword = ExportRun::open(&sword_run_dir)?;
assert_compatible(&[&body, &sword])?;
let layers = [
    LayerMaps::from_export_run(&body, "body", "clip000-walk", 0, 0, 0)?,
    LayerMaps::from_export_run(&sword, "sword", "clip000-walk", 0, 0, 0)?,
];
let (maps, lit_rgba) = compose_and_relight(&layers, &Light::default())?;

// Zelfde lagen via de consumentenvorm (.ppda + atlassen):
use paperdoll_renderer::atlas::AtlasSet;
let body = AtlasSet::open_run(&body_run_dir)?.load()?;
let layer = LayerMaps::from_atlas(&body, "body", "clip000-walk", 0, 60, 330)?;

Highres is exact 8× beide assen; batch-targets zijn momenteel 1–256 pixels per as (highres max 2048). Grotere projectinstellingen geven een duidelijke renderfout, geen stil verkleinde supersampling. Maximaal 500000 PNGs / 16 GiB geschatte ongecomprimeerde targetdata per run; output vereist hardlinks. Productie rendert de eerste skinned glTF/GLB-mesh met driehoekprimitieven, basiskleur/8-bit albedotextures en vertexkleuren. Een FBX-lichaam loopt via de genormaliseerde scene (fbx_scene) door dezelfde batch: alle animatiestacks × frames × 60 hoeken, dezelfde vaste camera, nekpivot en vaste zoom per lichaam, en dezelfde vier maps. Equipment hangt op de geanimeerde botten van dat FBX-skelet. Statische lichamen renderen één bindpose-sample per hoek (zie Statische lichamen). Live placement blijft een belichte, vereenvoudigde weergave.

Openen met

  • Windows: start de uitgepakte .exe eenmaal om de editor voor het huidige account aan Openen met toe te voegen. Kies daarna bij een .ppd Openen met → Paperdoll Renderer (of selecteer de .exe via Bladeren).
  • Debian/Arch: de pakketten installeren de .ppd-MIME-koppeling, desktopstarter en iconen. Kies de editor in Openen met.
  • Linux AppImage/losse binary: bewaar het bestand op zijn vaste plek en voer "/pad/Paperdoll.AppImage" --install-desktop uit. Hiervoor zijn shared-mime-info en desktop-file-utils nodig. Daarna staat de editor in Openen met. Herhaal dit na verplaatsen van de AppImage.

Het venster, de Linux-starter en de Windows-executable gebruiken Tims applicatie-icoon.

Tests

cargo fmt --check
cargo check --workspace --all-targets --locked
cargo clippy --workspace --all-targets --locked -- -D warnings
cargo test --workspace --locked
# Linux GPU-regressie: echte depth-occlusie, normal/depth/specular en lichtonafhankelijke albedo
xvfb-run -a cargo run --example preview_depth_probe --locked
# Productie op echte GPU (body of equipment); controleert daarna iedere atlascel tegen de losse PNG
xvfb-run -a cargo run --example production_fixture --locked -- /tmp/prod tests/fixtures/bodies/test-body-male.glb tests/fixtures/bodies/test-body-female.glb male 32 48 4
# Hervatten op echte GPU: setup, render met crash (abort) of annulering, hervatten, export_set- en atlascontrole
cargo run --release --example resume_fixture --locked -- setup /tmp/resume tests/fixtures/bodies/test-body-male.glb tests/fixtures/bodies/test-body-female.glb 32 32 2
xvfb-run -a cargo run --release --example resume_fixture --locked -- render /tmp/resume male --abort-after=200
xvfb-run -a cargo run --release --example resume_fixture --locked -- resume /tmp/resume male
cargo run --release --example resume_fixture --locked -- verify /tmp/resume
# FBX op echte GPU: live view (lichaam + FBX-zwaard) en volledige productie van body- en equipmentset
xvfb-run -a cargo run --example fbx_live_fixture --locked -- /tmp/fbx-live /tmp/fbx-live-proof 32 48 4
# Statische lichamen op echte GPU: OBJ-man en glTF-vrouw zonder skin, live view, equipment-weigering, productie en export_set
xvfb-run -a -s '-screen 0 1280x1024x24' cargo run --example static_body_fixture --locked -- /tmp/static-body /tmp/static-body-proof 32 48 4

De testlichamen komen uit scripts/generate_test_bodies.py. Het FBX-testbestand wordt met Blender via scripts/convert_test_body_to_fbx.py gemaakt. De rigide FBX-zwaarden (sword-fbx.fbx met ingebedde PNG, sword-fbx-external.fbx met PNG ernaast) komen uit scripts/make_fbx_equipment_fixture.py (Blender, Z-up geëxporteerd). De statische lichamen in tests/fixtures/bodies/static/ (OBJ+MTL+PNG en een GLB zonder skin) komen uit scripts/generate_static_bodies.py.