Recapture the gear portrait and gallery shots

Fix the portrait staging: face the rig toward the camera (the old yaw was 180
degrees out) and hide the focus disc, which was covering the face in close-ups.
Add the before/after Influencer portrait, fit measurements and judge scores in
docs/screens/realism/2026-11-01-gear. Re-run check_screenshots (11 good/0 bad);
headless 229/229.
This commit is contained in:
zwitschi committed 2026-11-01 18:09:50 +01:00
1 parent 1b319c48b7
commit 151630e957
11 files changed
+204 -4

No files matched your search

+5 -2
View File
@@ -38,8 +38,11 @@ live in `tools/blender_assets.py` (`_build_gear()`), the contract in `docs/blend
width and requires positive bag clearance on both coat and dress;
`test_npc_character.test_head_and_back_gear_clear_the_body_silhouette` loads the gear on
six roles and checks head-parent/width/brow bounds plus back-parent/0.26 m outer radius.
- [ ] Re-capture the portrait (`--stages=day,portrait`) and the gallery shots; record the
before/after in `docs/screens/realism/<date>-gear/`.
- [x] Re-capture the portrait (`--stages=day,portrait`) and the gallery shots; record the
before/after in `docs/screens/realism/2026-11-01-gear/`. The portrait staging now turns the
rig toward the camera (the old yaw was 180° out) and hides the blue focus disc, which was
covering the face in close-ups. `check_screenshots.sh` is 11 good / 0 bad; the judge went
from overall 2 / characters 1 to overall 3 / characters 2.
- [ ] Consider a second character close-up for a hoodie/winter NPC so headgear is covered too
(`--portrait-type=5` already forces a hooded role for comparison).
@@ -0,0 +1,134 @@
{
"run": "docs/screens/realism/2026-11-01-gear-judge",
"judge_model": "google/gemini-2.5-flash-lite",
"sets": {
"baseline": {
"npc_portrait": {
"target": "docs/screens/concepts/npc_portrait_day.png",
"metrics": {
"edge_density": 24.42,
"fine_detail": 9.88,
"contrast": 43.77,
"saturation_mean": 90.21,
"colour_spread": 50.11
},
"target_metrics": {
"edge_density": 7.47,
"fine_detail": 3.47,
"contrast": 52.66,
"saturation_mean": 93.44,
"colour_spread": 54.88
},
"metric_gap": 1.093,
"judge": {
"scores": {
"backdrop": 4.0,
"lighting": 3.0,
"overall": 2.0,
"materials": 2.0,
"texture_detail": 1.0,
"characters": 1.0
},
"score_range": {
"backdrop": [
4.0,
4.0
],
"lighting": [
3.0,
3.0
],
"overall": [
2.0,
2.0
],
"materials": [
2.0,
2.0
],
"texture_detail": [
1.0,
1.0
],
"characters": [
1.0,
1.0
]
},
"runs": 1,
"fixes": [
"Improve character model realism with more detailed facial features, realistic skin shaders, and better clothing textures.",
"Enhance material properties for all objects, especially the brick building and pavement, to better simulate real-world reflectivity, roughness, and subsurface scattering.",
"Increase texture resolution and detail for all assets, particularly for the brickwork, pavement, and character clothing, to reduce the appearance of tiling and blurriness.",
"Refine lighting to match the warm, directional sunlight and soft shadows of the target image, paying attention to ambient occlusion and global illumination.",
"Add atmospheric perspective and volumetric fog to the backdrop to create a sense of depth and distance, mimicking the haze seen in the target image."
]
}
}
},
"candidate": {
"npc_portrait": {
"target": "docs/screens/concepts/npc_portrait_day.png",
"metrics": {
"edge_density": 24.43,
"fine_detail": 9.89,
"contrast": 43.74,
"saturation_mean": 90.17,
"colour_spread": 50.08
},
"target_metrics": {
"edge_density": 7.47,
"fine_detail": 3.47,
"contrast": 52.66,
"saturation_mean": 93.44,
"colour_spread": 54.88
},
"metric_gap": 1.094,
"judge": {
"scores": {
"backdrop": 5.0,
"lighting": 4.0,
"overall": 3.0,
"materials": 3.0,
"texture_detail": 2.0,
"characters": 2.0
},
"score_range": {
"backdrop": [
5.0,
5.0
],
"lighting": [
4.0,
4.0
],
"overall": [
3.0,
3.0
],
"materials": [
3.0,
3.0
],
"texture_detail": [
2.0,
2.0
],
"characters": [
2.0,
2.0
]
},
"runs": 1,
"fixes": [
"Improve character model realism with more detailed facial features, realistic skin shaders, and better hair simulation.",
"Enhance material properties for clothing, pavement, and buildings to include subsurface scattering, anisotropic reflections, and more varied roughness maps.",
"Increase texture resolution and add micro-detail (e.g., pores, fabric weave, concrete imperfections) to all surfaces.",
"Implement more sophisticated global illumination and atmospheric scattering for a softer, more realistic lighting and haze effect.",
"Refine the backdrop by adding more complex building geometry, varied foliage, and realistic distant city details with appropriate atmospheric perspective."
]
}
}
}
}
}
@@ -0,0 +1,55 @@
# Gear fit report: `docs/screens/realism/2026-11-01-gear`
Influencer (`npc_coat`) portrait, forced with `--portrait-type=2`, before the gear-fit
changes (`da876e3`, with the capture yaw/focus fixes backported) and after them (`a478bfb`).
Both frames use the same camera, sun and portrait staging. The focus disc is hidden because
it is a gameplay overlay, not part of the character still.
| measurement | before | after |
| --- | --- | --- |
| sunglasses width | 0.282 m (0.90× head) | **0.202 m** (0.64× head) |
| bag body inner face | 0.168 m (coat skirt 0.225, dress 0.260) | **0.262 m** (clears both) |
| firefighter helmet brim | sat on the brow ridge | **raised 2 cm** |
Capture commands:
```
xvfb-run -a godot --path . --script res://src/test/capture_realism.gd -- \
--stages=portrait --portrait-type=2 \
--out=res://docs/screens/realism/2026-11-01-gear/candidate-v2
tools/check_screenshots.sh # 11 good / 0 bad
python3 tools/scene_concepts.py realism \
--run docs/screens/realism/2026-11-01-gear --judge
```
The judge improved the portrait from **overall 2 / characters 1** (baseline) to
**overall 3 / characters 2** (candidate); the remaining fixes are the broader realism
targets (skin/cloth shaders, GI, backdrop haze), not gear fit.
Vision judge: `google/gemini-2.5-flash-lite` (scores 0-10, higher is more realistic compared with the concept target).
| set | shot | target | gap ↓ | edges | detail | contrast | overall | lighting | materials | texture | backdrop |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| baseline | npc_portrait | npc_portrait_day | 1.093 | 24.42 | 9.88 | 43.77 | 2.0 | 3.0 | 2.0 | 1.0 | 4.0 |
| candidate | npc_portrait | npc_portrait_day | 1.094 | 24.43 | 9.89 | 43.74 | 3.0 | 4.0 | 3.0 | 2.0 | 5.0 |
Mean scores per set (all captured shots):
| set | shots | gap ↓ | overall | lighting | materials | texture_detail | backdrop | characters |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| baseline | 1 | 1.093 | 2.0 | 3.0 | 2.0 | 1.0 | 4.0 | 1.0 |
| candidate | 1 | 1.094 | 3.0 | 4.0 | 3.0 | 2.0 | 5.0 | 2.0 |
**baseline / npc_portrait** fixes:
- Improve character model realism with more detailed facial features, realistic skin shaders, and better clothing textures.
- Enhance material properties for all objects, especially the brick building and pavement, to better simulate real-world reflectivity, roughness, and subsurface scattering.
- Increase texture resolution and detail for all assets, particularly for the brickwork, pavement, and character clothing, to reduce the appearance of tiling and blurriness.
- Refine lighting to match the warm, directional sunlight and soft shadows of the target image, paying attention to ambient occlusion and global illumination.
- Add atmospheric perspective and volumetric fog to the backdrop to create a sense of depth and distance, mimicking the haze seen in the target image.
**candidate / npc_portrait** fixes:
- Improve character model realism with more detailed facial features, realistic skin shaders, and better hair simulation.
- Enhance material properties for clothing, pavement, and buildings to include subsurface scattering, anisotropic reflections, and more varied roughness maps.
- Increase texture resolution and add micro-detail (e.g., pores, fabric weave, concrete imperfections) to all surfaces.
- Implement more sophisticated global illumination and atmospheric scattering for a softer, more realistic lighting and haze effect.
- Refine the backdrop by adding more complex building geometry, varied foliage, and realistic distant city details with appropriate atmospheric perspective.
Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 856 KiB

After

Width:  |  Height:  |  Size: 856 KiB

+10 -2
View File
@@ -266,8 +266,16 @@ func _stage_portrait(delta: float, angle_deg: float = 0.0) -> bool:
look.y = 0.0
gm.guard.rotation.y = atan2(-look.x, -look.z)
gm.guard.head.rotation.x = deg_to_rad(1.0)
# Turn the drawn rig (not the root) so the subject looks at the camera.
best.rotation.y = atan2(look.x, look.z)
# The focus disc is a gameplay overlay, not part of the character still.
for focus in best.find_children("FocusCircle", "MeshInstance3D", true, false):
(focus as MeshInstance3D).visible = false
# Face the camera: from the subject, the guard lies in the -look direction.
# Use the drawn rig so an FSM yaw on the root cannot fight the pose.
var rig := best.find_child("Rig", true, false) as Node3D
if rig != null:
rig.rotation.y = atan2(-look.x, -look.z)
else:
best.rotation.y = atan2(-look.x, -look.z)
return true