fix(camera): prove the boom shortens, and record how to repeat it
With the spring arm activated the collision now works: a 2 m wall spawned 4 m behind the
pawn shortens the boom from 340 cm to 288 cm - 12 cm clear of the wall, matching the probe
size. -cameratest logs it, writes a placement screenshot, and the measurement is recorded
as a release check for 0.2.3.
Two traps documented because each one made a working mechanism look broken:
- a spawned static-mesh actor has no collision unless it is created deferred and given
its mesh and collision before FinishSpawning (three runs reported blocks trace=0)
- TargetArmLength is not rewritten when the boom shortens, so reading the property
reports the requested length; the camera's distance from the head is the measurement
Writes the 0.2.3 changelog entry and prunes the section from TODO.md.
This commit is contained in:
1 parent
3e4dbd1014
commit
82cafc2f29
40 files changed
+95
-69
No files matched your search
@@ -8,6 +8,28 @@ Format: [Keep a Changelog](https://keepachangelog.com/) style, versions follow [
|
||||
|
||||
Nothing yet.
|
||||
|
||||
## [0.2.3] — 2026-11-09
|
||||
|
||||
Camera collision worked in the code and never in the game.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **The third-person boom never shortened.** The spring arm was created with `SetAutoActivate(false)` and `ToggleCamera()` activated only the camera. A deactivated spring arm does not tick, and its collision probe runs in that tick, so the boom could not shorten no matter what stood behind the pawn. Both `ToggleCamera` and `BeginPlay` now activate the arm with the rig.
|
||||
|
||||
### Added
|
||||
|
||||
- **`-cameratest`** — backs the pawn against a spawned 2 m wall, waits for the boom, and reports the shortening, whether the boom ends inside geometry, and a back-trace from camera to head. It writes `review-demo-camera-collision.png` so the placement can be checked by eye.
|
||||
|
||||
### Verified
|
||||
|
||||
- With a wall 4 m behind the pawn the boom shortens from 340 cm to **288 cm** — 12 cm clear of the wall, matching the probe size. Recorded as a release check.
|
||||
- 8 review shots verify; 95 tool tests pass.
|
||||
|
||||
### Notes for future work
|
||||
|
||||
- **A spawned static-mesh actor has no collision unless it is deferred.** Setting the mesh and collision profile after `SpawnActor` produced a wall that blocked nothing (`blocks trace=0`) on three consecutive attempts. `SpawnActorDeferred` → set mesh and collision → `FinishSpawning` builds the physics state correctly.
|
||||
- **`TargetArmLength` is not rewritten when the boom shortens.** The spring arm applies the shortened length to the camera, so the measurement must be the camera's distance from the head; reading the property reports the requested length and looks like a failure.
|
||||
|
||||
## [0.2.2] — 2026-11-09
|
||||
|
||||
The character becomes a character: clothed, haired, and measured against a generated blueprint instead of judged by eye.
|
||||
|
||||
@@ -42,6 +42,7 @@ Measured at 1440p on the development workstation: Bazzite, Ryzen 7 7700X, 64 GB
|
||||
| `0.1.0` | Placement vs references | PASS (with deliberate simplifications) | Section below, 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.2.3` | Third-person camera does not clip through geometry | PASS — with a 2 m wall spawned 4 m behind the pawn the boom shortens from 340 cm to **288 cm** (12 cm clear of the wall, matching the probe size). `-cameratest` logs it and captures the placement | `UnrealEditor-Cmd <uproject> /Game/Hollywood/DemoMap -game -thirdperson -cameratest`, `Saved/Logs/GigLine.log` | 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 |
|
||||
|
||||
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.
@@ -16,7 +16,7 @@
|
||||
#include "TimerManager.h"
|
||||
#include "Containers/Ticker.h"
|
||||
#include "Camera/PlayerCameraManager.h"
|
||||
#include "Engine/BlockingVolume.h"
|
||||
#include "Engine/StaticMeshActor.h"
|
||||
#include "UnrealClient.h"
|
||||
#include "HAL/IConsoleManager.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
@@ -385,16 +385,28 @@ void AGigLineCharacter::UpdateCameraCollisionTest(float DeltaSeconds)
|
||||
// A 6 m cube, 1.6 m behind the pawn: close enough that a 340 cm boom must hit
|
||||
// it, far enough that the capsule is clear of it.
|
||||
const FVector Behind = -GetActorForwardVector();
|
||||
const FVector Where = GetActorLocation() + Behind * 160.f - FVector(0.f, 0.f, 90.f);
|
||||
const FVector Where = GetActorLocation() + Behind * 400.f - FVector(0.f, 0.f, 90.f);
|
||||
FActorSpawnParameters Params;
|
||||
Params.ObjectFlags |= RF_Transient;
|
||||
// A blocking volume, not a static mesh actor: the mesh version spawned but did
|
||||
// not block a trace (verified: blocks trace=0), so the wall was never there.
|
||||
CameraTestWall = World->SpawnActor<ABlockingVolume>(
|
||||
ABlockingVolume::StaticClass(), Where, FRotator::ZeroRotator, Params);
|
||||
// Static mesh cube, 2 m thick, 4 m behind. The earlier failures had the pawn
|
||||
// INSIDE a 6 m cube centred 1.6 m back, so every trace started inside geometry
|
||||
// and reported no hit - the wall existed, the measurement was inside it.
|
||||
// Deferred spawn: the mesh and collision must be set BEFORE the actor is
|
||||
// registered, otherwise the physics state is built for an empty component and
|
||||
// the wall exists visually while blocking nothing (every earlier run reported
|
||||
// "blocks trace=0" for exactly that reason).
|
||||
CameraTestWall = World->SpawnActorDeferred<AStaticMeshActor>(
|
||||
AStaticMeshActor::StaticClass(), FTransform(Where), this, nullptr,
|
||||
ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
|
||||
if (CameraTestWall)
|
||||
{
|
||||
CameraTestWall->SetActorScale3D(FVector(6.f, 6.f, 6.f));
|
||||
UStaticMeshComponent* Comp = CameraTestWall->GetStaticMeshComponent();
|
||||
Comp->SetMobility(EComponentMobility::Movable);
|
||||
Comp->SetStaticMesh(LoadObject<UStaticMesh>(
|
||||
nullptr, TEXT("/Engine/BasicShapes/Cube.Cube")));
|
||||
Comp->SetCollisionProfileName(TEXT("BlockAll"));
|
||||
CameraTestWall->SetActorScale3D(FVector(6.f, 2.f, 6.f));
|
||||
CameraTestWall->FinishSpawning(FTransform(Where));
|
||||
}
|
||||
UE_LOG(LogTemp, Warning, TEXT("GigLine CAMTEST wall spawned behind pawn at (%.0f,%.0f,%.0f)"),
|
||||
Where.X, Where.Y, Where.Z);
|
||||
@@ -412,21 +424,23 @@ void AGigLineCharacter::UpdateCameraCollisionTest(float DeltaSeconds)
|
||||
const FVector Head = GetActorLocation() + FVector(0.f, 0.f, 60.f);
|
||||
const float Dist = FVector::Dist(Head, CameraLoc);
|
||||
|
||||
// Direct test of the mechanism: if a wall is right behind the pawn, the arm must
|
||||
// be shorter than its resting length. Nothing else can move it.
|
||||
const bool bShortened = (Rest - Arm) > 40.f;
|
||||
// The spring arm shortens internally and applies the result to the camera; it does
|
||||
// NOT rewrite TargetArmLength, so the arm length is always the requested one. The
|
||||
// measurement that matters is the camera's distance from the head.
|
||||
const bool bShortened = (Rest - Dist) > 40.f;
|
||||
// Prove the spawned wall has collision at all before blaming the arm.
|
||||
FHitResult WallHit;
|
||||
FCollisionQueryParams QW(TEXT("GigLineCameraWall"), false, this);
|
||||
const bool bWallBlocks = World->LineTraceSingleByChannel(
|
||||
WallHit, GetActorLocation(), GetActorLocation() - GetActorForwardVector() * 300.f,
|
||||
WallHit, GetActorLocation(), GetActorLocation() - GetActorForwardVector() * 600.f,
|
||||
ECC_Visibility, QW);
|
||||
UE_LOG(LogTemp, Warning, TEXT("GigLine CAMTEST spawned wall blocks trace=%d dist=%.0f"),
|
||||
bWallBlocks ? 1 : 0, bWallBlocks ? WallHit.Distance : -1.f);
|
||||
|
||||
UE_LOG(LogTemp, Warning,
|
||||
TEXT("GigLine CAMTEST wall behind pawn: arm %.0f of %.0f cm, cam %.0f cm from head -> %s"),
|
||||
Arm, Rest, Dist, bShortened ? TEXT("PASS (collision works)") : TEXT("FAIL (no shortening)"));
|
||||
TEXT("GigLine CAMTEST wall behind pawn: boom %.0f cm (requested %.0f, shortened %.0f) -> %s"),
|
||||
Dist, Rest, Rest - Dist,
|
||||
bShortened ? TEXT("PASS (boom shortened)") : TEXT("FAIL (no shortening)"));
|
||||
|
||||
FScreenshotRequest::RequestScreenshot(TEXT("review-demo-camera-collision"), true, false);
|
||||
if (CameraTestWall)
|
||||
|
||||
@@ -208,7 +208,7 @@ protected:
|
||||
void UpdateCameraCollisionTest(float DeltaSeconds);
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<class ABlockingVolume> CameraTestWall;
|
||||
TObjectPtr<class AStaticMeshActor> CameraTestWall;
|
||||
|
||||
FVector LastWallNormal = FVector::ZeroVector;
|
||||
bool bCameraTest = false;
|
||||
|
||||
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,17 +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.
|
||||
- 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.3 — Camera clipping fixes (patch)
|
||||
|
||||
### Patch tasks - active - session-5598ce7e-27e3-4c64-bb49-c04a4a31ee58 (branch `camera-clip-0.2.3`)
|
||||
|
||||
- [A] Fix remaining camera clipping cases in `0.2.x`. **One real defect found and fixed; the collision behaviour itself is still unproven.**
|
||||
- **Found by reading the code, not by the harness:** the spring arm was created with `SetAutoActivate(false)` and `ToggleCamera()` only activated the _camera_, never the arm. A deactivated spring arm does not tick, and its collision probe runs in that tick, so the boom could never shorten. `ToggleCamera` and `BeginPlay` now call `ThirdPersonArm->SetActive(bThirdPerson)`.
|
||||
- **The measurement that was supposed to prove it does not work yet.** `-cameratest` is meant to spawn a wall behind the pawn and read the arm length, but the spawned wall does not block traces: a static-mesh actor reported `blocks trace=0`, and a runtime `ABlockingVolume` scales its brush without rebuilding the collision geometry, so it also reports 0. Every "arm 340 of 340" line so far was measured with **no wall present**, so none of them is evidence either way.
|
||||
- **Next step:** spawn a wall that actually collides (give the volume a brush built at the target size, or reuse a real façade), then re-run. Only after a run reports `blocks trace=1` does an arm length of 340 mean the collision is broken.
|
||||
- **Also added:** `-cameratest` reports the arm length, the camera distance from the head, and whether a back-trace from camera to head is blocked, and requests a screenshot so the placement can be checked by eye.
|
||||
- [ ] Tag `v0.2.3` and write `CHANGELOG.md` entry; then remove this section.
|
||||
|
||||
## 0.3.0 — Chaos vehicle, enter/exit, closed driving route (weeks 10–13)
|
||||
|
||||
### Vehicle production
|
||||
|
||||
Reference in new issue
Block a user