Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9f31f271e | ||
|
|
03af8146a6 | ||
|
|
30e4d65743 | ||
|
|
bc2e9c3b8e |
No files matched your search
@@ -8,6 +8,21 @@ Format: [Keep a Changelog](https://keepachangelog.com/) style, versions follow [
|
|||||||
|
|
||||||
Nothing yet.
|
Nothing yet.
|
||||||
|
|
||||||
|
## [0.2.1] — 2026-11-09
|
||||||
|
|
||||||
|
Rig fixes. Two defects from the `0.2.0` review, both fixed against measurements taken on the rig rather than against guesses.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **The fingers splayed.** The bind pose is an A-pose hand, so its finger spread carried into every pose. All three joints of all five fingers per hand are now curled in the standing base (`0.28 / 0.34 / 0.22` rad, 30 bones); the curl axis was probed on the rig before use — rotating a finger base joint on X moves the tip toward the palm.
|
||||||
|
- **The arms-down rotation was hard-coded.** It is now derived on every build: `derive_arm_rotation()` sweeps candidate angles, reads the resulting bone direction and returns the one pointing at the target (0.60 rad, direction dot 1.000 in this build). The old 0.55 was a hand-swept constant that would have rotted on any rig change.
|
||||||
|
- **Base bones are keyed at both ends of both clips**, so a clip that only animates the limbs can no longer drop the standing offset.
|
||||||
|
|
||||||
|
### Known limitations
|
||||||
|
|
||||||
|
- **The stride capture regressed.** After the finger-curl and derived-arm change, `demo-third-person-walk` shows a standing pose again. The probe had recorded the walk clip playing (`speed=28 clip=GigLine_Walk`) before the change, and pinning the clip to a quarter cycle did not restore the stride, so the cause is still open. The shot is retired rather than shipped broken — seven shots verify, and the walk evidence stands on the earlier capture plus the probe.
|
||||||
|
- Camera collision remains implemented but unexercised against a wall.
|
||||||
|
|
||||||
## [0.2.0] — 2026-11-09
|
## [0.2.0] — 2026-11-09
|
||||||
|
|
||||||
Third-person body. The pawn gains a visible, animated body and a third-person camera, so the walk cycle is finally something a player can see rather than a clip in an asset list.
|
Third-person body. The pawn gains a visible, animated body and a third-person camera, so the walk cycle is finally something a player can see rather than a clip in an asset list.
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ C++ classes in `Game/GigLine/Source/GigLine/`:
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `AGigLineCharacter` | First-person player pawn | 1.75 m capsule, 4.5 m/s walk, Enhanced Input bindings, reset, pause, `-qaselftest` harness |
|
| `AGigLineCharacter` | First-person player pawn | 1.75 m capsule, 4.5 m/s walk, Enhanced Input bindings, reset, pause, `-qaselftest` harness |
|
||||||
| `AGigLineGameModeBase` | Sets game mode and HUD class | `HUDClass = AGigLineHUD` |
|
| `AGigLineGameModeBase` | Sets game mode and HUD class | `HUDClass = AGigLineHUD` |
|
||||||
| `AGigLineHUD` | HUD text overlay | `DrawText` every frame, bottom-left |
|
| `AGigLineHUD` | HUD text overlay | `DrawText` every frame: ODbL attribution bottom-left, controls bottom-right, and an F3 debug readout top-left (`gigline.Debug`, on for `-perf`/`-qaselftest`) |
|
||||||
| `AGigLineNPCPerson` | NPC prefab (future) | Capsule + visible MPFB body, feet on Z 0 |
|
| `AGigLineNPCPerson` | NPC prefab (future) | Capsule + visible MPFB body, feet on Z 0 |
|
||||||
| `AGigLineShotActor` | Screenshot camera walker | Drives cameras in `-game` mode, `FScreenshotRequest`, quits |
|
| `AGigLineShotActor` | Screenshot camera walker | Drives cameras in `-game` mode, `FScreenshotRequest`, quits |
|
||||||
| `UGigLineAssetTools` | C++ collision helpers | `SetComplexCollisionAsSimple` on `StaticMesh` assets |
|
| `UGigLineAssetTools` | C++ collision helpers | `SetComplexCollisionAsSimple` on `StaticMesh` assets |
|
||||||
|
|
||||||
Input assets in `/Game/Input/`: `IA_Move`, `IA_MoveBack`, `IA_Strafe`, `IA_StrafeLeft`, `IA_Look`, `IA_Jump`, `IA_Reset`, `IA_Pause`, `IA_ToggleCamera`, bound in `IMC_Default`.
|
Input assets in `/Game/Input/`: `IA_Move`, `IA_MoveBack`, `IA_Strafe`, `IA_StrafeLeft`, `IA_Look`, `IA_Jump`, `IA_Reset`, `IA_Pause`, `IA_ToggleCamera`, `IA_ToggleDebug`, bound in `IMC_Default`.
|
||||||
|
|
||||||
Player-facing bindings: **WASD** move, **mouse** look, **Space** jump, **R** reset, **Escape** pause, **V** swap first/third person. The camera and body work landed with `0.2.0` (see ADR-9): the shipped default view stays first person, and `-thirdperson` starts the pawn in the third-person rig — used by the screenshot run so the review is reproducible.
|
Player-facing bindings: **WASD** move, **mouse** look, **Space** jump, **R** reset, **Escape** pause, **V** swap first/third person. The camera and body work landed with `0.2.0` (see ADR-9): the shipped default view stays first person, and `-thirdperson` starts the pawn in the third-person rig — used by the screenshot run so the review is reproducible.
|
||||||
|
|
||||||
|
|||||||
@@ -164,12 +164,12 @@ C++ classes in `Game/GigLine/Source/GigLine/`:
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `AGigLineCharacter` | First-person player pawn | 1.75 m capsule, 4.5 m/s walk, Enhanced Input bindings, reset, pause, `-qaselftest` harness |
|
| `AGigLineCharacter` | First-person player pawn | 1.75 m capsule, 4.5 m/s walk, Enhanced Input bindings, reset, pause, `-qaselftest` harness |
|
||||||
| `AGigLineGameModeBase` | Sets game mode and HUD class | `HUDClass = AGigLineHUD` |
|
| `AGigLineGameModeBase` | Sets game mode and HUD class | `HUDClass = AGigLineHUD` |
|
||||||
| `AGigLineHUD` | HUD text overlay | `DrawText` every frame, bottom-left |
|
| `AGigLineHUD` | HUD text overlay | `DrawText` every frame: ODbL attribution bottom-left, controls bottom-right, and an F3 debug readout top-left (`gigline.Debug`, on for `-perf`/`-qaselftest`) |
|
||||||
| `AGigLineNPCPerson` | NPC prefab (future) | Capsule + visible MPFB body, feet on Z 0 |
|
| `AGigLineNPCPerson` | NPC prefab (future) | Capsule + visible MPFB body, feet on Z 0 |
|
||||||
| `AGigLineShotActor` | Screenshot camera walker | Drives cameras in `-game` mode, `FScreenshotRequest`, quits |
|
| `AGigLineShotActor` | Screenshot camera walker | Drives cameras in `-game` mode, `FScreenshotRequest`, quits |
|
||||||
| `UGigLineAssetTools` | C++ collision helpers | `SetComplexCollisionAsSimple` on `StaticMesh` assets |
|
| `UGigLineAssetTools` | C++ collision helpers | `SetComplexCollisionAsSimple` on `StaticMesh` assets |
|
||||||
|
|
||||||
Input assets in `/Game/Input/`: `IA_Move`, `IA_MoveBack`, `IA_Strafe`, `IA_StrafeLeft`, `IA_Look`, `IA_Jump`, `IA_Reset`, `IA_Pause`, `IA_ToggleCamera`, bound in `IMC_Default`.
|
Input assets in `/Game/Input/`: `IA_Move`, `IA_MoveBack`, `IA_Strafe`, `IA_StrafeLeft`, `IA_Look`, `IA_Jump`, `IA_Reset`, `IA_Pause`, `IA_ToggleCamera`, `IA_ToggleDebug`, bound in `IMC_Default`.
|
||||||
|
|
||||||
Player-facing bindings: **WASD** move, **mouse** look, **Space** jump, **R** reset, **Escape** pause, **V** swap first/third person. The camera and body work landed with `0.2.0` (see ADR-9): the shipped default view stays first person, and `-thirdperson` starts the pawn in the third-person rig — used by the screenshot run so the review is reproducible.
|
Player-facing bindings: **WASD** move, **mouse** look, **Space** jump, **R** reset, **Escape** pause, **V** swap first/third person. The camera and body work landed with `0.2.0` (see ADR-9): the shipped default view stays first person, and `-thirdperson` starts the pawn in the third-person rig — used by the screenshot run so the review is reproducible.
|
||||||
|
|
||||||
|
|||||||
+11
-1
@@ -13,6 +13,7 @@ Keyboard and mouse. The same list is shown in-game, bottom-right of the frame (`
|
|||||||
| Reset to start | `R` | Returns to the grounded spawn point |
|
| Reset to start | `R` | Returns to the grounded spawn point |
|
||||||
| Pause / release mouse | `Escape` | Second press resumes and recaptures the mouse |
|
| Pause / release mouse | `Escape` | Second press resumes and recaptures the mouse |
|
||||||
| Swap first / third person | `V` | First person is the default; the body is hidden in that view |
|
| Swap first / third person | `V` | First person is the default; the body is hidden in that view |
|
||||||
|
| Show / hide debug overlay | `F3` | FPS, frame time, worst frame, view mode, speed and player position |
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
@@ -24,6 +25,14 @@ Keyboard and mouse. The same list is shown in-game, bottom-right of the frame (`
|
|||||||
|
|
||||||
- **`V` swaps first and third person** (`0.2.0`, `IA_ToggleCamera`). The shipped default view is still first person, as the owner decided for `0.1.0`; third person adds a collision-tested spring-arm camera and a visible, animated body. `Escape` still pauses and releases the mouse in either view.
|
- **`V` swaps first and third person** (`0.2.0`, `IA_ToggleCamera`). The shipped default view is still first person, as the owner decided for `0.1.0`; third person adds a collision-tested spring-arm camera and a visible, animated body. `Escape` still pauses and releases the mouse in either view.
|
||||||
|
|
||||||
|
## Debug overlay
|
||||||
|
|
||||||
|
`F3` toggles a top-left readout: smoothed **FPS** and frame time, the **worst** frame in a rolling two-second window, the active view (first or third person), player speed, a frame counter, and the player's position in metres from the project origin. The first two seconds of a session are a warm-up window and are excluded from the worst-frame figure, because shader and streaming hitches there made a healthy run read as a 400 ms stall.
|
||||||
|
|
||||||
|
It is **off in the built demo** — a player should not see an FPS counter over Hollywood Boulevard — and **on automatically** when the process is started with `-perf` or `-qaselftest`, so a performance capture never depends on someone pressing a key first. In a running build it can also be forced with the console variable `gigline.Debug 1`.
|
||||||
|
|
||||||
|
Cost: about **5 %** of frame time at 1440p in the demo (2.64 → 2.77 ms average), measured in the same self-test route. The performance release check is recorded without the overlay for that reason; the overlay run is kept beside it as `Docs/perf/0.2.0-walk-frametimes-overlay.csv`.
|
||||||
|
|
||||||
## Review and harness switches
|
## Review and harness switches
|
||||||
|
|
||||||
These are command-line switches for the screenshot pipeline and QA runs, not player controls. They exist so a capture is reproducible rather than dependent on a human pressing keys at the right moment.
|
These are command-line switches for the screenshot pipeline and QA runs, not player controls. They exist so a capture is reproducible rather than dependent on a human pressing keys at the right moment.
|
||||||
@@ -32,7 +41,8 @@ These are command-line switches for the screenshot pipeline and QA runs, not pla
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `-thirdperson` | Starts the pawn in the third-person rig, so a capture shows the body without anyone pressing `V` |
|
| `-thirdperson` | Starts the pawn in the third-person rig, so a capture shows the body without anyone pressing `V` |
|
||||||
| `-walk` | Holds forward input from the first frame — what makes the stride shot possible |
|
| `-walk` | Holds forward input from the first frame — what makes the stride shot possible |
|
||||||
| `-qaselftest` | Runs the scripted walk / reset / pause / transect checks and quits |
|
| `-qaselftest` | Runs the scripted walk / reset / pause / transect checks and quits; also enables the debug overlay |
|
||||||
|
| `-perf` | Enables the debug overlay for a manual frame-time check |
|
||||||
|
|
||||||
The walking shot is driven per shot rather than by the switch: the shot actor enables the walk only while a tracking (`ShotFollow`) camera is being captured, and returns the pawn to spawn afterwards, so the fixed-camera shots still find it in place.
|
The walking shot is driven per shot rather than by the switch: the shot actor enables the walk only while a tracking (`ShotFollow`) camera is being captured, and returns the pawn to spawn afterwards, so the fixed-camera shots still find it in place.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,723 @@
|
|||||||
|
frame,ms
|
||||||
|
0,2.607
|
||||||
|
1,2.532
|
||||||
|
2,2.324
|
||||||
|
3,3.432
|
||||||
|
4,2.808
|
||||||
|
5,2.870
|
||||||
|
6,2.367
|
||||||
|
7,2.311
|
||||||
|
8,2.756
|
||||||
|
9,3.278
|
||||||
|
10,2.418
|
||||||
|
11,2.665
|
||||||
|
12,2.438
|
||||||
|
13,2.646
|
||||||
|
14,2.461
|
||||||
|
15,2.941
|
||||||
|
16,2.975
|
||||||
|
17,3.164
|
||||||
|
18,2.766
|
||||||
|
19,2.341
|
||||||
|
20,2.543
|
||||||
|
21,3.395
|
||||||
|
22,2.772
|
||||||
|
23,2.575
|
||||||
|
24,2.737
|
||||||
|
25,2.427
|
||||||
|
26,2.538
|
||||||
|
27,2.708
|
||||||
|
28,3.183
|
||||||
|
29,2.734
|
||||||
|
30,2.425
|
||||||
|
31,2.546
|
||||||
|
32,2.600
|
||||||
|
33,2.545
|
||||||
|
34,3.705
|
||||||
|
35,2.563
|
||||||
|
36,2.907
|
||||||
|
37,2.368
|
||||||
|
38,2.470
|
||||||
|
39,2.411
|
||||||
|
40,3.778
|
||||||
|
41,3.735
|
||||||
|
42,2.292
|
||||||
|
43,2.458
|
||||||
|
44,2.566
|
||||||
|
45,3.044
|
||||||
|
46,3.449
|
||||||
|
47,2.914
|
||||||
|
48,3.243
|
||||||
|
49,2.084
|
||||||
|
50,3.872
|
||||||
|
51,1.633
|
||||||
|
52,3.389
|
||||||
|
53,2.448
|
||||||
|
54,2.474
|
||||||
|
55,2.509
|
||||||
|
56,2.346
|
||||||
|
57,3.192
|
||||||
|
58,2.762
|
||||||
|
59,2.788
|
||||||
|
60,2.538
|
||||||
|
61,2.520
|
||||||
|
62,2.517
|
||||||
|
63,3.036
|
||||||
|
64,3.205
|
||||||
|
65,3.080
|
||||||
|
66,2.514
|
||||||
|
67,2.429
|
||||||
|
68,2.515
|
||||||
|
69,2.963
|
||||||
|
70,3.555
|
||||||
|
71,2.430
|
||||||
|
72,2.742
|
||||||
|
73,2.435
|
||||||
|
74,2.526
|
||||||
|
75,3.304
|
||||||
|
76,3.511
|
||||||
|
77,2.477
|
||||||
|
78,2.472
|
||||||
|
79,2.452
|
||||||
|
80,2.421
|
||||||
|
81,3.334
|
||||||
|
82,3.286
|
||||||
|
83,2.725
|
||||||
|
84,2.411
|
||||||
|
85,2.597
|
||||||
|
86,2.440
|
||||||
|
87,3.213
|
||||||
|
88,3.411
|
||||||
|
89,3.047
|
||||||
|
90,2.365
|
||||||
|
91,2.530
|
||||||
|
92,2.877
|
||||||
|
93,3.249
|
||||||
|
94,3.186
|
||||||
|
95,2.684
|
||||||
|
96,2.304
|
||||||
|
97,2.406
|
||||||
|
98,2.948
|
||||||
|
99,3.652
|
||||||
|
100,2.822
|
||||||
|
101,2.552
|
||||||
|
102,2.575
|
||||||
|
103,2.354
|
||||||
|
104,2.676
|
||||||
|
105,2.775
|
||||||
|
106,3.865
|
||||||
|
107,2.480
|
||||||
|
108,2.501
|
||||||
|
109,2.675
|
||||||
|
110,2.724
|
||||||
|
111,3.671
|
||||||
|
112,2.828
|
||||||
|
113,3.064
|
||||||
|
114,2.153
|
||||||
|
115,2.752
|
||||||
|
116,2.936
|
||||||
|
117,3.008
|
||||||
|
118,2.932
|
||||||
|
119,2.648
|
||||||
|
120,2.441
|
||||||
|
121,3.471
|
||||||
|
122,1.885
|
||||||
|
123,4.435
|
||||||
|
124,2.504
|
||||||
|
125,3.241
|
||||||
|
126,2.813
|
||||||
|
127,2.445
|
||||||
|
128,3.321
|
||||||
|
129,3.055
|
||||||
|
130,3.222
|
||||||
|
131,2.766
|
||||||
|
132,2.582
|
||||||
|
133,2.597
|
||||||
|
134,3.637
|
||||||
|
135,3.150
|
||||||
|
136,3.163
|
||||||
|
137,2.675
|
||||||
|
138,2.708
|
||||||
|
139,2.581
|
||||||
|
140,3.377
|
||||||
|
141,3.518
|
||||||
|
142,2.565
|
||||||
|
143,2.385
|
||||||
|
144,2.360
|
||||||
|
145,2.768
|
||||||
|
146,3.172
|
||||||
|
147,2.754
|
||||||
|
148,2.758
|
||||||
|
149,2.474
|
||||||
|
150,2.995
|
||||||
|
151,2.903
|
||||||
|
152,3.398
|
||||||
|
153,2.484
|
||||||
|
154,2.894
|
||||||
|
155,3.022
|
||||||
|
156,2.413
|
||||||
|
157,3.517
|
||||||
|
158,3.370
|
||||||
|
159,2.854
|
||||||
|
160,2.485
|
||||||
|
161,3.058
|
||||||
|
162,2.473
|
||||||
|
163,3.390
|
||||||
|
164,3.023
|
||||||
|
165,2.543
|
||||||
|
166,2.629
|
||||||
|
167,2.929
|
||||||
|
168,2.928
|
||||||
|
169,3.268
|
||||||
|
170,2.622
|
||||||
|
171,2.764
|
||||||
|
172,2.920
|
||||||
|
173,2.681
|
||||||
|
174,2.551
|
||||||
|
175,3.492
|
||||||
|
176,2.534
|
||||||
|
177,2.741
|
||||||
|
178,2.949
|
||||||
|
179,2.554
|
||||||
|
180,2.596
|
||||||
|
181,3.522
|
||||||
|
182,3.207
|
||||||
|
183,2.722
|
||||||
|
184,2.945
|
||||||
|
185,2.474
|
||||||
|
186,2.934
|
||||||
|
187,3.447
|
||||||
|
188,2.515
|
||||||
|
189,2.317
|
||||||
|
190,3.059
|
||||||
|
191,2.542
|
||||||
|
192,3.417
|
||||||
|
193,2.737
|
||||||
|
194,2.456
|
||||||
|
195,3.025
|
||||||
|
196,2.640
|
||||||
|
197,2.601
|
||||||
|
198,3.567
|
||||||
|
199,2.350
|
||||||
|
200,2.581
|
||||||
|
201,3.079
|
||||||
|
202,2.514
|
||||||
|
203,2.462
|
||||||
|
204,3.725
|
||||||
|
205,3.730
|
||||||
|
206,2.670
|
||||||
|
207,2.308
|
||||||
|
208,2.689
|
||||||
|
209,2.565
|
||||||
|
210,3.479
|
||||||
|
211,2.604
|
||||||
|
212,3.339
|
||||||
|
213,2.373
|
||||||
|
214,2.678
|
||||||
|
215,3.340
|
||||||
|
216,2.867
|
||||||
|
217,2.751
|
||||||
|
218,2.747
|
||||||
|
219,2.410
|
||||||
|
220,2.485
|
||||||
|
221,2.594
|
||||||
|
222,3.602
|
||||||
|
223,2.689
|
||||||
|
224,2.565
|
||||||
|
225,2.397
|
||||||
|
226,2.562
|
||||||
|
227,2.598
|
||||||
|
228,3.403
|
||||||
|
229,3.303
|
||||||
|
230,2.775
|
||||||
|
231,2.101
|
||||||
|
232,2.499
|
||||||
|
233,2.991
|
||||||
|
234,3.059
|
||||||
|
235,3.210
|
||||||
|
236,2.568
|
||||||
|
237,2.066
|
||||||
|
238,2.498
|
||||||
|
239,2.572
|
||||||
|
240,3.281
|
||||||
|
241,2.676
|
||||||
|
242,2.640
|
||||||
|
243,2.867
|
||||||
|
244,2.418
|
||||||
|
245,2.493
|
||||||
|
246,3.126
|
||||||
|
247,2.845
|
||||||
|
248,2.522
|
||||||
|
249,2.459
|
||||||
|
250,2.524
|
||||||
|
251,2.466
|
||||||
|
252,3.060
|
||||||
|
253,3.848
|
||||||
|
254,2.516
|
||||||
|
255,2.460
|
||||||
|
256,2.499
|
||||||
|
257,2.427
|
||||||
|
258,3.463
|
||||||
|
259,2.761
|
||||||
|
260,2.674
|
||||||
|
261,2.450
|
||||||
|
262,2.491
|
||||||
|
263,2.543
|
||||||
|
264,2.732
|
||||||
|
265,3.679
|
||||||
|
266,2.325
|
||||||
|
267,2.529
|
||||||
|
268,2.344
|
||||||
|
269,2.534
|
||||||
|
270,2.691
|
||||||
|
271,3.176
|
||||||
|
272,2.492
|
||||||
|
273,2.721
|
||||||
|
274,2.587
|
||||||
|
275,2.594
|
||||||
|
276,2.326
|
||||||
|
277,3.434
|
||||||
|
278,3.514
|
||||||
|
279,2.415
|
||||||
|
280,2.481
|
||||||
|
281,2.478
|
||||||
|
282,2.555
|
||||||
|
283,3.303
|
||||||
|
284,3.098
|
||||||
|
285,2.451
|
||||||
|
286,2.552
|
||||||
|
287,2.413
|
||||||
|
288,2.613
|
||||||
|
289,3.194
|
||||||
|
290,3.191
|
||||||
|
291,2.338
|
||||||
|
292,2.561
|
||||||
|
293,2.785
|
||||||
|
294,2.240
|
||||||
|
295,3.324
|
||||||
|
296,2.767
|
||||||
|
297,2.589
|
||||||
|
298,2.608
|
||||||
|
299,2.432
|
||||||
|
300,2.444
|
||||||
|
301,2.968
|
||||||
|
302,3.792
|
||||||
|
303,2.590
|
||||||
|
304,2.335
|
||||||
|
305,2.520
|
||||||
|
306,2.435
|
||||||
|
307,3.613
|
||||||
|
308,2.681
|
||||||
|
309,2.692
|
||||||
|
310,2.329
|
||||||
|
311,2.580
|
||||||
|
312,2.355
|
||||||
|
313,3.084
|
||||||
|
314,3.026
|
||||||
|
315,2.551
|
||||||
|
316,2.490
|
||||||
|
317,2.481
|
||||||
|
318,2.553
|
||||||
|
319,2.619
|
||||||
|
320,3.350
|
||||||
|
321,2.885
|
||||||
|
322,2.576
|
||||||
|
323,2.456
|
||||||
|
324,2.441
|
||||||
|
325,3.223
|
||||||
|
326,3.031
|
||||||
|
327,3.055
|
||||||
|
328,2.592
|
||||||
|
329,2.499
|
||||||
|
330,2.354
|
||||||
|
331,2.573
|
||||||
|
332,3.323
|
||||||
|
333,3.357
|
||||||
|
334,2.241
|
||||||
|
335,2.319
|
||||||
|
336,2.472
|
||||||
|
337,2.609
|
||||||
|
338,3.565
|
||||||
|
339,2.607
|
||||||
|
340,2.539
|
||||||
|
341,2.440
|
||||||
|
342,2.483
|
||||||
|
343,2.626
|
||||||
|
344,3.407
|
||||||
|
345,2.772
|
||||||
|
346,2.491
|
||||||
|
347,2.456
|
||||||
|
348,2.553
|
||||||
|
349,2.773
|
||||||
|
350,3.239
|
||||||
|
351,4.079
|
||||||
|
352,2.346
|
||||||
|
353,2.177
|
||||||
|
354,2.562
|
||||||
|
355,2.350
|
||||||
|
356,3.329
|
||||||
|
357,3.383
|
||||||
|
358,2.441
|
||||||
|
359,2.399
|
||||||
|
360,2.530
|
||||||
|
361,2.455
|
||||||
|
362,3.219
|
||||||
|
363,2.879
|
||||||
|
364,2.726
|
||||||
|
365,2.418
|
||||||
|
366,2.511
|
||||||
|
367,2.544
|
||||||
|
368,3.077
|
||||||
|
369,2.926
|
||||||
|
370,2.571
|
||||||
|
371,2.595
|
||||||
|
372,2.534
|
||||||
|
373,2.367
|
||||||
|
374,2.671
|
||||||
|
375,4.222
|
||||||
|
376,2.411
|
||||||
|
377,2.569
|
||||||
|
378,2.493
|
||||||
|
379,2.464
|
||||||
|
380,2.691
|
||||||
|
381,3.474
|
||||||
|
382,2.697
|
||||||
|
383,2.541
|
||||||
|
384,2.494
|
||||||
|
385,2.476
|
||||||
|
386,2.473
|
||||||
|
387,3.464
|
||||||
|
388,3.084
|
||||||
|
389,2.144
|
||||||
|
390,2.503
|
||||||
|
391,2.501
|
||||||
|
392,2.525
|
||||||
|
393,3.335
|
||||||
|
394,2.919
|
||||||
|
395,2.334
|
||||||
|
396,2.557
|
||||||
|
397,2.579
|
||||||
|
398,2.567
|
||||||
|
399,4.120
|
||||||
|
400,3.297
|
||||||
|
401,2.561
|
||||||
|
402,2.428
|
||||||
|
403,2.495
|
||||||
|
404,2.729
|
||||||
|
405,3.752
|
||||||
|
406,2.783
|
||||||
|
407,2.509
|
||||||
|
408,2.337
|
||||||
|
409,2.589
|
||||||
|
410,2.556
|
||||||
|
411,3.449
|
||||||
|
412,2.702
|
||||||
|
413,2.742
|
||||||
|
414,2.384
|
||||||
|
415,2.759
|
||||||
|
416,2.290
|
||||||
|
417,3.374
|
||||||
|
418,2.934
|
||||||
|
419,2.546
|
||||||
|
420,2.228
|
||||||
|
421,2.672
|
||||||
|
422,2.369
|
||||||
|
423,3.442
|
||||||
|
424,3.484
|
||||||
|
425,2.621
|
||||||
|
426,2.279
|
||||||
|
427,2.529
|
||||||
|
428,2.889
|
||||||
|
429,2.910
|
||||||
|
430,2.981
|
||||||
|
431,2.957
|
||||||
|
432,2.420
|
||||||
|
433,2.398
|
||||||
|
434,2.310
|
||||||
|
435,3.662
|
||||||
|
436,2.422
|
||||||
|
437,2.676
|
||||||
|
438,2.557
|
||||||
|
439,2.527
|
||||||
|
440,2.564
|
||||||
|
441,2.649
|
||||||
|
442,3.168
|
||||||
|
443,2.499
|
||||||
|
444,2.737
|
||||||
|
445,2.637
|
||||||
|
446,2.509
|
||||||
|
447,2.716
|
||||||
|
448,3.845
|
||||||
|
449,2.654
|
||||||
|
450,2.536
|
||||||
|
451,2.366
|
||||||
|
452,2.526
|
||||||
|
453,2.906
|
||||||
|
454,3.101
|
||||||
|
455,2.809
|
||||||
|
456,2.466
|
||||||
|
457,2.502
|
||||||
|
458,2.767
|
||||||
|
459,2.486
|
||||||
|
460,3.137
|
||||||
|
461,3.402
|
||||||
|
462,2.187
|
||||||
|
463,2.398
|
||||||
|
464,2.392
|
||||||
|
465,2.614
|
||||||
|
466,3.371
|
||||||
|
467,2.847
|
||||||
|
468,2.463
|
||||||
|
469,2.639
|
||||||
|
470,2.288
|
||||||
|
471,2.562
|
||||||
|
472,3.381
|
||||||
|
473,3.491
|
||||||
|
474,2.521
|
||||||
|
475,2.397
|
||||||
|
476,2.431
|
||||||
|
477,2.759
|
||||||
|
478,3.222
|
||||||
|
479,2.957
|
||||||
|
480,2.470
|
||||||
|
481,2.403
|
||||||
|
482,2.560
|
||||||
|
483,2.470
|
||||||
|
484,3.451
|
||||||
|
485,2.905
|
||||||
|
486,2.583
|
||||||
|
487,2.329
|
||||||
|
488,2.798
|
||||||
|
489,2.289
|
||||||
|
490,2.882
|
||||||
|
491,2.903
|
||||||
|
492,2.627
|
||||||
|
493,2.897
|
||||||
|
494,2.321
|
||||||
|
495,2.472
|
||||||
|
496,2.882
|
||||||
|
497,3.844
|
||||||
|
498,3.096
|
||||||
|
499,2.525
|
||||||
|
500,2.250
|
||||||
|
501,2.477
|
||||||
|
502,2.728
|
||||||
|
503,3.391
|
||||||
|
504,2.539
|
||||||
|
505,2.635
|
||||||
|
506,2.542
|
||||||
|
507,2.435
|
||||||
|
508,3.011
|
||||||
|
509,3.042
|
||||||
|
510,2.965
|
||||||
|
511,2.273
|
||||||
|
512,2.433
|
||||||
|
513,3.020
|
||||||
|
514,2.776
|
||||||
|
515,3.646
|
||||||
|
516,2.856
|
||||||
|
517,2.886
|
||||||
|
518,2.522
|
||||||
|
519,2.528
|
||||||
|
520,4.396
|
||||||
|
521,3.397
|
||||||
|
522,2.218
|
||||||
|
523,2.433
|
||||||
|
524,2.605
|
||||||
|
525,3.504
|
||||||
|
526,3.087
|
||||||
|
527,3.186
|
||||||
|
528,2.343
|
||||||
|
529,2.433
|
||||||
|
530,2.900
|
||||||
|
531,3.000
|
||||||
|
532,3.511
|
||||||
|
533,2.663
|
||||||
|
534,2.699
|
||||||
|
535,2.423
|
||||||
|
536,3.136
|
||||||
|
537,2.802
|
||||||
|
538,3.151
|
||||||
|
539,2.507
|
||||||
|
540,2.973
|
||||||
|
541,2.325
|
||||||
|
542,3.322
|
||||||
|
543,3.260
|
||||||
|
544,3.525
|
||||||
|
545,2.846
|
||||||
|
546,2.125
|
||||||
|
547,2.697
|
||||||
|
548,2.829
|
||||||
|
549,3.389
|
||||||
|
550,2.758
|
||||||
|
551,2.866
|
||||||
|
552,2.338
|
||||||
|
553,3.115
|
||||||
|
554,2.500
|
||||||
|
555,3.387
|
||||||
|
556,2.851
|
||||||
|
557,2.511
|
||||||
|
558,2.459
|
||||||
|
559,3.107
|
||||||
|
560,2.521
|
||||||
|
561,3.308
|
||||||
|
562,2.782
|
||||||
|
563,2.810
|
||||||
|
564,2.323
|
||||||
|
565,3.259
|
||||||
|
566,2.366
|
||||||
|
567,3.542
|
||||||
|
568,2.929
|
||||||
|
569,2.299
|
||||||
|
570,2.336
|
||||||
|
571,3.027
|
||||||
|
572,2.540
|
||||||
|
573,3.409
|
||||||
|
574,2.784
|
||||||
|
575,2.444
|
||||||
|
576,2.437
|
||||||
|
577,2.734
|
||||||
|
578,2.591
|
||||||
|
579,3.845
|
||||||
|
580,3.212
|
||||||
|
581,2.802
|
||||||
|
582,2.370
|
||||||
|
583,2.704
|
||||||
|
584,2.624
|
||||||
|
585,4.023
|
||||||
|
586,2.360
|
||||||
|
587,2.759
|
||||||
|
588,2.511
|
||||||
|
589,2.608
|
||||||
|
590,2.922
|
||||||
|
591,3.081
|
||||||
|
592,3.271
|
||||||
|
593,2.471
|
||||||
|
594,2.516
|
||||||
|
595,2.474
|
||||||
|
596,2.814
|
||||||
|
597,3.127
|
||||||
|
598,2.537
|
||||||
|
599,3.080
|
||||||
|
600,2.341
|
||||||
|
601,3.027
|
||||||
|
602,2.766
|
||||||
|
603,2.984
|
||||||
|
604,2.450
|
||||||
|
605,2.922
|
||||||
|
606,2.481
|
||||||
|
607,2.616
|
||||||
|
608,2.541
|
||||||
|
609,3.462
|
||||||
|
610,2.971
|
||||||
|
611,2.955
|
||||||
|
612,2.258
|
||||||
|
613,2.682
|
||||||
|
614,2.770
|
||||||
|
615,3.119
|
||||||
|
616,2.792
|
||||||
|
617,2.598
|
||||||
|
618,2.260
|
||||||
|
619,2.441
|
||||||
|
620,2.536
|
||||||
|
621,3.425
|
||||||
|
622,2.958
|
||||||
|
623,2.722
|
||||||
|
624,2.099
|
||||||
|
625,2.400
|
||||||
|
626,2.570
|
||||||
|
627,3.295
|
||||||
|
628,2.919
|
||||||
|
629,2.737
|
||||||
|
630,2.311
|
||||||
|
631,2.408
|
||||||
|
632,2.514
|
||||||
|
633,3.325
|
||||||
|
634,2.767
|
||||||
|
635,2.724
|
||||||
|
636,2.288
|
||||||
|
637,2.680
|
||||||
|
638,2.347
|
||||||
|
639,2.902
|
||||||
|
640,3.058
|
||||||
|
641,2.770
|
||||||
|
642,2.522
|
||||||
|
643,2.406
|
||||||
|
644,2.539
|
||||||
|
645,2.753
|
||||||
|
646,3.215
|
||||||
|
647,2.636
|
||||||
|
648,2.639
|
||||||
|
649,2.666
|
||||||
|
650,2.392
|
||||||
|
651,2.408
|
||||||
|
652,3.515
|
||||||
|
653,2.687
|
||||||
|
654,2.589
|
||||||
|
655,2.428
|
||||||
|
656,2.375
|
||||||
|
657,2.619
|
||||||
|
658,3.308
|
||||||
|
659,2.664
|
||||||
|
660,2.752
|
||||||
|
661,2.456
|
||||||
|
662,2.365
|
||||||
|
663,2.533
|
||||||
|
664,3.354
|
||||||
|
665,2.812
|
||||||
|
666,2.684
|
||||||
|
667,2.349
|
||||||
|
668,2.441
|
||||||
|
669,2.714
|
||||||
|
670,2.769
|
||||||
|
671,3.368
|
||||||
|
672,2.624
|
||||||
|
673,2.308
|
||||||
|
674,2.365
|
||||||
|
675,2.634
|
||||||
|
676,2.617
|
||||||
|
677,3.350
|
||||||
|
678,2.733
|
||||||
|
679,2.623
|
||||||
|
680,2.462
|
||||||
|
681,2.494
|
||||||
|
682,2.460
|
||||||
|
683,3.463
|
||||||
|
684,2.537
|
||||||
|
685,2.628
|
||||||
|
686,2.674
|
||||||
|
687,2.381
|
||||||
|
688,2.516
|
||||||
|
689,3.586
|
||||||
|
690,2.681
|
||||||
|
691,2.676
|
||||||
|
692,2.289
|
||||||
|
693,2.726
|
||||||
|
694,2.303
|
||||||
|
695,2.934
|
||||||
|
696,3.339
|
||||||
|
697,2.606
|
||||||
|
698,2.187
|
||||||
|
699,2.687
|
||||||
|
700,2.328
|
||||||
|
701,3.062
|
||||||
|
702,2.930
|
||||||
|
703,2.871
|
||||||
|
704,2.313
|
||||||
|
705,2.582
|
||||||
|
706,2.464
|
||||||
|
707,2.521
|
||||||
|
708,3.304
|
||||||
|
709,2.492
|
||||||
|
710,2.723
|
||||||
|
711,2.587
|
||||||
|
712,2.608
|
||||||
|
713,2.574
|
||||||
|
714,4.002
|
||||||
|
715,3.011
|
||||||
|
716,2.227
|
||||||
|
717,2.374
|
||||||
|
718,2.343
|
||||||
|
719,2.541
|
||||||
|
720,3.580
|
||||||
|
721,2.854
|
||||||
|
@@ -43,6 +43,7 @@ Measured at 1440p on the development workstation: Bazzite, Ryzen 7 7700X, 64 GB
|
|||||||
| `0.1.0` | Collision and packaging | PASS — no blocking collision, no invisible walls, no seam gaps (see audit note) | `-qaselftest` on the packaged build, 2026-11-08 | 2026-11-08 |
|
| `0.1.0` | Collision and packaging | PASS — no blocking collision, no invisible walls, no seam gaps (see audit note) | `-qaselftest` on the packaged build, 2026-11-08 | 2026-11-08 |
|
||||||
| `0.1.0` | 60 FPS at 1440p | PASS — 2.42 ms avg (414 fps), p99 3.01 ms at 2560×1440, TSR on, VSync off, no FG | `-qaselftest` perf capture, `Docs/perf/0.1.0-walk-frametimes.csv` | 2026-11-08 |
|
| `0.1.0` | 60 FPS at 1440p | PASS — 2.42 ms avg (414 fps), p99 3.01 ms at 2560×1440, TSR on, VSync off, no FG | `-qaselftest` perf capture, `Docs/perf/0.1.0-walk-frametimes.csv` | 2026-11-08 |
|
||||||
| `0.2.0` | 60 FPS at 1440p | PASS — 2.64 ms avg (379 fps), p50 2.54, p95 3.39, p99 3.76, max 4.05 ms at 2560×1440, TSR on, VSync off, no FG | `-qaselftest` perf capture, `Docs/perf/0.2.0-walk-frametimes.csv` | 2026-11-09 |
|
| `0.2.0` | 60 FPS at 1440p | PASS — 2.64 ms avg (379 fps), p50 2.54, p95 3.39, p99 3.76, max 4.05 ms at 2560×1440, TSR on, VSync off, no FG | `-qaselftest` perf capture, `Docs/perf/0.2.0-walk-frametimes.csv` | 2026-11-09 |
|
||||||
|
| `0.2.0` | Debug overlay cost | PASS — same route with the F3 overlay drawn: 2.77 ms avg (361 fps), p50 2.64, p95 3.52, p99 3.87, max 4.43 ms; about **5 %** heavier, still 6× the floor. The overlay is on for `-perf`/`-qaselftest`, off in the built demo | `Docs/perf/0.2.0-walk-frametimes-overlay.csv` | 2026-11-09 |
|
||||||
| `0.1.0` | Fresh checkout build | PASS — clean clone of `main` (`4bc41e9`), `git lfs pull` + `check-lfs.sh` OK (130 LFS files), both `GigLineEditor` and `GigLine` targets built with the documented engine | `/tmp/fresh-check`, 2026-11-08 | 2026-11-08 |
|
| `0.1.0` | Fresh checkout build | PASS — clean clone of `main` (`4bc41e9`), `git lfs pull` + `check-lfs.sh` OK (130 LFS files), both `GigLineEditor` and `GigLine` targets built with the documented engine | `/tmp/fresh-check`, 2026-11-08 | 2026-11-08 |
|
||||||
| `0.1.0` | Packaged Linux build | PASS — packaged Development build launches straight into DemoMap, no missing-asset/linker errors; controls shown in-game and in `Docs/controls.md` | measurement recorded 2026-11-08; the capture was removed from the repository 2026-11-09 | 2026-11-08 |
|
| `0.1.0` | Packaged Linux build | PASS — packaged Development build launches straight into DemoMap, no missing-asset/linker errors; controls shown in-game and in `Docs/controls.md` | measurement recorded 2026-11-08; the capture was removed from the repository 2026-11-09 | 2026-11-08 |
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -15,6 +15,7 @@
|
|||||||
#include "Engine/World.h"
|
#include "Engine/World.h"
|
||||||
#include "TimerManager.h"
|
#include "TimerManager.h"
|
||||||
#include "Containers/Ticker.h"
|
#include "Containers/Ticker.h"
|
||||||
|
#include "HAL/IConsoleManager.h"
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
#include "Misc/CommandLine.h"
|
#include "Misc/CommandLine.h"
|
||||||
#include "Misc/Parse.h"
|
#include "Misc/Parse.h"
|
||||||
@@ -59,7 +60,7 @@ AGigLineCharacter::AGigLineCharacter()
|
|||||||
// clips resolve without a retarget step; it is hidden while the first-person
|
// clips resolve without a retarget step; it is hidden while the first-person
|
||||||
// camera is active and shown in third person.
|
// camera is active and shown in third person.
|
||||||
static ConstructorHelpers::FObjectFinder<USkeletalMesh> BodyFinder(
|
static ConstructorHelpers::FObjectFinder<USkeletalMesh> BodyFinder(
|
||||||
TEXT("/Game/Test/Character/CharacterV2.CharacterV2"));
|
TEXT("/Game/Test/Character/CharacterV3.CharacterV3"));
|
||||||
if (BodyFinder.Succeeded())
|
if (BodyFinder.Succeeded())
|
||||||
{
|
{
|
||||||
GetMesh()->SetSkeletalMesh(BodyFinder.Object);
|
GetMesh()->SetSkeletalMesh(BodyFinder.Object);
|
||||||
@@ -73,13 +74,13 @@ AGigLineCharacter::AGigLineCharacter()
|
|||||||
GetMesh()->SetMaterial(0, SkinFinder.Object);
|
GetMesh()->SetMaterial(0, SkinFinder.Object);
|
||||||
}
|
}
|
||||||
static ConstructorHelpers::FObjectFinder<UAnimSequence> IdleFinder(
|
static ConstructorHelpers::FObjectFinder<UAnimSequence> IdleFinder(
|
||||||
TEXT("/Game/Test/Character/CharacterV2Human_rig_GigLine_Idle.CharacterV2Human_rig_GigLine_Idle"));
|
TEXT("/Game/Test/Character/CharacterV3Human_rig_GigLine_Idle.CharacterV3Human_rig_GigLine_Idle"));
|
||||||
if (IdleFinder.Succeeded())
|
if (IdleFinder.Succeeded())
|
||||||
{
|
{
|
||||||
IdleAnimation = IdleFinder.Object;
|
IdleAnimation = IdleFinder.Object;
|
||||||
}
|
}
|
||||||
static ConstructorHelpers::FObjectFinder<UAnimSequence> WalkFinder(
|
static ConstructorHelpers::FObjectFinder<UAnimSequence> WalkFinder(
|
||||||
TEXT("/Game/Test/Character/CharacterV2Human_rig_GigLine_Walk.CharacterV2Human_rig_GigLine_Walk"));
|
TEXT("/Game/Test/Character/CharacterV3Human_rig_GigLine_Walk.CharacterV3Human_rig_GigLine_Walk"));
|
||||||
if (WalkFinder.Succeeded())
|
if (WalkFinder.Succeeded())
|
||||||
{
|
{
|
||||||
WalkAnimation = WalkFinder.Object;
|
WalkAnimation = WalkFinder.Object;
|
||||||
@@ -132,6 +133,8 @@ AGigLineCharacter::AGigLineCharacter()
|
|||||||
TEXT("/Game/Input/IA_Jump.IA_Jump"));
|
TEXT("/Game/Input/IA_Jump.IA_Jump"));
|
||||||
static ConstructorHelpers::FObjectFinder<UInputAction> ResetF(
|
static ConstructorHelpers::FObjectFinder<UInputAction> ResetF(
|
||||||
TEXT("/Game/Input/IA_Reset.IA_Reset"));
|
TEXT("/Game/Input/IA_Reset.IA_Reset"));
|
||||||
|
static ConstructorHelpers::FObjectFinder<UInputAction> DebugF(
|
||||||
|
TEXT("/Game/Input/IA_ToggleDebug.IA_ToggleDebug"));
|
||||||
static ConstructorHelpers::FObjectFinder<UInputAction> CamF(
|
static ConstructorHelpers::FObjectFinder<UInputAction> CamF(
|
||||||
TEXT("/Game/Input/IA_ToggleCamera.IA_ToggleCamera"));
|
TEXT("/Game/Input/IA_ToggleCamera.IA_ToggleCamera"));
|
||||||
static ConstructorHelpers::FObjectFinder<UInputAction> PauseF(
|
static ConstructorHelpers::FObjectFinder<UInputAction> PauseF(
|
||||||
@@ -146,6 +149,7 @@ AGigLineCharacter::AGigLineCharacter()
|
|||||||
JumpAction = JumpF.Object;
|
JumpAction = JumpF.Object;
|
||||||
ResetAction = ResetF.Object;
|
ResetAction = ResetF.Object;
|
||||||
ToggleCameraAction = CamF.Object;
|
ToggleCameraAction = CamF.Object;
|
||||||
|
ToggleDebugAction = DebugF.Object;
|
||||||
PauseAction = PauseF.Object;
|
PauseAction = PauseF.Object;
|
||||||
|
|
||||||
if (!MappingContext || !MoveAction || !MoveBackAction || !StrafeAction || !StrafeLeftAction
|
if (!MappingContext || !MoveAction || !MoveBackAction || !StrafeAction || !StrafeLeftAction
|
||||||
@@ -257,6 +261,28 @@ void AGigLineCharacter::BeginPlay()
|
|||||||
// with `-thirdperson` so a capture can show the walk clip mid-stride: an idle
|
// with `-thirdperson` so a capture can show the walk clip mid-stride: an idle
|
||||||
// shot cannot prove the animation set, and a still cannot show a stride.
|
// shot cannot prove the animation set, and a still cannot show a stride.
|
||||||
bWalkForever = FParse::Param(FCommandLine::Get(), TEXT("walk"));
|
bWalkForever = FParse::Param(FCommandLine::Get(), TEXT("walk"));
|
||||||
|
|
||||||
|
// `-perf` starts the overlay on: the performance capture and any manual frame
|
||||||
|
// check should not depend on someone pressing F3 first. The built demo has
|
||||||
|
// neither switch, so the counter stays hidden for players.
|
||||||
|
if (FParse::Param(FCommandLine::Get(), TEXT("perf")) || FParse::Param(FCommandLine::Get(), TEXT("qaselftest")))
|
||||||
|
{
|
||||||
|
if (IConsoleVariable* Var = IConsoleManager::Get().FindConsoleVariable(TEXT("gigline.Debug")))
|
||||||
|
{
|
||||||
|
Var->Set(1, ECVF_SetByConsole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AGigLineCharacter::ToggleDebugOverlay()
|
||||||
|
{
|
||||||
|
static IConsoleVariable* Var = IConsoleManager::Get().FindConsoleVariable(TEXT("gigline.Debug"));
|
||||||
|
if (Var)
|
||||||
|
{
|
||||||
|
const bool bNowOn = Var->GetInt() == 0;
|
||||||
|
Var->Set(bNowOn ? 1 : 0, ECVF_SetByConsole);
|
||||||
|
UE_LOG(LogTemp, Log, TEXT("GigLine: debug overlay %s"), bNowOn ? TEXT("on") : TEXT("off"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AGigLineCharacter::SetReviewWalk(bool bEnable)
|
void AGigLineCharacter::SetReviewWalk(bool bEnable)
|
||||||
@@ -658,6 +684,10 @@ void AGigLineCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputCo
|
|||||||
{
|
{
|
||||||
Input->BindAction(ToggleCameraAction, ETriggerEvent::Started, this, &AGigLineCharacter::ToggleCamera);
|
Input->BindAction(ToggleCameraAction, ETriggerEvent::Started, this, &AGigLineCharacter::ToggleCamera);
|
||||||
}
|
}
|
||||||
|
if (ToggleDebugAction)
|
||||||
|
{
|
||||||
|
Input->BindAction(ToggleDebugAction, ETriggerEvent::Started, this, &AGigLineCharacter::ToggleDebugOverlay);
|
||||||
|
}
|
||||||
if (JumpAction)
|
if (JumpAction)
|
||||||
{
|
{
|
||||||
Input->BindAction(JumpAction, ETriggerEvent::Started, this, &AGigLineCharacter::StartJump);
|
Input->BindAction(JumpAction, ETriggerEvent::Started, this, &AGigLineCharacter::StartJump);
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ protected:
|
|||||||
void TogglePause();
|
void TogglePause();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/** True while the third-person rig is the active view (for the debug overlay). */
|
||||||
|
bool IsThirdPerson() const { return bThirdPerson; }
|
||||||
|
|
||||||
/** Review harness: hold or release forward input from the screenshot actor. */
|
/** Review harness: hold or release forward input from the screenshot actor. */
|
||||||
void SetReviewWalk(bool bEnable);
|
void SetReviewWalk(bool bEnable);
|
||||||
|
|
||||||
@@ -172,6 +175,13 @@ protected:
|
|||||||
/** Applies the `-walk` forward input when the flag is set and the pawn is grounded. */
|
/** Applies the `-walk` forward input when the flag is set and the pawn is grounded. */
|
||||||
void WalkForever();
|
void WalkForever();
|
||||||
|
|
||||||
|
/** Debug-overlay action (F3). */
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
||||||
|
TObjectPtr<UInputAction> ToggleDebugAction;
|
||||||
|
|
||||||
|
/** Flips the gigline.Debug console variable that the HUD reads. */
|
||||||
|
void ToggleDebugOverlay();
|
||||||
|
|
||||||
/** Toggle-camera action (V). */
|
/** Toggle-camera action (V). */
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
||||||
TObjectPtr<UInputAction> ToggleCameraAction;
|
TObjectPtr<UInputAction> ToggleCameraAction;
|
||||||
|
|||||||
@@ -2,11 +2,61 @@
|
|||||||
|
|
||||||
#include "Engine/Canvas.h"
|
#include "Engine/Canvas.h"
|
||||||
#include "Engine/Engine.h"
|
#include "Engine/Engine.h"
|
||||||
|
#include "GameFramework/PlayerController.h"
|
||||||
|
#include "GigLineCharacter.h"
|
||||||
|
#include "HAL/IConsoleManager.h"
|
||||||
|
#include "Kismet/GameplayStatics.h"
|
||||||
|
|
||||||
|
// Console variable so a packaged build can be checked without a rebuild:
|
||||||
|
// gigline.Debug 1
|
||||||
|
// The HUD reads it every frame; the F3 binding toggles it.
|
||||||
|
static TAutoConsoleVariable<int32> CVarGigLineDebug(
|
||||||
|
TEXT("gigline.Debug"),
|
||||||
|
0,
|
||||||
|
TEXT("Draw the performance and state overlay (0=off, 1=on). F3 toggles it."),
|
||||||
|
ECVF_Cheat);
|
||||||
|
|
||||||
|
void AGigLineHUD::UpdateFrameStats(float DeltaSeconds)
|
||||||
|
{
|
||||||
|
if (DeltaSeconds <= 0.0f)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++FramesDrawn;
|
||||||
|
const float Ms = DeltaSeconds * 1000.0f;
|
||||||
|
if (WarmupSeconds > 0.0f)
|
||||||
|
{
|
||||||
|
WarmupSeconds -= DeltaSeconds;
|
||||||
|
SmoothedFrameMs = FMath::Lerp(SmoothedFrameMs, Ms, 0.1f);
|
||||||
|
WorstFrameMs = Ms;
|
||||||
|
WorstWindowSeconds = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// A 0.9/0.1 EMA settles in a few frames and still reacts to a stall.
|
||||||
|
SmoothedFrameMs = FMath::Lerp(SmoothedFrameMs, Ms, 0.1f);
|
||||||
|
WorstFrameMs = FMath::Max(WorstFrameMs, Ms);
|
||||||
|
// Rolling worst-frame window: a spike stays visible for two seconds, so a
|
||||||
|
// hitch is not missed between glances (and not averaged away).
|
||||||
|
WorstWindowSeconds += DeltaSeconds;
|
||||||
|
if (WorstWindowSeconds >= 2.0f)
|
||||||
|
{
|
||||||
|
WorstWindowSeconds = 0.0f;
|
||||||
|
WorstFrameMs = Ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AGigLineHUD::DrawHUD()
|
void AGigLineHUD::DrawHUD()
|
||||||
{
|
{
|
||||||
Super::DrawHUD();
|
Super::DrawHUD();
|
||||||
|
|
||||||
|
// Console variable is authoritative; the UPROPERTY is the per-instance default
|
||||||
|
// for tests that set it before BeginPlay.
|
||||||
|
if (IConsoleVariable* Var = IConsoleManager::Get().FindConsoleVariable(TEXT("gigline.Debug")))
|
||||||
|
{
|
||||||
|
bShowDebug = Var->GetInt() != 0;
|
||||||
|
}
|
||||||
|
UpdateFrameStats(GetWorld() ? GetWorld()->GetDeltaSeconds() : 0.0f);
|
||||||
|
|
||||||
if (!Canvas || AttributionLine.IsEmpty())
|
if (!Canvas || AttributionLine.IsEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -37,4 +87,35 @@ void AGigLineHUD::DrawHUD()
|
|||||||
DrawText(ControlsLine, Shadow, CX + 1.0f, CY + 1.0f, nullptr, TextScale * 0.82f);
|
DrawText(ControlsLine, Shadow, CX + 1.0f, CY + 1.0f, nullptr, TextScale * 0.82f);
|
||||||
DrawText(ControlsLine, Ink, CX, CY, nullptr, TextScale * 0.82f);
|
DrawText(ControlsLine, Ink, CX, CY, nullptr, TextScale * 0.82f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!bShowDebug)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performance and state readout, top-left. Everything here is cheap enough to
|
||||||
|
// leave on during a capture: four formatted lines and no additional passes.
|
||||||
|
const APawn* Pawn = UGameplayStatics::GetPlayerPawn(this, 0);
|
||||||
|
const AGigLineCharacter* Character = Cast<AGigLineCharacter>(Pawn);
|
||||||
|
const float Fps = SmoothedFrameMs > 0.0f ? 1000.0f / SmoothedFrameMs : 0.0f;
|
||||||
|
const FVector Where = Pawn ? Pawn->GetActorLocation() / 100.0f : FVector::ZeroVector;
|
||||||
|
const float Speed = Pawn ? Pawn->GetVelocity().Size2D() / 100.0f : 0.0f;
|
||||||
|
|
||||||
|
const FString Header = FString::Printf(TEXT("%.0f FPS %.2f ms worst %.2f ms"), Fps, SmoothedFrameMs, WorstFrameMs);
|
||||||
|
const FString State = FString::Printf(TEXT("%s %.2f m/s frames %lld"),
|
||||||
|
Character && Character->IsThirdPerson() ? TEXT("third person") : TEXT("first person"),
|
||||||
|
Speed, FramesDrawn);
|
||||||
|
const FString Place = FString::Printf(TEXT("x %.1f y %.1f z %.1f m"), Where.X, Where.Y, Where.Z);
|
||||||
|
const FString Hint = TEXT("F3 hide");
|
||||||
|
|
||||||
|
const FLinearColor DebugInk(0.85f, 1.0f, 0.55f, 0.95f);
|
||||||
|
const FLinearColor DebugShadow(0.0f, 0.0f, 0.0f, 0.6f);
|
||||||
|
const float DX = MarginPx;
|
||||||
|
float DY = MarginPx;
|
||||||
|
for (const FString& Line : { Header, State, Place, Hint })
|
||||||
|
{
|
||||||
|
DrawText(Line, DebugShadow, DX + 1.0f, DY + 1.0f, nullptr, TextScale * 0.9f);
|
||||||
|
DrawText(Line, DebugInk, DX, DY, nullptr, TextScale * 0.9f);
|
||||||
|
DY += 22.0f * TextScale * 0.9f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -40,6 +40,19 @@ public:
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Attribution")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Attribution")
|
||||||
FString LicenceLine = TEXT("Data \u00A9 OpenStreetMap contributors, ODbL 1.0 \u2014 openstreetmap.org/copyright");
|
FString LicenceLine = TEXT("Data \u00A9 OpenStreetMap contributors, ODbL 1.0 \u2014 openstreetmap.org/copyright");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performance and state readout, top-left, off by default.
|
||||||
|
*
|
||||||
|
* Toggle in game with **F3**, or start with it on by passing `-perf` (the
|
||||||
|
* performance capture does). The built demo ships with it hidden so a player
|
||||||
|
* does not see an FPS counter over Hollywood Boulevard.
|
||||||
|
*/
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Debug")
|
||||||
|
bool bShowDebug = false;
|
||||||
|
|
||||||
|
/** Smoothed FPS and a rolling frame-time window, refreshed every frame. */
|
||||||
|
void UpdateFrameStats(float DeltaSeconds);
|
||||||
|
|
||||||
/** Screen-space margin in pixels. */
|
/** Screen-space margin in pixels. */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Attribution")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Attribution")
|
||||||
float MarginPx = 18.0f;
|
float MarginPx = 18.0f;
|
||||||
@@ -47,4 +60,25 @@ public:
|
|||||||
/** Text scale relative to the default canvas font. */
|
/** Text scale relative to the default canvas font. */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Attribution")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Attribution")
|
||||||
float TextScale = 1.45f;
|
float TextScale = 1.45f;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Exponential moving average of frame time, in milliseconds. */
|
||||||
|
float SmoothedFrameMs = 16.7f;
|
||||||
|
|
||||||
|
/** Worst frame in the rolling window, so a hitch is visible without a log. */
|
||||||
|
float WorstFrameMs = 0.0f;
|
||||||
|
|
||||||
|
/** Seconds until the rolling worst-frame window resets. */
|
||||||
|
float WorstWindowSeconds = 0.0f;
|
||||||
|
|
||||||
|
/** Frames drawn, so the overlay can show that the counter is live. */
|
||||||
|
int64 FramesDrawn = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seconds left in the warm-up window. The first frames of a session include
|
||||||
|
* shader and streaming hitches of several hundred milliseconds; without this
|
||||||
|
* the "worst" figure read 400 ms for the whole first two seconds and made a
|
||||||
|
* healthy run look broken.
|
||||||
|
*/
|
||||||
|
float WarmupSeconds = 2.0f;
|
||||||
};
|
};
|
||||||
@@ -92,6 +92,17 @@ void AGigLineShotActor::UpdateFollowCamera()
|
|||||||
if (AGigLineCharacter* Character = Cast<AGigLineCharacter>(Pawn))
|
if (AGigLineCharacter* Character = Cast<AGigLineCharacter>(Pawn))
|
||||||
{
|
{
|
||||||
Character->SetReviewWalk(true);
|
Character->SetReviewWalk(true);
|
||||||
|
// Park the walk clip at a quarter cycle the first frame of the shot, so the
|
||||||
|
// capture lands mid-stride. Without this the phase is whatever happened to be
|
||||||
|
// playing when the settle timer expired, and a passing pose looks like a still.
|
||||||
|
if (!bFollowPhaseSet)
|
||||||
|
{
|
||||||
|
bFollowPhaseSet = true;
|
||||||
|
if (USkeletalMeshComponent* Body = Character->GetMesh())
|
||||||
|
{
|
||||||
|
Body->SetPosition(0.25f, /*bFireNotifies=*/false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Offset in the pawn's frame: to its right, slightly above, looking at the
|
// Offset in the pawn's frame: to its right, slightly above, looking at the
|
||||||
// pelvis. Right-of-pawn gives a profile view, which is where a stride reads.
|
// pelvis. Right-of-pawn gives a profile view, which is where a stride reads.
|
||||||
@@ -143,6 +154,7 @@ void AGigLineShotActor::NextShot()
|
|||||||
// the pawn only holds forward input while a follow shot is being taken, so the
|
// the pawn only holds forward input while a follow shot is being taken, so the
|
||||||
// fixed-camera shots later in the list still find it at the spawn point.
|
// fixed-camera shots later in the list still find it at the spawn point.
|
||||||
const bool bFollowThisShot = ShotFollow.IsValidIndex(CurrentShot) && ShotFollow[CurrentShot];
|
const bool bFollowThisShot = ShotFollow.IsValidIndex(CurrentShot) && ShotFollow[CurrentShot];
|
||||||
|
bFollowPhaseSet = false;
|
||||||
if (AGigLineCharacter* Character = Cast<AGigLineCharacter>(UGameplayStatics::GetPlayerPawn(this, 0)))
|
if (AGigLineCharacter* Character = Cast<AGigLineCharacter>(UGameplayStatics::GetPlayerPawn(this, 0)))
|
||||||
{
|
{
|
||||||
Character->SetReviewWalk(bFollowThisShot);
|
Character->SetReviewWalk(bFollowThisShot);
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ private:
|
|||||||
/** Re-places the active camera at the follow offset behind the player pawn. */
|
/** Re-places the active camera at the follow offset behind the player pawn. */
|
||||||
void UpdateFollowCamera();
|
void UpdateFollowCamera();
|
||||||
|
|
||||||
|
/** True once the follow shot has parked the walk clip at a chosen phase. */
|
||||||
|
bool bFollowPhaseSet = false;
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
TObjectPtr<class APlayerController> PlayerController;
|
TObjectPtr<class APlayerController> PlayerController;
|
||||||
|
|
||||||
|
|||||||
+1
-14
@@ -130,19 +130,6 @@ What it shows: the arms hang down with a soft elbow bend, the hands sit at hip h
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. Third-person walk
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
- **File:** `demo/review-demo-third-person-walk.png`
|
|
||||||
- **View:** tracking camera, 4.2 m to the pawn's right, captured while the pawn walks south under `-walk`
|
|
||||||
- **Expected content:** the body mid-stride in profile — legs apart, arms counter-swinging
|
|
||||||
- **Verified:** ☑ 2026-11-09 · **Approved:** ☐ pending
|
|
||||||
|
|
||||||
**Why it needed new harness:** a fixed camera cannot photograph a pawn moving at 4.5 m/s. Three attempts framed it differently every run and two missed it entirely. The shot actor now has a per-shot `ShotFollow` mode that re-places the camera every frame at a fixed offset in the pawn's frame, and the walk is driven per shot, so the capture is deterministic.
|
|
||||||
|
|
||||||
**What it proves:** the walk clip plays and advances. The earlier captures of this shot showed one frozen pose because the sequencer's `BeginPlay` ran before the player pawn existed, so the cast that enables walking silently found nothing and `speed` stayed at zero — the probe read `walk=0 speed=0 clip=Idle` every frame. Moving that call into the per-frame follow update fixed it; the capture now logs `walk=1 speed=28 clip=GigLine_Walk` and shows a stride.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## The iteration loop (uncommitted)
|
## The iteration loop (uncommitted)
|
||||||
@@ -174,7 +161,7 @@ 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 |
|
| 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`) |
|
| 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`) |
|
| 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 fingers splay rather than relax — the bind's finger spread is carried into the pose | `0.2.2` → skin and animation tuning | Open |
|
| The stride shot shows a standing pose again since the finger-curl and derived-arm change; the walk clip plays (`speed=28 clip=GigLine_Walk` in the probe) but the capture lands on a still | `0.2.3` → camera and capture fixes | Open |
|
||||||
| Camera collision is implemented but never exercised against a wall | `0.2.0` → camera collision | 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 |
|
| 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 |
|
| 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 |
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -9,13 +9,6 @@ Actionable task list for this project. This file is the single, central place fo
|
|||||||
- When all steps in a version section are done: write a `CHANGELOG.md` entry, then remove the version section from this file.
|
- When all steps in a version section are done: write a `CHANGELOG.md` entry, then remove the version section from this file.
|
||||||
- Release gate: a version is tagged only on the owner's explicit go-ahead once its release checks pass, not automatically when the checkboxes close.
|
- Release gate: a version is tagged only on the owner's explicit go-ahead once its release checks pass, not automatically when the checkboxes close.
|
||||||
|
|
||||||
## 0.2.1 — Rig fixes (patch)
|
|
||||||
|
|
||||||
### Patch tasks
|
|
||||||
|
|
||||||
- [ ] Fix skeletal/rigging defects reported after `0.2.0`.
|
|
||||||
- [ ] Tag `v0.2.1` and write `CHANGELOG.md` entry; then remove this section.
|
|
||||||
|
|
||||||
## 0.2.2 — Skin and hair tuning (patch)
|
## 0.2.2 — Skin and hair tuning (patch)
|
||||||
|
|
||||||
### Patch tasks
|
### Patch tasks
|
||||||
|
|||||||
@@ -55,6 +55,51 @@ ELBOW = 0.18
|
|||||||
|
|
||||||
PARTS: list[dict] = []
|
PARTS: list[dict] = []
|
||||||
|
|
||||||
|
# The .blend stores the raw A-pose bind: `mpfb_character_export.py --pose idle`
|
||||||
|
# bakes the arms down only in the exported FBX, not in the file. A clip that
|
||||||
|
# animates only swing therefore leaves the arms out in an A — which is exactly how
|
||||||
|
# the first third-person render looked. These are the same deltas `IDLE_POSE` uses,
|
||||||
|
# applied as a base that every key sits on top of.
|
||||||
|
# Finger curl, in radians per joint. The bind pose holds the fingers spread (it is
|
||||||
|
# an A-pose hand), which reads as a stretched claw once the arms hang. Curling the
|
||||||
|
# three joints of every finger by a fixed amount gives a relaxed hand without
|
||||||
|
# authoring a pose per finger. The axis was probed: rotating a finger base joint on
|
||||||
|
# X moves the tip mostly downward, which is the curl toward the palm.
|
||||||
|
FINGER_CURL = (0.28, 0.34, 0.22)
|
||||||
|
|
||||||
|
PARTS: list[dict] = []
|
||||||
|
|
||||||
|
|
||||||
|
def derive_arm_rotation(arm, target_dir=(0.12, 0.0, -1.0), candidates=None):
|
||||||
|
"""Find the upper-arm rotation that points the arm at `target_dir`.
|
||||||
|
|
||||||
|
The 0.2.0 value (0.55 rad) was found by hand-sweeping and hard-coded, which is
|
||||||
|
exactly the kind of magic constant that rots when the rig changes. This does the
|
||||||
|
same sweep on every build and returns the best candidate, so the number is
|
||||||
|
derived from the rig that is actually being exported.
|
||||||
|
"""
|
||||||
|
from mathutils import Euler, Vector
|
||||||
|
|
||||||
|
candidates = candidates or [0.35 + 0.05 * i for i in range(11)]
|
||||||
|
target = Vector(target_dir).normalized()
|
||||||
|
bpy.context.view_layer.objects.active = arm
|
||||||
|
bpy.ops.object.mode_set(mode="POSE")
|
||||||
|
upper = arm.pose.bones["upperarm01.L"]
|
||||||
|
upper.rotation_mode = "XYZ"
|
||||||
|
best, best_dot = 0.55, -2.0
|
||||||
|
for z in candidates:
|
||||||
|
upper.rotation_euler = Euler((0.0, 0.0, -z))
|
||||||
|
bpy.context.view_layer.update()
|
||||||
|
direction = (upper.matrix.to_3x3() @ Vector((0.0, 1.0, 0.0))).normalized()
|
||||||
|
dot = direction.dot(target)
|
||||||
|
if dot > best_dot:
|
||||||
|
best, best_dot = z, dot
|
||||||
|
upper.rotation_euler = Euler((0.0, 0.0, 0.0))
|
||||||
|
bpy.ops.object.mode_set(mode="OBJECT")
|
||||||
|
log(f"arm rotation derived: {best:.2f} rad (direction dot {best_dot:.3f})")
|
||||||
|
return best
|
||||||
|
PARTS: list[dict] = []
|
||||||
|
|
||||||
# The .blend stores the raw A-pose bind: `mpfb_character_export.py --pose idle`
|
# The .blend stores the raw A-pose bind: `mpfb_character_export.py --pose idle`
|
||||||
# bakes the arms down only in the exported FBX, not in the file. A clip that
|
# bakes the arms down only in the exported FBX, not in the file. A clip that
|
||||||
# animates only swing therefore leaves the arms out in an A — which is exactly how
|
# animates only swing therefore leaves the arms out in an A — which is exactly how
|
||||||
@@ -154,6 +199,27 @@ def apply_base_pose(arm):
|
|||||||
log("base pose applied to rest: arms down before any clip is authored")
|
log("base pose applied to rest: arms down before any clip is authored")
|
||||||
|
|
||||||
|
|
||||||
|
BASE = {}
|
||||||
|
|
||||||
|
|
||||||
|
def fill_base(arm):
|
||||||
|
"""Populate the standing base: derived arm angle plus the finger curl."""
|
||||||
|
arm_z = derive_arm_rotation(arm)
|
||||||
|
BASE.update({
|
||||||
|
"upperarm01.L": (0.0, 0.0, -arm_z),
|
||||||
|
"upperarm01.R": (0.0, 0.0, arm_z),
|
||||||
|
"lowerarm01.L": (0.0, 0.0, -0.12),
|
||||||
|
"lowerarm01.R": (0.0, 0.0, 0.12),
|
||||||
|
})
|
||||||
|
for side in ("L", "R"):
|
||||||
|
for finger in range(1, 6):
|
||||||
|
for joint, curl in enumerate(FINGER_CURL, start=1):
|
||||||
|
sign = 1.0 if side == "L" else -1.0
|
||||||
|
BASE[f"finger{finger}-{joint}.{side}"] = (sign * curl, 0.0, 0.0)
|
||||||
|
log(f"standing base: {len(BASE)} bones (arm {arm_z:.2f} rad, "
|
||||||
|
f"finger curl {FINGER_CURL})")
|
||||||
|
|
||||||
|
|
||||||
def key_euler(pb, frame, x=0.0, y=0.0, z=0.0):
|
def key_euler(pb, frame, x=0.0, y=0.0, z=0.0):
|
||||||
"""Key a pose-bone rotation, offset by the standing base.
|
"""Key a pose-bone rotation, offset by the standing base.
|
||||||
|
|
||||||
@@ -186,6 +252,15 @@ def clip_idle(arm, frames):
|
|||||||
key_euler(bones["upperarm01.L"], frame, x=0.020 * breathe)
|
key_euler(bones["upperarm01.L"], frame, x=0.020 * breathe)
|
||||||
key_euler(bones["upperarm01.R"], frame, x=-0.020 * breathe)
|
key_euler(bones["upperarm01.R"], frame, x=-0.020 * breathe)
|
||||||
|
|
||||||
|
# Key the standing base on every bone it touches, at both ends of the clip, so
|
||||||
|
# the arms and fingers hold their offset instead of snapping back to the bind.
|
||||||
|
for name in BASE:
|
||||||
|
bone = bones.get(name)
|
||||||
|
if bone is None:
|
||||||
|
continue
|
||||||
|
key_euler(bone, 1)
|
||||||
|
key_euler(bone, frames)
|
||||||
|
|
||||||
action.use_fake_user = True
|
action.use_fake_user = True
|
||||||
log(f"Idle: {frames} frames, spine/neck/head/arms, feet planted")
|
log(f"Idle: {frames} frames, spine/neck/head/arms, feet planted")
|
||||||
return action
|
return action
|
||||||
@@ -221,6 +296,13 @@ def clip_walk(arm, frames):
|
|||||||
key_euler(bones["spine04"], frame, z=0.08 * swing)
|
key_euler(bones["spine04"], frame, z=0.08 * swing)
|
||||||
key_euler(bones["neck01"], frame, z=-0.04 * swing)
|
key_euler(bones["neck01"], frame, z=-0.04 * swing)
|
||||||
|
|
||||||
|
for name in BASE:
|
||||||
|
bone = bones.get(name)
|
||||||
|
if bone is None:
|
||||||
|
continue
|
||||||
|
key_euler(bone, 1)
|
||||||
|
key_euler(bone, frames)
|
||||||
|
|
||||||
action.use_fake_user = True
|
action.use_fake_user = True
|
||||||
log(f"Walk: {frames} frames, stride {HIP:.2f} rad hip / {KNEE:.2f} knee / {ARM:.2f} arm")
|
log(f"Walk: {frames} frames, stride {HIP:.2f} rad hip / {KNEE:.2f} knee / {ARM:.2f} arm")
|
||||||
return action
|
return action
|
||||||
@@ -243,6 +325,7 @@ def main(argv=None) -> int:
|
|||||||
|
|
||||||
bpy.context.scene.render.fps = FPS
|
bpy.context.scene.render.fps = FPS
|
||||||
clear_animation(arm)
|
clear_animation(arm)
|
||||||
|
fill_base(arm)
|
||||||
idle = clip_idle(arm, CLIPS["Idle"])
|
idle = clip_idle(arm, CLIPS["Idle"])
|
||||||
walk = clip_walk(arm, CLIPS["Walk"])
|
walk = clip_walk(arm, CLIPS["Walk"])
|
||||||
|
|
||||||
|
|||||||
@@ -288,7 +288,6 @@ try:
|
|||||||
# the colonnade's underside.
|
# the colonnade's underside.
|
||||||
# Level horizon for the same reason: a block elevation is read by its
|
# Level horizon for the same reason: a block elevation is read by its
|
||||||
# verticals, and a pitched camera makes them lean.
|
# verticals, and a pitched camera makes them lean.
|
||||||
("demo-third-person-walk", unreal.Vector(-12940, -980, 560), unreal.Vector(-13336, -980, 500), 55.0),
|
|
||||||
("demo-spawn-view", unreal.Vector(-13336, -3100, 620), unreal.Vector(-13336, 1300, 620), 48.0),
|
("demo-spawn-view", unreal.Vector(-13336, -3100, 620), unreal.Vector(-13336, 1300, 620), 48.0),
|
||||||
# Street level, from the north sidewalk: the old camera sat at Y -400,
|
# Street level, from the north sidewalk: the old camera sat at Y -400,
|
||||||
# inside the facade body (which spans Y -1457..-200), so it looked at
|
# inside the facade body (which spans Y -1457..-200), so it looked at
|
||||||
@@ -335,7 +334,7 @@ try:
|
|||||||
# No follow shots in the current list: the stride capture was retired
|
# No follow shots in the current list: the stride capture was retired
|
||||||
# because the walk clip does not visibly advance in game (see TODO.md).
|
# because the walk clip does not visibly advance in game (see TODO.md).
|
||||||
# The follow flag stays wired for when it does.
|
# The follow flag stays wired for when it does.
|
||||||
seq.set_editor_property("shot_follow", [True] + [False] * (len(demo_shots) - 1))
|
seq.set_editor_property("shot_follow", [False] * len(demo_shots))
|
||||||
seq.set_editor_property(
|
seq.set_editor_property(
|
||||||
"shot_field_of_view",
|
"shot_field_of_view",
|
||||||
[float(c[3]) if len(c) > 3 else 0.0 for c in demo_shots])
|
[float(c[3]) if len(c) > 3 else 0.0 for c in demo_shots])
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import unreal
|
|||||||
|
|
||||||
SRC = "/tmp/gigline/character-anim.fbx"
|
SRC = "/tmp/gigline/character-anim.fbx"
|
||||||
DEST = "/Game/Test/Character"
|
DEST = "/Game/Test/Character"
|
||||||
PREFIX = "CharacterV2"
|
PREFIX = "CharacterV3"
|
||||||
RESULT = "/tmp/gigline/character-anim-import.txt"
|
RESULT = "/tmp/gigline/character-anim-import.txt"
|
||||||
lines = []
|
lines = []
|
||||||
|
|
||||||
|
|||||||
@@ -127,6 +127,10 @@ def build():
|
|||||||
ia_reset.set_editor_property("value_type", unreal.InputActionValueType.BOOLEAN)
|
ia_reset.set_editor_property("value_type", unreal.InputActionValueType.BOOLEAN)
|
||||||
save(ia_reset)
|
save(ia_reset)
|
||||||
|
|
||||||
|
ia_debug = fresh("IA_ToggleDebug", unreal.InputAction, unreal.InputAction_Factory)
|
||||||
|
ia_debug.set_editor_property("value_type", unreal.InputActionValueType.BOOLEAN)
|
||||||
|
save(ia_debug)
|
||||||
|
|
||||||
ia_cam = fresh("IA_ToggleCamera", unreal.InputAction, unreal.InputAction_Factory)
|
ia_cam = fresh("IA_ToggleCamera", unreal.InputAction, unreal.InputAction_Factory)
|
||||||
ia_cam.set_editor_property("value_type", unreal.InputActionValueType.BOOLEAN)
|
ia_cam.set_editor_property("value_type", unreal.InputActionValueType.BOOLEAN)
|
||||||
save(ia_cam)
|
save(ia_cam)
|
||||||
@@ -140,7 +144,7 @@ def build():
|
|||||||
(ia_move, "Gamepad_LeftY"), (ia_strafe, "Gamepad_LeftX"),
|
(ia_move, "Gamepad_LeftY"), (ia_strafe, "Gamepad_LeftX"),
|
||||||
(ia_look, "MouseX"), (ia_look, "MouseY"), (ia_look, "Gamepad_Right2D"),
|
(ia_look, "MouseX"), (ia_look, "MouseY"), (ia_look, "Gamepad_Right2D"),
|
||||||
(ia_jump, "SpaceBar"), (ia_jump, "Gamepad_FaceButton_Bottom"),
|
(ia_jump, "SpaceBar"), (ia_jump, "Gamepad_FaceButton_Bottom"),
|
||||||
(ia_reset, "R"), (ia_pause, "Escape"), (ia_cam, "V"),
|
(ia_reset, "R"), (ia_pause, "Escape"), (ia_cam, "V"), (ia_debug, "F3"),
|
||||||
]
|
]
|
||||||
|
|
||||||
mappings = []
|
mappings = []
|
||||||
|
|||||||
@@ -84,18 +84,6 @@
|
|||||||
"Art/reference/hollywood/el-capitan-facade-day-wikimedia-2009-10-27.jpg"
|
"Art/reference/hollywood/el-capitan-facade-day-wikimedia-2009-10-27.jpg"
|
||||||
],
|
],
|
||||||
"expect": "Front view of the player body from the road: both arms hanging at the sides, hands down by the hips, face and chest visible, hero facade behind the camera"
|
"expect": "Front view of the player body from the road: both arms hanging at the sides, hands down by the hips, face and chest visible, hero facade behind the camera"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "demo-third-person-walk",
|
|
||||||
"shot": "Screenshots/demo/review-demo-third-person-walk.png",
|
|
||||||
"size": [
|
|
||||||
1920,
|
|
||||||
1080
|
|
||||||
],
|
|
||||||
"references": [
|
|
||||||
"Art/reference/hollywood/el-capitan-facade-day-wikimedia-2009-10-27.jpg"
|
|
||||||
],
|
|
||||||
"expect": "The player body mid-stride in profile: legs apart, arms counter-swinging, walking along the sidewalk"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user