Compare commits
6
Commits
v0.2.2
..
266fc1bb0c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
266fc1bb0c | ||
|
|
73b5bd6cd1 | ||
|
|
82cafc2f29 | ||
|
|
3e4dbd1014 | ||
|
|
a6701aa3d1 | ||
|
|
d8b44f1e57 |
No files matched your search
@@ -179,7 +179,11 @@ Always use a consistent scale test, named export presets, and repeatable import
|
||||
|
||||
## Blender skills
|
||||
|
||||
`.agents/skills/blender-skills/` holds 94 Blender skill packs (MIT, blender-skills 1.3.0). They are agent instructions, not add-ons, and nothing in the pipeline depends on them.
|
||||
The 93 upstream Blender skill packs (MIT, blender-skills 1.3.0) live once, in the **common** agent folder `~/.pi/agent/skills/`, together with the shared `references/` notes and the upstream `LICENSE`. They are agent instructions, not add-ons, and nothing in the pipeline depends on them.
|
||||
|
||||
Only the project-specific pack stays in the repository: `.agents/skills/blender-skills/blender-director/` — the pipeline orchestrator, which names this project's tools and stages. It refers to the shared notes by absolute path (`~/.pi/agent/skills/references/…`).
|
||||
|
||||
Do not copy the common packs into the repository: a second copy under a different root is a name collision, and Pi keeps the first one it finds and warns on every start. Add a pack to `~/.pi/agent/skills/<pack>/SKILL.md` (one level down, flat) and it is picked up everywhere; `references/` sits beside them at `~/.pi/agent/skills/references/`.
|
||||
|
||||
**All agents must consult the relevant skill packs before starting a task in that discipline.** Each patch section in `TODO.md` lists its suggested skills; the general mapping is:
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
+3
-2
@@ -33,8 +33,9 @@ Unreal Engine 5.9 is in preview and Unreal Engine 6 has been announced as of Nov
|
||||
| --- | --- |
|
||||
| Package | blender-skills `1.3.0`, upstream commit `8f778d2`, MIT |
|
||||
| Source | <https://github.com/arjun988/blender-skills> |
|
||||
| Location | Local only: `.agents/skills/blender-skills/` — not distributed with the repository |
|
||||
| Installed | 2026-11-06, copied from a local checkout of `.claude/skills/` without edits |
|
||||
| Location | Local only, common root: `~/.pi/agent/skills/` (93 packs, `references/`, `LICENSE`) — not distributed with the repository |
|
||||
| Project-specific | `.agents/skills/blender-skills/blender-director/` in this repository |
|
||||
| Installed | 2026-11-06, copied from a local checkout of `.claude/skills/` without edits; flattened to the common root on 2026-11-10 |
|
||||
|
||||
These are instructions and reference notes for agents, not code that runs in a build. Four of them assume a **Blender MCP server**; this project drives Blender headlessly through `bpy` (`Tools/*.py`) instead, so MCP is optional and nothing depends on it.
|
||||
|
||||
|
||||
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,9 @@
|
||||
#include "Engine/World.h"
|
||||
#include "TimerManager.h"
|
||||
#include "Containers/Ticker.h"
|
||||
#include "Camera/PlayerCameraManager.h"
|
||||
#include "Engine/StaticMeshActor.h"
|
||||
#include "UnrealClient.h"
|
||||
#include "HAL/IConsoleManager.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "Misc/CommandLine.h"
|
||||
@@ -311,6 +314,11 @@ void AGigLineCharacter::BeginPlay()
|
||||
// `-walk` holds forward input from the first frame. The screenshot run uses it
|
||||
// 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.
|
||||
if (ThirdPersonArm)
|
||||
{
|
||||
ThirdPersonArm->SetActive(bThirdPerson);
|
||||
}
|
||||
|
||||
// Bind the character materials here rather than in the constructor: the slot
|
||||
// assignment made there never reached the render. LoadObject, not FObjectFinder,
|
||||
// because FObjectFinder may only be used inside a constructor - putting one in
|
||||
@@ -333,6 +341,7 @@ void AGigLineCharacter::BeginPlay()
|
||||
}
|
||||
|
||||
bWalkForever = FParse::Param(FCommandLine::Get(), TEXT("walk"));
|
||||
bCameraTest = FParse::Param(FCommandLine::Get(), TEXT("cameratest"));
|
||||
|
||||
// `-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
|
||||
@@ -346,6 +355,102 @@ void AGigLineCharacter::BeginPlay()
|
||||
}
|
||||
}
|
||||
|
||||
float AGigLineCharacter::GetThirdPersonArmLength() const
|
||||
{
|
||||
return ThirdPersonArm ? ThirdPersonArm->TargetArmLength : 0.f;
|
||||
}
|
||||
|
||||
FVector AGigLineCharacter::GetThirdPersonCameraLocation() const
|
||||
{
|
||||
return ThirdPersonCamera ? ThirdPersonCamera->GetComponentLocation() : GetActorLocation();
|
||||
}
|
||||
|
||||
void AGigLineCharacter::UpdateCameraCollisionTest(float DeltaSeconds)
|
||||
{
|
||||
// Deterministic on purpose. Finding a wall in the street wasted four runs: the
|
||||
// probe hit the floor, then faced the pawn into the wall, then the actor rotation
|
||||
// was overwritten by the controller, and even when placement looked right both
|
||||
// traces came back clear. A spawned wall behind the pawn removes every one of
|
||||
// those variables.
|
||||
CameraTestElapsed += DeltaSeconds;
|
||||
UWorld* World = GetWorld();
|
||||
if (!World)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CameraTestPlaced)
|
||||
{
|
||||
CameraTestPlaced = true;
|
||||
// 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 * 400.f - FVector(0.f, 0.f, 90.f);
|
||||
FActorSpawnParameters Params;
|
||||
Params.ObjectFlags |= RF_Transient;
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CameraTestElapsed < 2.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const float Rest = ThirdPersonBoomLength;
|
||||
const float Arm = GetThirdPersonArmLength();
|
||||
const FVector CameraLoc = GetThirdPersonCameraLocation();
|
||||
const FVector Head = GetActorLocation() + FVector(0.f, 0.f, 60.f);
|
||||
const float Dist = FVector::Dist(Head, CameraLoc);
|
||||
|
||||
// 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() * 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: 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)
|
||||
{
|
||||
CameraTestWall->Destroy();
|
||||
CameraTestWall = nullptr;
|
||||
}
|
||||
bCameraTest = false;
|
||||
}
|
||||
|
||||
void AGigLineCharacter::ToggleDebugOverlay()
|
||||
{
|
||||
static IConsoleVariable* Var = IConsoleManager::Get().FindConsoleVariable(TEXT("gigline.Debug"));
|
||||
@@ -852,6 +957,11 @@ void AGigLineCharacter::Tick(float DeltaSeconds)
|
||||
Super::Tick(DeltaSeconds);
|
||||
// Speed-driven animation state: correct whether the player walked, was pushed,
|
||||
// or fell, and independent of which input produced the movement.
|
||||
if (bCameraTest)
|
||||
{
|
||||
UpdateCameraCollisionTest(GetWorld() ? GetWorld()->GetDeltaSeconds() : 0.f);
|
||||
}
|
||||
|
||||
WalkForever();
|
||||
UpdateBodyAnimation();
|
||||
|
||||
@@ -866,6 +976,15 @@ void AGigLineCharacter::ToggleCamera()
|
||||
bThirdPerson = !bThirdPerson;
|
||||
FirstPersonCamera->SetActive(!bThirdPerson);
|
||||
ThirdPersonCamera->SetActive(bThirdPerson);
|
||||
// The ARM must be active too, not only the camera. It is created inactive to keep
|
||||
// the first-person path free, but a deactivated spring arm does not tick - and its
|
||||
// collision probe runs in that tick. Leaving it off was why the boom never
|
||||
// shortened: with a 6 m wall spawned 1.6 m behind the pawn the camera still sat at
|
||||
// its full 340 cm.
|
||||
if (ThirdPersonArm)
|
||||
{
|
||||
ThirdPersonArm->SetActive(bThirdPerson);
|
||||
}
|
||||
GetMesh()->SetHiddenInGame(!bThirdPerson);
|
||||
if (HairMesh)
|
||||
{
|
||||
|
||||
@@ -200,6 +200,21 @@ protected:
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
||||
TObjectPtr<UInputAction> ToggleDebugAction;
|
||||
|
||||
/** Current boom length and camera position of the third-person rig. */
|
||||
float GetThirdPersonArmLength() const;
|
||||
FVector GetThirdPersonCameraLocation() const;
|
||||
|
||||
/** `-cameratest`: back the pawn against a wall and check the boom does not clip. */
|
||||
void UpdateCameraCollisionTest(float DeltaSeconds);
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<class AStaticMeshActor> CameraTestWall;
|
||||
|
||||
FVector LastWallNormal = FVector::ZeroVector;
|
||||
bool bCameraTest = false;
|
||||
bool CameraTestPlaced = false;
|
||||
float CameraTestElapsed = 0.0f;
|
||||
|
||||
/** Flips the gigline.Debug console variable that the HUD reads. */
|
||||
void ToggleDebugOverlay();
|
||||
|
||||
|
||||
@@ -512,3 +512,11 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO.
|
||||
- **A 1 cm solidify shell lets the body poke through.** Garments built by duplicating body faces needed 2 cm of solidify plus an 8 mm fatten along their own normals before the cloth read as continuous at shoulders, hips and knees.
|
||||
- **Warm skin sampling as blue-grey was lighting, not material.** The body stood in building shadow and was lit almost entirely by the blue `Demo_SkyLight` (intensity 2.6): face (99, 98, 100), arms (67, 74, 81). Raising the sun to pitch -74 moved the face to (131, 121, 117). A deliberate red test colour reaching the render first proved the material and the slot assignment were fine, which is what stopped a long hunt in the wrong place.
|
||||
- **The Unreal commandlet drops unknown command-line switches.** A `--unlit-test` flag passed after `-script` never reached Python; an environment variable does get through (and even that proved unnecessary once the red test settled the question).
|
||||
|
||||
## 2026-11-10 — skills: one common copy, project-specific stays local
|
||||
|
||||
- **Symlinked packs were the wrong fix.** The 2026-11-06 fix put 94 symlinks in `~/.agents/skills/<pack>` → the repo, while `~/.pi/agent/skills/blender-skills/` held a full second copy of the same packs. Pi keeps the first discovery and warns on every start: 94 "collision" lines. `~/.agents/skills/blender-skills/` (the upstream git checkout) also contains 94 packs under `.claude/skills/` and `.cursor/skills/` — inert, because dot-directories are not scanned.
|
||||
- **`blender-director/SKILL.md` never loaded.** It declared `role:` twice in `metadata` (`specialist` then `orchestrator`); duplicate YAML keys are fatal, so the pack was dropped silently while the other 94 loaded.
|
||||
- **Layout now** — shared, one level down and flat so it is discovered: `~/.pi/agent/skills/<93 packs>/`, `~/.pi/agent/skills/references/`, `~/.pi/agent/skills/LICENSE`. Project-specific and versioned: `.agents/skills/blender-skills/blender-director/`, whose `../references/` links were rewritten to `~/.pi/agent/skills/references/…` because it no longer sits beside them. The 94 `~/.agents/skills` symlinks are gone.
|
||||
- **Verified** by walking the three discovery roots (`~/.pi/agent/skills`, `~/.agents/skills`, project `.agents/skills`, dot-dirs skipped), parsing every frontmatter: **97 skills loaded, 0 malformed, 0 collisions**. Backup of the old trees: `/tmp/agent-skills-backup.tgz`.
|
||||
- Rule: a skill exists in **one** place. Two roots with the same `name` is a warning on every start, and the loser is invisible — check the startup list, not the file tree.
|
||||
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.
|
||||
- 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
|
||||
|
||||
- [ ] Fix remaining camera clipping cases in `0.2.x`.
|
||||
- [ ] 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