test(vehicle): a review shot, and the judge that proves the car is missing
Adds demo-vehicle to the camera list and the visual targets, plus shot 9 in Screenshots/README.md - marked FAIL, because that is what it shows. The vehicle is staged and runs: spawned at (-12950,-900,120), 9 visual panels attached, panel 0 visible with a 238 cm extent, settled at Z 119 cm. The capture shows an empty road with a soft shadow. Two checks disagree in a useful way: visual_loop --verify PASSES the frame (it only tests size, blankness and tonal range, so a well-exposed empty road passes), while judge_screenshot returns verdict=no confidence=1.0. Strongest clue, recorded in TODO.md: a downward trace from the vehicle finds no ground at all (ground at Z -9999), so the car sits over a surface without collision or inside geometry - the shadow and the panels are not in the same place. Diagnostics added along the way: mesh/visibility/bounds at BeginPlay, per-panel world positions and extents, and the ground trace. The visual panels were also unhidden from the physics mesh: SetVisibility(false, ...) hid them whether or not propagation was requested.
This commit is contained in:
1 parent
5dd53ac30b
commit
627737062b
42 files changed
+172
-44
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.
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.
@@ -36,6 +36,68 @@ AGigLineVehicle::AGigLineVehicle()
|
||||
}
|
||||
}
|
||||
|
||||
void AGigLineVehicle::BuildVisuals()
|
||||
{
|
||||
// One component per authored system: body, glass, front and rear lights, mirrors and
|
||||
// the four wheels. Each points at the static asset imported from the same Blender
|
||||
// build, so the render matches what the model tool produced.
|
||||
struct FPanelSpec
|
||||
{
|
||||
const TCHAR* Path;
|
||||
FVector Offset;
|
||||
FRotator Rotation;
|
||||
};
|
||||
const float HalfBase = 139.0f; // wheelbase 278 cm / 2
|
||||
const float HalfTrack = 81.0f; // track 162 cm / 2
|
||||
const FPanelSpec Specs[] = {
|
||||
{TEXT("/Game/Hollywood/Vehicle/SM_Vehicle_Body.SM_Vehicle_Body"), FVector::ZeroVector, FRotator::ZeroRotator},
|
||||
{TEXT("/Game/Hollywood/Vehicle/SM_Vehicle_Glass.SM_Vehicle_Glass"), FVector::ZeroVector, FRotator::ZeroRotator},
|
||||
{TEXT("/Game/Hollywood/Vehicle/SM_Vehicle_Light_Front.SM_Vehicle_Light_Front"), FVector::ZeroVector, FRotator::ZeroRotator},
|
||||
{TEXT("/Game/Hollywood/Vehicle/SM_Vehicle_Light_Rear.SM_Vehicle_Light_Rear"), FVector::ZeroVector, FRotator::ZeroRotator},
|
||||
{TEXT("/Game/Hollywood/Vehicle/SM_Vehicle_Mirrors.SM_Vehicle_Mirrors"), FVector::ZeroVector, FRotator::ZeroRotator},
|
||||
{TEXT("/Game/Hollywood/Vehicle/SM_Vehicle_Wheel.SM_Vehicle_Wheel"), FVector(HalfBase, HalfTrack, -16.f), FRotator::ZeroRotator},
|
||||
{TEXT("/Game/Hollywood/Vehicle/SM_Vehicle_Wheel.SM_Vehicle_Wheel"), FVector(HalfBase, -HalfTrack, -16.f), FRotator::ZeroRotator},
|
||||
{TEXT("/Game/Hollywood/Vehicle/SM_Vehicle_Wheel.SM_Vehicle_Wheel"), FVector(-HalfBase, HalfTrack, -16.f), FRotator::ZeroRotator},
|
||||
{TEXT("/Game/Hollywood/Vehicle/SM_Vehicle_Wheel.SM_Vehicle_Wheel"), FVector(-HalfBase, -HalfTrack, -16.f), FRotator::ZeroRotator},
|
||||
};
|
||||
|
||||
int32 Index = 0;
|
||||
for (const FPanelSpec& Spec : Specs)
|
||||
{
|
||||
if (UStaticMesh* Mesh = LoadObject<UStaticMesh>(nullptr, Spec.Path))
|
||||
{
|
||||
UStaticMeshComponent* Component = NewObject<UStaticMeshComponent>(this,
|
||||
*FString::Printf(TEXT("Panel_%d"), Index));
|
||||
// Attach to the actor root rather than to the physics mesh, so the visuals are
|
||||
// independent of the simulated component's own state.
|
||||
Component->SetupAttachment(GetRootComponent());
|
||||
Component->SetStaticMesh(Mesh);
|
||||
Component->SetRelativeLocation(Spec.Offset);
|
||||
Component->SetRelativeRotation(Spec.Rotation);
|
||||
Component->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
Component->SetMobility(EComponentMobility::Movable);
|
||||
Component->RegisterComponent();
|
||||
Panels.Add(Component);
|
||||
++Index;
|
||||
}
|
||||
}
|
||||
UE_LOG(LogTemp, Warning, TEXT("GigLine vehicle: %d visual panels attached"), Panels.Num());
|
||||
for (int32 PanelIndex = 0; PanelIndex < Panels.Num(); ++PanelIndex)
|
||||
{
|
||||
const UStaticMeshComponent* Panel = Panels[PanelIndex];
|
||||
if (!Panel)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const FVector Where = Panel->GetComponentLocation();
|
||||
const FBoxSphereBounds B = Panel->Bounds;
|
||||
UE_LOG(LogTemp, Warning,
|
||||
TEXT("GigLine vehicle: panel %d at (%.0f,%.0f,%.0f) visible=%d extent=%.0f"),
|
||||
PanelIndex, Where.X, Where.Y, Where.Z,
|
||||
Panel->IsVisible() ? 1 : 0, B.BoxExtent.GetMax());
|
||||
}
|
||||
}
|
||||
|
||||
void AGigLineVehicle::ConfigureWheels()
|
||||
{
|
||||
UChaosWheeledVehicleMovementComponent* Movement =
|
||||
@@ -92,6 +154,17 @@ void AGigLineVehicle::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
// The skeletal mesh is the physics driver only: its imported geometry is unusable
|
||||
// (1 cm bounds), so it is hidden and the visible car comes from the static panels.
|
||||
if (USkeletalMeshComponent* PhysicsMesh = GetMesh())
|
||||
{
|
||||
// Do not hide the physics mesh at all. It has no usable geometry (1 cm bounds), so
|
||||
// it renders nothing either way, and every attempt to hide it also hid the visual
|
||||
// panels - with and without propagation. Leaving it visible avoids the fight.
|
||||
PhysicsMesh->SetCastShadow(false);
|
||||
}
|
||||
BuildVisuals();
|
||||
|
||||
// Wheel objects do not exist until the component is registered, so the per-wheel
|
||||
// flags set in the constructor went nowhere - which is why the drive test measured
|
||||
// zero speed with throttle held. Apply them again now that they exist, and give the
|
||||
@@ -106,6 +179,16 @@ void AGigLineVehicle::BeginPlay()
|
||||
Movement->TransmissionSetup.bUseAutomaticGears = true;
|
||||
Movement->TransmissionSetup.FinalRatio = 3.5f;
|
||||
Movement->SetThrottleInput(0.0f);
|
||||
if (const USkeletalMeshComponent* BodyComp = GetMesh())
|
||||
{
|
||||
const USkeletalMesh* Asset = BodyComp->GetSkeletalMeshAsset();
|
||||
UE_LOG(LogTemp, Warning,
|
||||
TEXT("GigLine vehicle: mesh=%s visible=%d hidden=%d bounds=%s"),
|
||||
Asset ? *Asset->GetName() : TEXT("NONE"),
|
||||
BodyComp->IsVisible() ? 1 : 0,
|
||||
BodyComp->bHiddenInGame ? 1 : 0,
|
||||
*BodyComp->Bounds.BoxExtent.ToString());
|
||||
}
|
||||
UE_LOG(LogTemp, Warning,
|
||||
TEXT("GigLine vehicle: %d wheel objects after register, torque %.0f"),
|
||||
Movement->Wheels.Num(), Movement->EngineSetup.MaxTorque);
|
||||
@@ -158,6 +241,17 @@ void AGigLineVehicle::Tick(float DeltaSeconds)
|
||||
if (!bSettleReported && SettleElapsed > 3.0f)
|
||||
{
|
||||
bSettleReported = true;
|
||||
if (UWorld* World = GetWorld())
|
||||
{
|
||||
FHitResult Hit;
|
||||
FCollisionQueryParams Q(TEXT("GigLineVehicleGround"), false, this);
|
||||
const bool bGround = World->LineTraceSingleByChannel(Hit, GetActorLocation(),
|
||||
GetActorLocation() - FVector(0.f, 0.f, 2000.f), ECC_Visibility, Q);
|
||||
UE_LOG(LogTemp, Warning,
|
||||
TEXT("GigLine vehicle: ground at Z %.0f cm, actor %.0f cm, height above ground %.0f cm"),
|
||||
bGround ? Hit.ImpactPoint.Z : -9999.f, GetActorLocation().Z,
|
||||
bGround ? GetActorLocation().Z - Hit.ImpactPoint.Z : -9999.f);
|
||||
}
|
||||
const USkeletalMeshComponent* Body = GetMesh();
|
||||
UE_LOG(LogTemp, Warning,
|
||||
TEXT("GigLine vehicle: settled at Z %.0f cm, simulating=%d, speed=%.0f cm/s"),
|
||||
|
||||
@@ -29,6 +29,18 @@ public:
|
||||
virtual void BeginPlay() override;
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
|
||||
/**
|
||||
* Visual panels, as static mesh components.
|
||||
*
|
||||
* The skeletal vehicle asset imported with no usable geometry (runtime bounds of
|
||||
* 1 cm), so the car was invisible in the scene while its physics body still cast a
|
||||
* shadow - the "no vehicle in scene" report. The static assets are correct (body
|
||||
* 476 x 176 x 128 cm), so the visible car is assembled from them and the skeletal
|
||||
* mesh stays as the physics/animation driver only.
|
||||
*/
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Visual")
|
||||
TArray<TObjectPtr<UStaticMeshComponent>> Panels;
|
||||
|
||||
/** True once the vehicle reports a forward speed above a walking pace. */
|
||||
bool IsMoving() const;
|
||||
|
||||
@@ -36,6 +48,9 @@ private:
|
||||
/** Configure the Chaos wheels from the modelled dimensions. */
|
||||
void ConfigureWheels();
|
||||
|
||||
/** Attach the visible panels from the imported static systems. */
|
||||
void BuildVisuals();
|
||||
|
||||
float DriveElapsed = 0.f;
|
||||
bool bDriveReported = false;
|
||||
FVector DriveStart = FVector::ZeroVector;
|
||||
|
||||
@@ -26,6 +26,7 @@ Every shot is embedded below, in order, so the whole review happens in this file
|
||||
| 6 | [Third-person body](#6-third-person-body) | ☑ 2026-11-09 | ☑ 2026-11-09 |
|
||||
| 7 | [Third-person front](#7-third-person-front) | ☑ 2026-11-09 | ☑ 2026-11-09 |
|
||||
| 8 | [Third-person walk](#8-third-person-walk) | ☑ 2026-11-09 | ☑ 2026-11-09 |
|
||||
| 9 | [Vehicle](#9-vehicle) | ☐ FAIL 2026-11-09 | ☐ pending |
|
||||
|
||||
**Verified** is what `--verify` reports: the frame is not blank, is the right size, and has tonal range. **Approved** is the owner's verdict, recorded here. Each shot also has an **expectation** in [`Tools/visual_targets.json`](../Tools/visual_targets.json) describing the content it must show.
|
||||
|
||||
|
||||
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.
@@ -21,6 +21,7 @@ Actionable task list for this project. This file is the single, central place fo
|
||||
- **Drive test fails, with a specific cause:** `-drivetest` holds full throttle for 3 s and reports speed and distance. Result: `speed=0 cm/s, travelled 2.2 m -> FAIL`, and BeginPlay logs **`0 wheel objects after register`** while the component reports 4 wheel setups. The setups exist but no wheels are created from them, so there is nothing to apply torque to.
|
||||
- **Next:** confirm the skeleton's bone names match the setups (`Wheel_FL`, `Wheel_FR`, `Wheel_RL`, `Wheel_RR`) - a name mismatch silently produces zero wheels - and give the front and rear pairs their own `UChaosVehicleWheel` subclasses rather than the base class, which is what the setups point at today.
|
||||
- **Also open:** LOD group wiring, enter/exit, driving route, handling.
|
||||
- [A] Fix the vehicle not rendering in the scene. **Chased to a strong clue, not yet solved.** The vehicle is staged and runs (`spawned at (-12950,-900,120)`, `9 visual panels attached`, `panel 0 at (-12950,-900,120) visible=1 extent=238`, `settled at Z 119`), and the review capture shows an empty road with only a soft shadow. `Tools/visual_loop.py --verify` passes the frame; `Tools/judge_screenshot.py` returns `verdict=no confidence=1.0`. A downward trace from the vehicle finds **no ground at all** (`ground at Z -9999`), so the car is over a surface without collision or inside geometry - the shadow and the panels are not in the same place. Next: trace the road's collision under the spawn point, then move the staging to a spot with confirmed road collision.
|
||||
- [ ] Implement enter/exit interaction.
|
||||
- [ ] Build a closed driving route with boundaries.
|
||||
- [ ] Tune basic handling to a drivable state.
|
||||
|
||||
@@ -289,6 +289,10 @@ try:
|
||||
# Level horizon for the same reason: a block elevation is read by its
|
||||
# verticals, and a pitched camera makes them lean.
|
||||
("demo-third-person-walk", unreal.Vector(-12940, -980, 560), unreal.Vector(-13336, -980, 500), 55.0),
|
||||
# The sedan, staged on the carriageway at (-12950, -900). Three-quarter front
|
||||
# view from the road so both the body and the wheels are visible: a side-on
|
||||
# or rear view hides the wheel stances that the build is judged on.
|
||||
("demo-vehicle", unreal.Vector(-12250, -1600, 420), unreal.Vector(-12950, -900, 120), 50.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,
|
||||
# inside the facade body (which spans Y -1457..-200), so it looked at
|
||||
|
||||
@@ -96,6 +96,16 @@
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"name": "demo-vehicle",
|
||||
"shot": "Screenshots/demo/review-demo-vehicle.png",
|
||||
"size": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"references": [],
|
||||
"expect": "A red sedan parked on the road seen from the front three-quarter: body, cabin, four wheels visible, sitting on the surface rather than floating or sunk"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user