feat(hero): facade rework — inscription, medallions, motto band, banner lettering #39

Merged
zwitschi merged 93 commits from hero-facade-0.3.0 into main 2026-11-10 15:37:40 +01:00
40 changed files with 73 additions and 54 deletions
Showing only changes of commit c94ec7bbb9 - Show all commits

No files matched your search

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.
@@ -392,11 +392,22 @@ void AGigLineCharacter::LogFootProbes()
const FVector From = GetActorLocation() + FVector(0.f, 0.f, 3000.f);
const bool bTop = WorldTop->LineTraceSingleByChannel(Top, From,
From - FVector(0.f, 0.f, 6000.f), ECC_WorldStatic, QTop);
FString MeshName = TEXT("none");
if (bTop)
{
if (const UStaticMeshComponent* HitMesh = Cast<UStaticMeshComponent>(Top.GetComponent()))
{
if (const UStaticMesh* Asset = HitMesh->GetStaticMesh())
{
MeshName = Asset->GetName();
}
}
}
UE_LOG(LogTemp, Warning,
TEXT("GigLine top surface under player: hit=%d Z=%.0f actor=%s (actor Z %.0f)"),
TEXT("GigLine top surface under player: hit=%d Z=%.0f actor=%s mesh=%s (actor Z %.0f)"),
bTop ? 1 : 0, bTop ? Top.ImpactPoint.Z : -9999.f,
bTop && Top.GetActor() ? *Top.GetActor()->GetName() : TEXT("none"),
GetActorLocation().Z);
*MeshName, GetActorLocation().Z);
}
const FVector Feet = GetActorLocation() - FVector(0.f, 0.f, CapsuleHalf);
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.
+10 -2
View File
@@ -26,9 +26,17 @@ Actionable task list for this project. This file is the single, central place fo
- [x] Fix the character and car floating. **The measurement was taken at the wrong moment.** The foot probe ran in `BeginPlay`, while the pawn is still at its spawn height and falling, so every trace reported a surface far below it (`ground 366` against an actor at 561) and read as a float that was not there. The probe now runs **three seconds after spawn**, from the capsule's feet, on three channels, and names the actor it hits. Character: the player start at Z 600 left the soles 39 cm in the air (the capsule settles at 561 on this pavement); the start is now the measured 561. Car: the template's lowest geometry is exhaust, so grounding on the whole model put the tyres 4 cm above the origin - it is now grounded on its wheels, staged at Z 342 after the traced road height (366) disagreed with the visible road by ~25 cm.
- [x] Fix the vehicle's material colour. The template's `car paint` is a legacy mix-shader graph that the FBX exporter cannot map, so `SM_Vehicle_Body` imported holding `WorldGridMaterial` and rendered black while Blender showed red. Legacy graphs are now converted to Principled before export (saturated colour wins over the grey diffuse next to it), and the staged body panel is assigned `M_Vehicle_HatchPaint`. Judge: `verdict=yes confidence=0.9`.
- [x] Fix the missing vehicle glazing. The `windows` material was metallic 1.0 with roughness 0.0 - a black void that read as an empty cabin. Now tinted translucent (opacity 0.85, roughness 0.08); opacity 0.45 was tried first and made the glass invisible. The vision judge still returns `verdict=no` for the frame, disagreeing with what is visibly tinted glass; it is advisory, and the human verdict decides.
- [A] Fix the pavement: its collision sits above its visible surface. The judge now flags the character and car as floating in the spawn view, and its criterion is in the expectation ("a shadow more than a hand's width below an object means the object is floating"). Two readings are possible and both fit the pixels: the object really floats, or it stands on the raised pavement and the sun throws its shadow past the kerb onto the road. `Tools/shadow_gap.py` now does the measurement: object vs shadow in pixels, as a fraction of the object's height. It works on synthetic frames (tests pass) but returns `unknown` on the real spawn view, because the crop contains two surfaces - the pale wall behind and the dark road below - and a single global background cannot classify both. Next: per-region backgrounds, or crop tightly around the feet and their shadow only.
- [A] Put the player on the sidewalk, not the road. The judge now flags the character and car as floating in the spawn view, and its criterion is in the expectation ("a shadow more than a hand's width below an object means the object is floating"). Two readings are possible and both fit the pixels: the object really floats, or it stands on the raised pavement and the sun throws its shadow past the kerb onto the road. `Tools/shadow_gap.py` now does the measurement: object vs shadow in pixels, as a fraction of the object's height. It works on synthetic frames (tests pass) but returns `unknown` on the real spawn view, because the crop contains two surfaces - the pale wall behind and the dark road below - and a single global background cannot classify both. Next: per-region backgrounds, or crop tightly around the feet and their shadow only.
**The float is a pavement bug, proved by a null result.** Lowering the player start from 455 to 395 changed **nothing** in the ground-level feet shot: the capsule falls onto the collider and always rests at Z 456 with its feet at 369, while the rendered pavement is roughly a metre lower. So the sidewalk's **collision extends above its visible top** - the player stands on an invisible ledge. Spawn height, capsule offset and the shadow are all consequences of that, not causes.
**Root cause found: the player stands on the road.** Three spawn heights (455, 395, 469) produced **identical** captures, and the in-game probe names the surface every time:
```
GigLine top surface under player: hit Z=366 actor=StaticMeshActor_2 mesh=Road_Hollywood
```
The capsule lands on `Road_Hollywood` at Z 366, while the north sidewalk exists with collision and its top is at **Z 380** (`Demo_Sidewalk_North`, QueryAndPhysics). The character therefore stands ~14 cm **below** the sidewalk surface and reads as floating against the kerb - the shadow is thrown onto the road, which is genuinely lower.
Spawn height is irrelevant: the capsule falls through to the road regardless. The open question is the player start's **XY footprint**, not its Z - either it is not over the sidewalk mesh, or the sidewalk has a gap at that point.
**The measurement that says otherwise:** tracing down from 30 m above the player, the topmost surface is Z 366 and the capsule's feet sit at 369 - three centimetres, which is the capsule skin. If the character still looks like it floats, the gap is between the **rendered** pavement and its **collision** surface, not the spawn Z. That is the thing to measure next: the sidewalk mesh's rendered top versus the collider returned by the trace.