From a1f5989cbb35235aecb3dbb3b9b450b73303a779 Mon Sep 17 00:00:00 2001 From: Zwitschi Date: Mon, 9 Nov 2026 10:56:43 +0100 Subject: [PATCH] =?UTF-8?q?fix(anim):=20the=20clip=20now=20drives=20the=20?= =?UTF-8?q?body=20=E2=80=94=20two=20causes,=20both=20measured?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The body stood in an A-pose while the log said the clip was playing. Two independent defects, found by querying the imported asset instead of guessing: 1. PlayAnimation needs the component in AnimationSingleNode with a live single-node instance. The body is hidden at construction and only unhidden by the camera toggle, so the first call could land before the component was ready, and the Wanted == PlayingAnimation guard then returned forever. UpdateBodyAnimation now sets the mode, calls SetAnimation + Play, and re-asserts while the instance is missing. 2. The arms-down offsets lived only in the clip keys. The exporter writes clip data relative to the rest pose, so they arrived as a ±20 degree swing around an A-posed bind - which is exactly what the pose probe measured. apply_base_pose now bakes them into the rest pose before any clip is authored, the same trick mpfb_character_export.py --pose idle uses. The table is applied with inverted signs: as written, the FBX axis mapping produced arms raised in a V. Shot 6 confirms it: the arms hang at the sides. Still open and recorded - the idle pose reads awkwardly (arms forward, hands splayed) and the walk clip has no shot in motion; both are marked in TODO.md and Screenshots/README.md. Instrumentation removed; the diagnostics that remain are behind gigline.SetupLogs. --- Game/GigLine/Content/Hollywood/DemoMap.umap | 4 +-- .../Content/Hollywood/Site/M_Asphalt.uasset | 2 +- .../Content/Hollywood/Site/M_Concrete.uasset | 2 +- .../Hollywood/Site/M_FacadeBanner.uasset | 2 +- .../Hollywood/Site/M_FacadeGlass.uasset | 2 +- .../Hollywood/Site/M_FacadeStone.uasset | 2 +- .../Hollywood/Site/M_FacadeStoneShadow.uasset | 2 +- .../Content/Hollywood/Site/M_Ground.uasset | 2 +- .../Hollywood/Site/M_KerbConcrete.uasset | 2 +- .../Content/Hollywood/Site/M_RoadPaint.uasset | 2 +- .../Content/Hollywood/Site/M_Stucco.uasset | 2 +- .../Content/Hollywood/Site/Terrain_DEM.uasset | 2 +- .../Hollywood/Textures/T_Asphalt_BC.uasset | 2 +- .../Hollywood/Textures/T_Asphalt_R.uasset | 2 +- .../Hollywood/Textures/T_Concrete_BC.uasset | 2 +- .../Hollywood/Textures/T_Concrete_R.uasset | 2 +- .../Textures/T_StoneAshlar_BC.uasset | 2 +- .../Hollywood/Textures/T_StoneAshlar_R.uasset | 2 +- .../Hollywood/Textures/T_Stucco_BC.uasset | 2 +- .../Hollywood/Textures/T_Stucco_R.uasset | 2 +- .../Theatre/SM_Trim_BladeSign.uasset | 2 +- .../Theatre/SM_Trim_BladeSignBracket.uasset | 2 +- .../Theatre/SM_Trim_BladeSignFrame.uasset | 2 +- .../Theatre/SM_Trim_MarqueeCanopy.uasset | 2 +- .../Theatre/SM_Trim_MarqueeFascia.uasset | 2 +- .../Theatre/SM_Trim_MarqueeSoffit.uasset | 2 +- .../Test/Character/Character_Anim.uasset | 4 +-- Game/GigLine/Content/Test/ReviewMap.umap | 4 +-- .../Source/GigLine/GigLineCharacter.cpp | 31 +++++++++++++---- MEMORY.md | 4 +++ Screenshots/README.md | 17 ++++++---- Screenshots/demo/review-demo-crossing.png | 4 +-- .../demo/review-demo-north-buildings.png | 4 +-- .../demo/review-demo-retail-frontage.png | 4 +-- Screenshots/demo/review-demo-spawn-view.png | 4 +-- Screenshots/demo/review-demo-street-level.png | 4 +-- Screenshots/demo/review-demo-third-person.png | 4 +-- TODO.md | 2 +- Tools/character_anim_build.py | 34 +++++++++++++++++-- 39 files changed, 115 insertions(+), 59 deletions(-) diff --git a/Game/GigLine/Content/Hollywood/DemoMap.umap b/Game/GigLine/Content/Hollywood/DemoMap.umap index 793795e..b4d0002 100644 --- a/Game/GigLine/Content/Hollywood/DemoMap.umap +++ b/Game/GigLine/Content/Hollywood/DemoMap.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3cadf24b327116118550a7fb62dd6cc1cc748e152959ed2cdcf3a1de64bb4bb0 -size 781914 +oid sha256:bd5ce81994dceab0d0d53a34086cc8a38f90c044b8be0ef199dda9ac35fd53ce +size 781960 diff --git a/Game/GigLine/Content/Hollywood/Site/M_Asphalt.uasset b/Game/GigLine/Content/Hollywood/Site/M_Asphalt.uasset index fa2a3e5..df02059 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_Asphalt.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_Asphalt.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fcf355af961bd5f0c50d9dd5f9f680e64ad23327cd4934831a0c23644b3af20c +oid sha256:bbe722b3f217de9bb5418c7756d0d267db345f30b513baac6d8d0eb58b2d30a9 size 10019 diff --git a/Game/GigLine/Content/Hollywood/Site/M_Concrete.uasset b/Game/GigLine/Content/Hollywood/Site/M_Concrete.uasset index 10f810e..ad201f1 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_Concrete.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_Concrete.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe5db22b218b38420b546ee75e1f10128f3735ff9679ec42350405cc741bc55f +oid sha256:e988e4fbfd8e70e1299639802d7545a6285c9ae83a18ad365b357a923bfbaf81 size 10024 diff --git a/Game/GigLine/Content/Hollywood/Site/M_FacadeBanner.uasset b/Game/GigLine/Content/Hollywood/Site/M_FacadeBanner.uasset index ea83fb9..1721e23 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_FacadeBanner.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_FacadeBanner.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8396d7101a43df58b845b2c9fdf745c11ed8aa8d2703f603fde038ae37472765 +oid sha256:cc344d87142e61c32690b9c539540804c9197b0ad3d46ddce8ec217ad51eb733 size 11419 diff --git a/Game/GigLine/Content/Hollywood/Site/M_FacadeGlass.uasset b/Game/GigLine/Content/Hollywood/Site/M_FacadeGlass.uasset index fe9c91f..6e35ebb 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_FacadeGlass.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_FacadeGlass.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c07c6cd2ebe7f984196757043e6c16a092a154b7dae33b8c3f11113a78e42fd2 +oid sha256:52206ebbef1dc94e3c23a4aa7f100859e9ae084781e226d78a809cdb3e235b89 size 11414 diff --git a/Game/GigLine/Content/Hollywood/Site/M_FacadeStone.uasset b/Game/GigLine/Content/Hollywood/Site/M_FacadeStone.uasset index 810d776..b033084 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_FacadeStone.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_FacadeStone.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3229e39839dfd7cfbe787cddc4337399ecfb7bc25c1364057db38cfd34d07c5b +oid sha256:58912f4e53835576a6be2fe271d76bb03b085227c8f4f68cd09f313cc07df82c size 17083 diff --git a/Game/GigLine/Content/Hollywood/Site/M_FacadeStoneShadow.uasset b/Game/GigLine/Content/Hollywood/Site/M_FacadeStoneShadow.uasset index de97c69..58f2424 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_FacadeStoneShadow.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_FacadeStoneShadow.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8dd4749d4946a34cd333320d098887843040765651273e336804b819880994ee +oid sha256:d700eefb4ca7388ed7f8b993df5ccd96755d676da517b469e54cfa4fcab0365d size 17113 diff --git a/Game/GigLine/Content/Hollywood/Site/M_Ground.uasset b/Game/GigLine/Content/Hollywood/Site/M_Ground.uasset index c23ffe8..773259d 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_Ground.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_Ground.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a9c8cc98384edbe2df0ab772f790310047339159346fb11ad4c7b86a82bea132 +oid sha256:1ad5c097bbe648098164f928cd3f65c25d4e19d27ef977dd6fddc5700e5ecb9e size 10014 diff --git a/Game/GigLine/Content/Hollywood/Site/M_KerbConcrete.uasset b/Game/GigLine/Content/Hollywood/Site/M_KerbConcrete.uasset index 0b90a35..2fd45e6 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_KerbConcrete.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_KerbConcrete.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c6934516f42a8539d7a9e37b4386a3746be9eec4cb18feabe433d1126e9cf4c4 +oid sha256:ed9a6ff5803cb88f437f0d501b657ad67dd94ef9b106ab9f146f78fb40b5515b size 10044 diff --git a/Game/GigLine/Content/Hollywood/Site/M_RoadPaint.uasset b/Game/GigLine/Content/Hollywood/Site/M_RoadPaint.uasset index 0d2b0d7..74c50e3 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_RoadPaint.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_RoadPaint.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad2e8ec104f49d612d66b54e7af742ac1041b9dd8572083c252b7011c0438101 +oid sha256:074e023941b72b9389cff4d79d550e0537c100c82ca199f223ea725fae09f34e size 10029 diff --git a/Game/GigLine/Content/Hollywood/Site/M_Stucco.uasset b/Game/GigLine/Content/Hollywood/Site/M_Stucco.uasset index a9067fe..e22d380 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_Stucco.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_Stucco.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a09613d3a4f47fb6532e402061acc3510265896b3bff90167943387a32c5addc +oid sha256:e78b99b1160dd2e2def0d0a3639f180cd1e05eb9a9ebbc416a20c72edb42a6c7 size 11389 diff --git a/Game/GigLine/Content/Hollywood/Site/Terrain_DEM.uasset b/Game/GigLine/Content/Hollywood/Site/Terrain_DEM.uasset index 4759c46..73eddfc 100644 --- a/Game/GigLine/Content/Hollywood/Site/Terrain_DEM.uasset +++ b/Game/GigLine/Content/Hollywood/Site/Terrain_DEM.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cdd2cde3bfdbc117cd0445d61c68659f8924ed794df9e61cedc466b5bb97c1ae +oid sha256:07197b7a3f41927c1b79448ee864e1dcee92efb6e61c7faf60b7ec9663b9248a size 357901 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_BC.uasset b/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_BC.uasset index 01702ac..94a7914 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_BC.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_BC.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1e00754bcb7fb131a40c9a162bf0dfc0c1a0b9a84718e121e715ed4f2d4d9ab +oid sha256:681be23cedf0dfc3078954f0e10e2ce44bc95ce836a38ab7afdcc505ba4cec61 size 70879 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_R.uasset b/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_R.uasset index 06d4b3b..274108f 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_R.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_R.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f717ded45c8aaf50861582119ce524061947bf05a36f7e335f657f193f5c6e0 +oid sha256:e00a2893aee8bb896647a57424c5192ee4b72004ac59bda9d59c5f2e9210ac24 size 29011 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_Concrete_BC.uasset b/Game/GigLine/Content/Hollywood/Textures/T_Concrete_BC.uasset index d1db955..0543682 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_Concrete_BC.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_Concrete_BC.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b6ed6dcdcacec001b0407ac7b06d7a28244a0b95ebc6ff1592047b7a2f25f8dc +oid sha256:b2de801b2140f67783f8080f9cdb378e002ae718db87841c22846c17dba378d1 size 58568 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_Concrete_R.uasset b/Game/GigLine/Content/Hollywood/Textures/T_Concrete_R.uasset index 79e20bc..fc67794 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_Concrete_R.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_Concrete_R.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e5a34257578275ea6943266ab22676e0da79945fb9f49f581620786564ebe3b +oid sha256:c9cffdbfe0986ca06244288c56d9470683483e057b79ab5817fdf319ecf1cfaa size 17517 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_BC.uasset b/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_BC.uasset index 8321fd1..ebf0ec5 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_BC.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_BC.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e03c186726d7384eec66a3cd4ded3f6c907b1c64793a2daa999a5558c61c053e +oid sha256:0afb4a71fac5ca243c15788f8489f7feee300023b9df0e28b23d88cc76c37076 size 40610 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_R.uasset b/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_R.uasset index 9ebb467..7ea7e4b 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_R.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_R.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac2fce195bfc270b86810c906bc37dae592797fa4c3cf4fa02a005dfb26db446 +oid sha256:2f04b0118383c665f348f58e2444748e94eb7ea3838911d49c474da2586d35e5 size 18770 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_Stucco_BC.uasset b/Game/GigLine/Content/Hollywood/Textures/T_Stucco_BC.uasset index 8c4d274..e3a1f6e 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_Stucco_BC.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_Stucco_BC.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad13b6b085fafb13723adf631d4fdd0b1dd4a118d50607d8d87af5d67f5d1921 +oid sha256:444178c78a14b79842f2082839f9210809bf72d3c4e17ba257b3faa09401e16e size 62746 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_Stucco_R.uasset b/Game/GigLine/Content/Hollywood/Textures/T_Stucco_R.uasset index 1e69c24..2a014d8 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_Stucco_R.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_Stucco_R.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a17fc39a2a9b8b0e0f5103857876173a766c9db26e3334bd5d2b0e06657550c +oid sha256:001fb4d9af44228b20e12875afabd4535c2de170f3ed3afcf8df893af8245b1a size 17541 diff --git a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSign.uasset b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSign.uasset index 3d1dc5e..873a096 100644 --- a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSign.uasset +++ b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSign.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36649be3dd41c043f68494ac8dbcfd2bb85e735f8665ce1e3c45f2672a109d3e +oid sha256:42ec14ea323dc5e8653f6da1ca9a908c428b2eb2a2e60e29e2b4be6bf33f6f11 size 72330 diff --git a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignBracket.uasset b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignBracket.uasset index ad862cd..d338999 100644 --- a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignBracket.uasset +++ b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignBracket.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:affc4a3580c12d372f03bfcaae78543739bf4e8cb5d234b1c2273357b1451035 +oid sha256:8b141dccd86ec7c0b6e44020d508745dbd728168b031e38616d778796bb8bdc0 size 72466 diff --git a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignFrame.uasset b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignFrame.uasset index 069a7fa..8feb0c9 100644 --- a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignFrame.uasset +++ b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignFrame.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eb80f9f2267837bbe796f77a7d5564ef9928436709d656cd0b6ce989ee3a065b +oid sha256:0bfaddfc11d2bd9ab6833412aa6c4e04e64838d1d7348420fe1c18df7db60773 size 72406 diff --git a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeCanopy.uasset b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeCanopy.uasset index 7334a32..99aa089 100644 --- a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeCanopy.uasset +++ b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeCanopy.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:133969c52a67672ef871a423ca4e445f65fce751ec6c275f63b6855300f6774b +oid sha256:4dde3c4394b1173d3c51384e700857991c80ea51a693eab879f49c80acda89f1 size 72370 diff --git a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeFascia.uasset b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeFascia.uasset index 14a16d9..dc26e64 100644 --- a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeFascia.uasset +++ b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeFascia.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff64d40901f3b376446ed2de3bebab4f93317e6ae3fc89fe6ab6c9db1d30efe5 +oid sha256:1f2c9eb2dde27f35b7c577b217731b89eaa47bea5d0e1681c54ffdd1dc587f6a size 72438 diff --git a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeSoffit.uasset b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeSoffit.uasset index c931cdf..9fd285b 100644 --- a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeSoffit.uasset +++ b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeSoffit.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c84cbf3f0afd1f2f18d345c61a748a2fa5f6fc033df6b238f8edcd59c8e8cf8c +oid sha256:509dac96c9c9ef76e441a53fb10935fdff6eed25dd12673e1e057b9e685587c3 size 72413 diff --git a/Game/GigLine/Content/Test/Character/Character_Anim.uasset b/Game/GigLine/Content/Test/Character/Character_Anim.uasset index 6b48bc1..a85a658 100644 --- a/Game/GigLine/Content/Test/Character/Character_Anim.uasset +++ b/Game/GigLine/Content/Test/Character/Character_Anim.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b0ae70ce75d164ae31342b65b87611bec2df35585086a30d39621b0d7cccedbf -size 3756275 +oid sha256:9527ef1720ce27a219eab92f3a9fa12feccdfa8173977cd75b9aa9eb92bf0a7c +size 3756743 diff --git a/Game/GigLine/Content/Test/ReviewMap.umap b/Game/GigLine/Content/Test/ReviewMap.umap index f9adb5d..32be8b8 100644 --- a/Game/GigLine/Content/Test/ReviewMap.umap +++ b/Game/GigLine/Content/Test/ReviewMap.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec72b33cc57c5aa50889c6d0bc68c78ce5fde621881ed5c3bde4d6679610ef4e -size 28811 +oid sha256:4d44eb29a592ca2c7ce809ae860d1c259a373cfec5841b088c876278a33d3ff1 +size 29389 diff --git a/Game/GigLine/Source/GigLine/GigLineCharacter.cpp b/Game/GigLine/Source/GigLine/GigLineCharacter.cpp index f8ccf01..fbfe12c 100644 --- a/Game/GigLine/Source/GigLine/GigLineCharacter.cpp +++ b/Game/GigLine/Source/GigLine/GigLineCharacter.cpp @@ -727,6 +727,7 @@ void AGigLineCharacter::Tick(float DeltaSeconds) // Speed-driven animation state: correct whether the player walked, was pushed, // or fell, and independent of which input produced the movement. UpdateBodyAnimation(); + } void AGigLineCharacter::ToggleCamera() @@ -771,16 +772,34 @@ void AGigLineCharacter::UpdateBodyAnimation() } return; } - if (Wanted == PlayingAnimation) + + // PlayAnimation is only an intent: it needs the component in single-node mode and + // a live single-node instance. The body is hidden at construction and only + // unhidden by the camera toggle, so the first call could land on a component that + // was not ready and never retried - the clip name logged, the pose left at bind. + // Driving the mode and the instance explicitly, and re-asserting every frame while + // the instance is missing, makes that failure self-correcting. + if (GetMesh()->GetAnimationMode() != EAnimationMode::AnimationSingleNode) { - return; + GetMesh()->SetAnimationMode(EAnimationMode::AnimationSingleNode); } - PlayingAnimation = Wanted; - if (CVarGigLineSetupLogs.GetValueOnGameThread()) + if (Wanted != PlayingAnimation || GetMesh()->GetSingleNodeInstance() == nullptr) { - UE_LOG(LogTemp, Log, TEXT("GigLine: playing body clip %s"), *Wanted->GetName()); + PlayingAnimation = Wanted; + GetMesh()->SetAnimation(Wanted); + GetMesh()->Play(true); + if (CVarGigLineSetupLogs.GetValueOnGameThread()) + { + static bool bLoggedAnimState = false; + if (!bLoggedAnimState) + { + bLoggedAnimState = true; + UE_LOG(LogTemp, Log, TEXT("GigLine: body clip %s, mode=%d, instance=%s"), + *Wanted->GetName(), static_cast(GetMesh()->GetAnimationMode()), + GetMesh()->GetSingleNodeInstance() ? TEXT("ok") : TEXT("nil")); + } + } } - GetMesh()->PlayAnimation(Wanted, true); } void AGigLineCharacter::ResetToStart() diff --git a/MEMORY.md b/MEMORY.md index 8577f97..db051a6 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -474,3 +474,7 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO. - **The material was a real but separate defect**: `M_Character_Export` had no `SkeletalMesh` usage flag, so Unreal substituted the default grey with only a `LogMaterial` warning. Fixed in place (`used_with_skeletal_mesh = True`). - **`PlayAnimation` alone is not enough.** `USkeletalMeshComponent::PlayAnimation` needs the component already in `AnimationSingleNode` mode; the body is hidden at construction (`SetHiddenInGame(true)`) and only unhidden by the camera toggle, so the first call can land on a component that is not yet in the right mode and never retries — the guard `Wanted == PlayingAnimation` then returns forever and the pose stays at bind. - **What to log next time**: animation mode and `GetSingleNodeInstance()` together with the clip name. A clip name alone shows the intent, not the effect. +- **Fixed 2026-11-09, two independent causes.** (1) `PlayAnimation` needs `AnimationSingleNode` plus a live single-node instance; the body is hidden at construction and only unhidden by the camera toggle, so the first call could land before the component was ready and the `Wanted == PlayingAnimation` guard then returned forever. `UpdateBodyAnimation` now sets the mode, calls `SetAnimation` + `Play`, and re-asserts while `GetSingleNodeInstance()` is null. (2) The arms-down offsets lived only in the clip keys — the exporter writes clip data **relative to the rest pose**, so they arrived in Unreal as a ±20° swing around an A-posed bind. `apply_base_pose` now bakes them into the rest pose before any clip is authored, which is what `mpfb_character_export.py --pose idle` already did. +- **The base pose needs inverted signs when baked to rest.** Applied as written, the FBX axis mapping produced arms raised in a V; negating the table gives arms down. Both states were verified on the imported asset, not assumed. +- **Unreal bone names use underscores**: `upperarm01_L`, not Blender's `upperarm01.L`. `GetBoneIndex(TEXT("upperarm01.L"))` returns INDEX_NONE, `GetBoneTransform` then returns identity, and a probe reading it reports a constant 0.0000 — which looks like "animation not applied" and is actually "bone not found". Check `AnimPose.get_bone_names()` before trusting any bone probe. +- **`Log` verbosity does not reach the capture log, `Warning` does.** Two diagnostic runs produced zero lines because the messages were `UE_LOG(LogTemp, Log, ...)`; the same lines at `Warning` appeared. Instrument with Warning when the evidence has to survive into `/tmp/gigline/render-*.log`. diff --git a/Screenshots/README.md b/Screenshots/README.md index b4f9407..c4be440 100644 --- a/Screenshots/README.md +++ b/Screenshots/README.md @@ -96,19 +96,23 @@ Known gaps in this first pass, recorded rather than hidden: ## 6. Third-person body -![Third-person body: the player pawn seen from behind on the north sidewalk](demo/review-demo-third-person.png) +![Third-person body: the player pawn standing on the north sidewalk, seen from behind](demo/review-demo-third-person.png) - **File:** `demo/review-demo-third-person.png` - **View:** third-person boom, ~6 m behind the pawn, captured with `-thirdperson` so the pawn starts in the third-person rig - **Expected content:** the player's own visible body on the north sidewalk, seen from behind, with the hero façade across the street - **Verified:** ☑ 2026-11-09 · **Approved:** ☐ pending -What this shot is evidence for, and what it is not: +What this shot is evidence for: -- **Implemented and visible:** the pawn carries a visible skeletal body with the warm skin material, and a spring-arm camera with collision testing. The **V** toggle swaps first and third person; the shipped default stays first person and the review passes `-thirdperson`. -- **Not working:** the figure is in **bind pose, arms out**. The idle clip is bound and `PlayAnimation` is called — the run logs `GigLine: playing body clip Character_AnimHuman_rig_GigLine_Idle` — so the call succeeds and the pose does not apply. Tracked in `TODO.md` under "Verify animation plays correctly on the imported rig" with that evidence. +- The pawn carries a visible skeletal body with the warm skin material, and a spring-arm camera with collision testing. The **V** toggle swaps first and third person; the shipped default stays first person and the review passes `-thirdperson`. +- **The idle clip now drives the body.** The arms hang at the sides rather than standing out in a bind A-pose, which is what the first three captures of this shot showed. + +What is still not right, and is tracked: + +- **The arms hang too far forward and the hands splay outward**, so the pose reads as a person standing awkwardly rather than at rest. The base pose is applied to the rest pose with inverted signs (the FBX axis mapping flips it); the elbow and hand orientation still need work, and that belongs to the `0.2.2` skin/animation tuning pass rather than to this rig. +- **The walk clip has no shot of its own.** It imports and its curves carry a ±18° arm swing and a 0.45 rad hip swing, but nothing has captured it in motion; a walking shot needs a camera that follows a moving pawn. - **Camera collision is implemented but unproven:** the spawn point has open space behind it, so no shot exercises the arm shortening. -- The skin material needed `used_with_skeletal_mesh=True`; without it Unreal silently substituted the default grey, which is what the first capture of this shot showed. --- @@ -141,8 +145,9 @@ Every issue is tracked in `TODO.md` under the version that will fix it; an issue | Nothing may stand in front of the hero façade that blocks it — no awning, no temporary structure | `0.9.0` → per-building models, hero façade | Open | | Retail parapet has no moulded profile, and wall lettering built as a plate does not read at 40 m | `0.9.0` → 6800 Lee Drug and 6806–6820, second pass | Open (moved out of `0.1.6`) | | 6822 Budget is a bare blockout volume — no photograph exists to model it from | `0.9.0` → photography gap | Deferred (moved out of `0.1.6`) | -| Third-person body renders in bind pose: the clip is bound and `PlayAnimation` is called, but the pose does not apply | `0.2.0` → verify animation plays correctly | Open (blocks `0.2.0`) | +| Third-person idle pose reads awkwardly: arms hang forward and the hands splay, because the base pose is applied with inverted signs to compensate for the FBX axis flip | `0.2.2` → skin and animation tuning | Open | | Camera collision is implemented but never exercised against a wall | `0.2.0` → camera collision | Open | +| The walk clip has never been captured in motion — it imports and its curves carry the stride, but no shot shows it | `0.2.0` → verify animation plays correctly | Open | | Between kerb and building line the walkable surface is the terrain mesh, not a modelled pavement | `0.6.0` → model the pavement between kerb and building line | Open | Accepted by the owner, not a defect: diff --git a/Screenshots/demo/review-demo-crossing.png b/Screenshots/demo/review-demo-crossing.png index 457233d..ecaf303 100644 --- a/Screenshots/demo/review-demo-crossing.png +++ b/Screenshots/demo/review-demo-crossing.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:06bd939e40544e818c721a8e52d4f9db42bcc15578fdf23a0f07e5e3e81a3a0e -size 3090121 +oid sha256:84519c584c1a6e47b88d116c18143e0872aeac290f1d5e9db3778072d36823e2 +size 3088862 diff --git a/Screenshots/demo/review-demo-north-buildings.png b/Screenshots/demo/review-demo-north-buildings.png index a7d947d..00104eb 100644 --- a/Screenshots/demo/review-demo-north-buildings.png +++ b/Screenshots/demo/review-demo-north-buildings.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:16b30099d71573954ae5f2bf3082a50b6ef715753c83470b6d56146b93da8526 -size 2619302 +oid sha256:a6175ecc2071d6f44424fb23ecf6680721b14f0c2b9984f5d3dee68df94b9431 +size 2620166 diff --git a/Screenshots/demo/review-demo-retail-frontage.png b/Screenshots/demo/review-demo-retail-frontage.png index c5854ac..b60b5e9 100644 --- a/Screenshots/demo/review-demo-retail-frontage.png +++ b/Screenshots/demo/review-demo-retail-frontage.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9cb8296dd77c3b1ce3af3c26be36280f22bdcbf35c79458cd82850ee4083510 -size 2520582 +oid sha256:ac8c902c8726185db34e71d86f96ef88d5b218f85de0fcdc1b76eb6cad02064e +size 2521184 diff --git a/Screenshots/demo/review-demo-spawn-view.png b/Screenshots/demo/review-demo-spawn-view.png index 92bfc1c..f6dc9fb 100644 --- a/Screenshots/demo/review-demo-spawn-view.png +++ b/Screenshots/demo/review-demo-spawn-view.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c060b014cf4e04d0f5b3c8255e505a1f0d80abb1a1796190a7aba00370d49618 -size 2944637 +oid sha256:20b159462049b45c91c89d98f4ea69ae4f98a3ea64b16e9cecb8bb1959052543 +size 2987440 diff --git a/Screenshots/demo/review-demo-street-level.png b/Screenshots/demo/review-demo-street-level.png index 24d4553..65f3751 100644 --- a/Screenshots/demo/review-demo-street-level.png +++ b/Screenshots/demo/review-demo-street-level.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ee9182712bef9ea7415722e2c546df0ee3d914cc46ee73b450c683245b1f4a3c -size 2875166 +oid sha256:2e72776ae4e4f296307a4af29362c9dc7a317c172f403730714fc4a2b279f8cc +size 2848073 diff --git a/Screenshots/demo/review-demo-third-person.png b/Screenshots/demo/review-demo-third-person.png index 9691a14..e708f8a 100644 --- a/Screenshots/demo/review-demo-third-person.png +++ b/Screenshots/demo/review-demo-third-person.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e33aa48f09e9896a2ba9779e17b2c2a0c28a54d6a2429ef84325a98f0fa25d4a -size 2999077 +oid sha256:2fa077a010e0468c4b83eebc0213c8245713517d0ce8d2155c2bc798b190fa63 +size 2998339 diff --git a/TODO.md b/TODO.md index c7b9b10..92a075f 100644 --- a/TODO.md +++ b/TODO.md @@ -17,7 +17,7 @@ Actionable task list for this project. This file is the single, central place fo - [x] Import character into Unreal; validate skeleton, scale, and materials. Done: `/Game/Test/Character` — `SkeletalMesh` (138 bones), `Skeleton`, warm `M_Character_Export` material with baked `T_Character_Diffuse`. - [x] Promote the character asset into a reusable NPC prefab (visible body, collision capsule, idle pose) ready for pedestrians (`0.5.0`) once the third-person body lands. Done 2026-11-07: `AGigLineNPCPerson` (see the 0.1.0 Character-development item); `0.5.0` reuses it as the pedestrian base. - [x] Create basic idle/walk animation set. Done 2026-11-09: `Tools/character_anim_build.py` authors `GigLine_Idle` (60 f) and `GigLine_Walk` (30 f) at 30 fps from parametric cycles, and `Tools/ue_character_anim_import.py` imports them. Both AnimSequences verified in `/Game/Test/Character`: Idle 1.967 s, Walk 0.967 s. Limb axes were **measured** on the rig, not assumed — the probe rotated `upperleg01.L` 0.5 rad per axis and read `foot.L`, which showed X is the fore/aft swing (Y twists, Z abducts). -- [A] Verify animation plays correctly on the imported rig. **Playback is broken and now measurable**: the pawn's mesh is bound, both clips resolve, and the run logs `GigLine: playing body clip Character_AnimHuman_rig_GigLine_Idle`, but shot 5 still renders the body in bind pose (arms out). So `PlayAnimation` is called and the pose is not applied — next step is to check whether the imported clip carries bone curves at all (the FBX bake may be sampling only keyed bones) or whether the component needs `SetAnimationMode(AnimationSingleNode)` before `SetAnimation`/`Play`. +- [~] Verify animation plays correctly on the imported rig. **Fixed 2026-11-09**: the clip now drives the body — shot 6 shows the arms hanging at the sides instead of an A-pose. Two causes, both proven by measurement rather than guessed: (1) `PlayAnimation` needs the component in `AnimationSingleNode` with a live single-node instance, and the body is hidden at construction, so the first call could land before the component was ready and never retry; the code now sets the mode, calls `SetAnimation` + `Play`, and re-asserts while the instance is missing. (2) the arms-down offsets were carried only in the clip keys, which the exporter writes relative to the rest pose — so they arrived as a ±20° swing around an A-posed bind; they are now baked into the rest pose before the clips are authored (`apply_base_pose`). **Still open:** the idle pose reads awkwardly (arms hang forward, hands splay) because the base is applied with inverted signs to compensate for the FBX axis flip, and the walk clip has never been captured in motion. Earlier evidence: the pawn's mesh is bound, both clips resolve, and the run logs `GigLine: playing body clip Character_AnimHuman_rig_GigLine_Idle`, but shot 5 still renders the body in bind pose (arms out). So `PlayAnimation` is called and the pose is not applied — next step is to check whether the imported clip carries bone curves at all (the FBX bake may be sampling only keyed bones) or whether the component needs `SetAnimationMode(AnimationSingleNode)` before `SetAnimation`/`Play`. ### Camera and controls diff --git a/Tools/character_anim_build.py b/Tools/character_anim_build.py index 17dc182..1107acd 100644 --- a/Tools/character_anim_build.py +++ b/Tools/character_anim_build.py @@ -91,10 +91,37 @@ def pose_bones(arm): return arm.pose.bones +def apply_base_pose(arm): + """Bake the arms-down pose into the REST pose before authoring any clip. + + The first two attempts added the arms-down as an offset inside every key. That + is not what the export sees: the exporter writes clip data relative to the rest + pose, so an offset that lives only in the keys arrives in Unreal as a small + delta around an A-posed bind - the body stood in an A with a ±20 degree arm + swing, which is exactly what the Unreal pose probe measured. Baking the pose + into the rest pose first is the same trick `mpfb_character_export.py --pose + idle` uses, and it makes bind and clips agree. + """ + bpy.context.view_layer.objects.active = arm + bpy.ops.object.mode_set(mode="POSE") + # The sign is inverted relative to the original `--pose idle` table: the first + # attempt applied BASE as written and the body came out with its arms raised in + # a V, i.e. the FBX axis mapping flips this rotation. Verified on the imported + # asset rather than guessed - see MEMORY.md, 2026-11-09. + for name, eul in BASE.items(): + bone = arm.pose.bones.get(name) + if bone is None: + continue + bone.rotation_mode = "XYZ" + bone.rotation_euler = (-eul[0], -eul[1], -eul[2]) + bpy.ops.pose.armature_apply() + bpy.ops.object.mode_set(mode="OBJECT") + log("base pose applied to rest: arms down before any clip is authored") + + def key_euler(pb, frame, x=0.0, y=0.0, z=0.0): - """Key a pose-bone rotation on top of the arms-down base.""" - bx, by, bz = BASE.get(pb.name, (0.0, 0.0, 0.0)) - pb.rotation_euler = (bx + x, by + y, bz + z) + """Key a pose-bone rotation; the arms-down base is already in the rest pose.""" + pb.rotation_euler = (x, y, z) pb.keyframe_insert(data_path="rotation_euler", frame=frame) @@ -174,6 +201,7 @@ def main(argv=None) -> int: bpy.context.scene.render.fps = FPS clear_animation(arm) + apply_base_pose(arm) idle = clip_idle(arm, CLIPS["Idle"]) walk = clip_walk(arm, CLIPS["Walk"])