Add Planar Capture System implementation checklist and developer reference

- Created a comprehensive implementation checklist for the Planar Capture System (Systems 136-147) detailing tasks across multiple phases including C++ core, material foundation, Blueprint actors, data assets, integration, and performance testing.
- Added a developer reference document outlining the architecture, data flow, state machine, budget enforcement, render target pooling, horror features, integration points, multiplayer networking, performance characteristics, debugging methods, and build order for the capture systems.
- Introduced examples of capture surface usage in the Project Void horror game, including specific implementations for mirrors, monitors, portals, and fake windows, along with a checklist for integration tasks.
This commit is contained in:
Lefteris Notas
2026-05-22 15:36:08 +03:00
parent 6b6c702dd7
commit 0a2d08b2ad
34 changed files with 5245 additions and 32 deletions

View File

@@ -0,0 +1,202 @@
# Planar Capture System Architecture — UE5 Modular Game Framework
**Version:** 1.0 | **Systems:** 136-147 (12 systems) | **Phase:** 17 — Rendering & Visual
This document specifies the architecture of the Planar Capture System — a unified rendering pipeline for mirrors, portals, monitors, and horror surfaces. One capture pipeline, one quality manager, one material interface.
---
## Architecture Overview
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ BLUEPRINT LAYER (Designer-Facing) │
│ BP_Mirror BP_HorrorMirror BP_Portal BP_Monitor BP_FakeWindow │
│ DA_PlanarCaptureProfile MPC_CaptureSurface MI_Mirror_Clean/Dirty/Steam │
├─────────────────────────────────────────────────────────────────────────────┤
│ C++ LAYER (Performance-Critical) │
│ UBPC_PlanarCapture — SceneCapture2D lifecycle, camera math │
│ ABP_PlanarCaptureActor — Surface mesh, MDI, overlap/proximity │
│ ASS_PlanarCaptureManager — Global budget, RT pool, scoring │
│ UPlanarCaptureCameraUtils — Mirror/Portal/Oblique math (static) │
├─────────────────────────────────────────────────────────────────────────────┤
│ UE5 ENGINE │
│ USceneCaptureComponent2D UTextureRenderTarget2D UMaterialParameterColl │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## System Map (12 Systems — Files 136-147)
| # | System | Type | Parent Class | Purpose |
|---|--------|------|-------------|---------|
| 136 | `BPC_PlanarCapture` | BPC_ Component | `ActorComponent` | Core capture: SceneCapture2D lifecycle, camera math, RT management, actor lists, horror ring buffer |
| 137 | `BP_PlanarCaptureActor` | BP_ Actor | `Actor` | Placeable surface actor: mesh, MDI, proximity trigger, manager registration |
| 138 | `SS_PlanarCaptureManager` | SS_ Subsystem | `WorldSubsystem` | Global budget manager: surface scoring, quality tier assignment, RT pool |
| 139 | `BP_Mirror` | BP_ Actor | `BP_PlanarCaptureActor` | Standard mirror: Mode=Mirror, dirt/steam/condensation layers, aging |
| 140 | `BP_Portal` | BP_ Actor | `BP_PlanarCaptureActor` | Portal surface: Mode=Portal, linked target, teleport on overlap, clip plane |
| 141 | `BP_Monitor` | BP_ Actor | `BP_PlanarCaptureActor` | Security screen/TV: Mode=Monitor, fixed camera ref, low update rate, scanlines |
| 142 | `BP_HorrorMirror` | BP_ Actor | `BP_Mirror` | Horror mirror: wrong reflection actor, delayed frame, steam text reveal, scare events |
| 143 | `BP_FakeWindow` | BP_ Actor | `BP_PlanarCaptureActor` | Architectural fake window: Mode=FakeWindow, linked sublevel, weather overlay |
| 144 | `M_CaptureSurface_Master` | Material | `Material` | Master unlit material: RT sample, condensation, dirt, steam, horror layers |
| 145 | `MPC_CaptureSurface` | MPC | `MaterialParameterCollection` | Global MPC: SteamIntensity, DirtOpacity, MirrorDarkness, WrongReflectionBlend, etc. (10 params) |
| 146 | `DA_PlanarCaptureProfile` | DA_ Data Asset | `PrimaryDataAsset` | Per-surface capture config: default mode, quality profile overrides, actor lists |
| 147 | `MI_Mirror_Clean/Dirty/Steam/Horror` | MI_ Instances | `M_CaptureSurface_Master` | Pre-configured material instances for common mirror states |
---
## Enums
### `EPlanarCaptureMode` (C++: defined in `PlanarCaptureCommon.h`)
| Value | Description |
|-------|-------------|
| `Mirror` | Standard planar mirror reflection |
| `Portal` | Portal with linked target surface |
| `Monitor` | Fixed-camera security screen / TV |
| `HorrorMirror` | Mirror with horror features (wrong reflection, delayed frame) |
| `HorrorPortal` | Portal with horror features |
| `FakeWindow` | Architectural fake window (parallax, weather) |
### `EPlanarCaptureQualityTier` (C++: defined in `PlanarCaptureCommon.h`)
| Value | RT Size | FPS | Shadows | Lumen | Post | Clip Plane |
|-------|---------|-----|---------|-------|------|-----------|
| `Off` | — | 0 | — | — | — | — |
| `Low` | 256 | 4 | No | No | No | No |
| `Medium` | 512 | 15 | Dynamic | Optional | No | Yes |
| `High` | 1024 | 30 | Full | Yes | Minimal | Yes |
| `Hero` | 2048 | 60 | Full | Yes | Full | Yes |
---
## Communication Matrix
| Source | Target | Method | What |
|--------|--------|--------|------|
| `BP_PlanarCaptureActor` | `SS_PlanarCaptureManager` | Direct (RegisterSurface) | Registers on BeginPlay |
| `SS_PlanarCaptureManager` | `BPC_PlanarCapture` | Direct (ApplyQualityTier) | Assigns quality tier |
| `BPC_PlanarCapture` | `USceneCaptureComponent2D` | Direct (owns) | Camera math + CaptureScene |
| `BPC_PlanarCapture` | `MPC_CaptureSurface` | Direct (SetScalarParameter) | Pushes steam/dirt/horror params |
| `BP_HorrorMirror` | `BPC_ScareEventSystem` (101) | Interface / Dispatcher | Triggers coordinated scares |
| `BP_HorrorMirror` | `SS_AudioManager` (132) | Direct | Plays mirror horror SFX |
| `BPC_PlanarCapture` | `BPC_StateManager` (130) | IsActionPermitted() | Checks if capture can activate |
| `BP_Portal` | Player Pawn | Overlap Event | Teleports player through portal |
---
## Quality Scoring Algorithm
```
CompositeScore = (ScreenCoverage × 0.5) + (FacingAngle × 0.3) + (DistanceFactor × 0.1) + (ScriptedPriority × 0.1)
Tier assignment:
Score ≥ 0.8 → Hero (capped at GlobalQualityCap, max MaxHeroSurfaces)
Score ≥ 0.5 → High (capped at max MaxHighSurfaces)
Score ≥ 0.2 → Medium (capped at max MaxMediumSurfaces)
Score > 0 → Low
Score = 0 or !inFrustum → Off
```
---
## Material Layer Stack (M_CaptureSurface_Master)
```
Layer 0: Render target sample (UV-flipped for mirror, straight for portal/monitor)
Layer 1: Condensation normal map → distorts UV of RT sample
Layer 2: Fresnel edge fade mask
Layer 3: Dirt/scratch multiply (DirtOpacity MPC param)
Layer 4: Steam/fog lerp (animated noise, SteamIntensity MPC param)
Layer 5: Steam emissive glow (backlit fog, SteamEmissiveIntensity)
Layer 6: Text reveal mask lerp (TextRevealProgress, uses steam as carrier)
Layer 7: Mirror darkness multiply (MirrorDarkness MPC param)
Layer 8: Wrong reflection crossfade (WrongReflectionBlend MPC param)
Output: Unlit shading model
```
---
## Horror Features
| Feature | Driven By | Layer |
|---------|-----------|-------|
| Mirror-only ghost actor | ShowOnly list in C++ | C++ |
| Wrong reflection Metahuman swap | ActivateHorrorReflection() | C++ |
| Delayed frame reflection | FrameRingBuffer + DelayedReflectionBlend MPC | C++ + Material |
| Steam fogging | SteamIntensity MPC → Layer 4 | Material |
| Dirt / scratches | DirtOpacity MPC → Layer 3 | Material |
| Condensation rivulets | CondensationFlow MPC → Layer 1 | Material |
| UV distortion / breathing | DistortionAmplitude MPC → Layer 1 | Material |
| Text in steam reveal | TextRevealProgress MPC → Layer 6 | Material |
| Mirror goes dark | MirrorDarkness MPC → Layer 7 | Material |
| Wrong reflection crossfade | WrongReflectionBlend MPC → Layer 8 | Material |
| Surface aging/oxidation | SurfaceAge MPC → Layer 3 (tint) | Material |
---
## Blueprint Limitations & Workarounds
### `USceneCaptureComponent2D::CaptureScene()` (C++ Only)
**Workaround:** Call from C++ in `UBPC_PlanarCapture`. Blueprint calls `CaptureNow()` which invokes C++ capture.
**Affected Files:** 136, 139-143
### `FSceneView::ViewMatrices` for Oblique Projection (C++ Only)
**Workaround:** Use `UPlanarCaptureCameraUtils::ComputeObliqueProjectionMatrix()` (BlueprintCallable).
**Affected Files:** 136, 140
### `USceneCaptureComponent2D::ShowOnlyActors` Runtime Modification (Partial C++)
**Workaround:** `UBPC_PlanarCapture::UpdateActorLists()` resolves TSoftObjectPtrs into the array.
**Affected Files:** 136, 142
---
## Performance Budget Guidelines
| Tier | Max Simultaneous | RT Memory per Surface | GPU Cost |
|------|-----------------|----------------------|----------|
| Hero | 1 | 16 MB (2048² × 4B) | Very High |
| High | 3 | 4 MB (1024² × 4B) | High |
| Medium | 6 | 1 MB (512² × 4B) | Medium |
| Low | Unlimited | 256 KB (256² × 4B) | Low |
| Off | — | 0 | None |
**Total Budget:** 128 MB default (configurable via `SS_PlanarCaptureManager.MaxTotalRenderTargetMemoryMB`)
---
## Multiplayer Considerations
- Capture rendering is **local-only** — each client renders their own view
- `BP_PlanarCaptureActor` replicates `bIsActive` for server-authoritative surface control
- Horror events (wrong reflection activation) are triggered server-side and replicated via gameplay tags
- No client prediction needed — captures are cosmetic
---
## Integration Points with Existing Systems
| Existing System | Integration |
|----------------|-------------|
| `BPC_StateManager` (130) | Query `IsActionPermitted()` before enabling capture, teleport gating |
| `BPC_ScareEventSystem` (101) | Horror mirror events trigger coordinated scares |
| `SS_AudioManager` (132) | Mirror/portal SFX route through audio subsystem |
| `SS_EnhancedInputManager` (128) | Input context switch for portal inspection mode |
| `BPC_DiegeticDisplay` (18) | Monitors can display diegetic UI render targets |
| `BPC_CameraStateLayer` (14) | Camera FOV adjustments during portal transitions |
| `I_Persistable` (36) | Mirror surface state (destroyed, dirty, oxidized) saves/loads |
| `DA_ScareEvent` (127) | Mirror apparition scare event data asset |
| `WBP_SettingsMenu` (57) | Capture surface quality settings (Performance section) |
---
## Build Order (Phase 17)
1. **Phase 17a:** C++ Core — `PlanarCaptureCommon.h`, `PlanarCaptureCameraUtils`, `BPC_PlanarCapture`, `SS_PlanarCaptureManager`, `BP_PlanarCaptureActor`
2. **Phase 17b:** Material Foundation — `M_CaptureSurface_Master`, `MPC_CaptureSurface`, `MI_Mirror_*` instances
3. **Phase 17c:** Blueprint Actors — `BP_Mirror`, `BP_Portal`, `BP_Monitor`, `BP_HorrorMirror`, `BP_FakeWindow`
4. **Phase 17d:** Data Assets — `DA_PlanarCaptureProfile`
5. **Phase 17e:** Integration — Wire horror events to `BPC_ScareEventSystem`, audio to `SS_AudioManager`, persistence to `I_Persistable`
---
*Planar Capture System Architecture v1.0 — See `docs/blueprints/17-capture/` for per-system blueprint specs.*

View File

@@ -0,0 +1,157 @@
# 136 — Planar Capture Component (`BPC_PlanarCapture`)
## Purpose
Core capture component managing `USceneCaptureComponent2D` lifecycle for mirrors, portals, monitors, and horror surfaces. All camera math, render target management, and per-frame capture decisions happen here in C++ for performance.
## Dependencies
- **Requires:** `SS_PlanarCaptureManager` (138) for quality tier assignment and RT pool, `UPlanarCaptureCameraUtils` for camera math
- **Required By:** `BP_PlanarCaptureActor` (137) — owned by parent actor
- **Engine/Plugin Requirements:** Renderer, RenderCore modules
## Class Info
| Property | Value |
|----------|-------|
| **Parent Class** | `ActorComponent` (C++ `UBPC_PlanarCapture`) |
| **Class Type** | Blueprint Component (C++ Full Implementation) |
| **Asset Path** | `Content/Framework/Capture/` |
| **C++ Header** | `Source/PG_Framework/Public/Capture/BPC_PlanarCapture.h` |
| **C++ Source** | `Source/PG_Framework/Private/Capture/BPC_PlanarCapture.cpp` |
| **C++ Status** | ✅ Full Implementation |
| **BP Asset** | None — use C++ component directly on actors |
## 1. Enums
*Defined in `PlanarCaptureCommon.h` — see Architecture doc for full listing.*
| Enum | Values | Description |
|------|--------|-------------|
| `EPlanarCaptureMode` | Mirror, Portal, Monitor, HorrorMirror, HorrorPortal, FakeWindow | Capture surface mode |
| `EPlanarCaptureQualityTier` | Off, Low, Medium, High, Hero | Quality tier levels |
| `EPlanarCaptureInitResult` | Success, NoRenderTargetPool, InvalidSurfaceMesh, BudgetExceeded, ManagerUnavailable | Init result codes |
## 2. Structs
*Defined in `PlanarCaptureCommon.h`*
### `FPlanarCaptureQualityProfile`
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `RenderTargetSize` | int32 | 512 | Square RT resolution (256/512/1024/2048) |
| `CaptureInterval` | float | 0.0667 | Min seconds between captures (~15fps default) |
| `bEnableShadows` | bool | true | Shadow rendering toggle |
| `bEnablePostProcess` | bool | false | Post-process toggle |
| `bEnableFog` | bool | false | Exponential height fog toggle |
| `bEnableBloom` | bool | false | Bloom toggle |
| `bEnableAO` | bool | false | Ambient occlusion toggle |
| `bEnableLumen` | bool | false | Lumen GI toggle (expensive) |
| `bEnableMotionBlur` | bool | false | Motion blur toggle |
| `bEnableClipPlane` | bool | true | Oblique near-plane toggle |
| `DelayedFrameCount` | int32 | 0 | Horror delayed frame ring buffer size |
## 3. Variables
### Configuration (EditAnywhere, BlueprintReadOnly)
| Variable | Type | Default | Category | Description |
|----------|------|---------|----------|-------------|
| `CaptureMode` | EPlanarCaptureMode | Mirror | `Capture\|Config` | Surface type |
| `QualityProfiles` | TArray〈FPlanarCaptureQualityProfile〉 | 4 entries | `Capture\|Config` | Quality profiles per tier [0=Low,1=Med,2=High,3=Hero] |
| `CaptureFOV` | float | 90.0 | `Capture\|Config` | Capture camera FOV |
| `MaxViewDistance` | float | 5000.0 | `Capture\|Config` | Max render distance |
| `ShowOnlyActors` | TArray〈FPlanarCaptureActorListEntry〉 | — | `Capture\|ActorLists` | Exclusive show actors |
| `HiddenActors` | TArray〈FPlanarCaptureActorListEntry〉 | — | `Capture\|ActorLists` | Hidden actors |
| `WrongReflectionActor` | TSoftObjectPtr〈AActor〉 | — | `Capture\|Horror` | Horror mode wrong reflection swap |
| `SurfaceMeshComponent` | TSoftObjectPtr〈UStaticMeshComponent〉 | — | `Capture\|Config` | Mesh for clip plane calculation |
| `LinkedTargetSurface` | TSoftObjectPtr〈ABP_PlanarCaptureActor〉 | — | `Capture\|Portal` | Portal destination surface |
| `FixedCameraActor` | TSoftObjectPtr〈AActor〉 | — | `Capture\|Monitor` | Monitor fixed camera |
### Runtime (BlueprintReadOnly)
| Variable | Type | Description |
|----------|------|-------------|
| `CurrentQualityTier` | EPlanarCaptureQualityTier | Assigned quality tier |
| `bIsCapturing` | bool | Is capture currently active |
| `CaptureRenderTarget` | UTextureRenderTarget2D* | Active render target |
## 4. Functions
### Public (BlueprintCallable)
#### `InitializeCapture()` → `EPlanarCaptureInitResult`
- **Description:** Allocates RT from pool, creates USceneCaptureComponent2D, configures show flags
- **Flow:** Request RT → Create SceneCapture → ApplyShowFlags → UpdateActorLists → Set bIsCapturing
- **Nodes Used:** `RequestRenderTarget`, `CreateSceneCaptureComponent2D`, `ApplyShowFlags`, `UpdateActorLists`
#### `ShutdownCapture()`
- **Description:** Stops capture, releases RT to pool, destroys SceneCapture2D
- **Flow:** Set bIsCapturing=false → DestroyComponent → ReleaseRenderTarget → Clear ring buffer
#### `ApplyQualityTier(Tier: EPlanarCaptureQualityTier)`
- **Description:** Apply a quality tier profile immediately. Called by SS_PlanarCaptureManager.
- **Flow:** If Off → ShutdownCapture. If transitioning from Off → InitializeCapture. Else → UpdateShowFlags + ApplyProfile.
#### `CaptureNow()`
- **Description:** Bypasses tick interval, captures immediately. Used for event-driven captures.
- **Blueprint Authority:** Any (local)
- **Flow:** Get viewer camera → ComputeCaptureCameraTransform → Set SceneCapture transform → CaptureScene → PushMPCParameters
#### `ActivateHorrorReflection()`
- **Description:** Saves original ShowOnly list, swaps to WrongReflectionActor
- **Flow:** Save ShowOnlyActors → Clear list → Add WrongReflectionActor → UpdateActorLists
#### `DeactivateHorrorReflection()`
- **Description:** Restores original ShowOnly list after horror event
- **Flow:** Clear list → Restore from SavedShowOnlyActors → UpdateActorLists
#### `SetScriptedPriority(Priority: float)`
- **Description:** Scripted priority override (0.0-1.0). Higher values force higher quality tier.
#### `PushMPCParameters(MPC: UMaterialParameterCollection*)`
- **Description:** Push all 10 MPC scalar parameters for surface material effects
### Compute (BlueprintPure)
#### `ComputeCaptureCameraTransform(ViewerCamera: FTransform)` → `FTransform`
- **Description:** Computes capture camera position based on mode (mirror reflection, portal relative, etc.)
#### `GetCurrentScore()` → `FPlanarCaptureScore`
- **Description:** Returns current composite quality score for this surface
## 5. Event Dispatchers
| Dispatcher | Parameters | Description |
|------------|-----------|-------------|
| `OnCaptureQualityChanged` | OldTier, NewTier | Quality tier changed |
| `OnCaptureInitialized` | Result: EPlanarCaptureInitResult | Init completed |
| `OnCaptureRendered` | — | Each frame rendered |
## 6. Communication Matrix
| Target System | Method | What |
|---------------|--------|------|
| `SS_PlanarCaptureManager` | Direct (cached reference) | RT requests, quality tier reception |
| `BP_PlanarCaptureActor` | Direct (owner) | Surface mesh, MPC reference |
| `UPlanarCaptureCameraUtils` | Static function calls | Mirror/portal/oblique math |
| `USceneCaptureComponent2D` | Direct (owns) | Full lifecycle control |
## 7. Manual Implementation Guide
*The C++ component is fully functional. Blueprint users interact through the public API:*
1. To force a capture (e.g., on a sequencer event):
```
Get BPC_PlanarCapture → Call CaptureNow()
```
2. To trigger a horror mirror wrong reflection:
```
Get BPC_PlanarCapture → Call ActivateHorrorReflection()
Wait (duration from curve) → Call DeactivateHorrorReflection()
```
3. To boost a specific mirror for a scare moment:
```
Get BPC_PlanarCapture → Call SetScriptedPriority(1.0)
Wait (scare duration) → Call SetScriptedPriority(0.0)
```
## 8. Build Checklist
- [ ] C++ component compiled and functional
- [ ] No BP child needed — attach directly to actor
- [ ] Configure QualityProfiles array in component defaults (4 entries)
- [ ] Set CaptureMode in component defaults
- [ ] Assign SurfaceMeshComponent reference

View File

@@ -0,0 +1,125 @@
# 137 — Planar Capture Actor (`BP_PlanarCaptureActor`)
## Purpose
Placeable actor wrapping a `BPC_PlanarCapture` component. Owns the surface mesh, material dynamic instances, proximity trigger for quality scoring, and the capture component. Blueprint children (139-143) extend this for specific modes.
## Dependencies
- **Requires:** `BPC_PlanarCapture` (136), `SS_PlanarCaptureManager` (138)
- **Required By:** `BP_Mirror` (139), `BP_Portal` (140), `BP_Monitor` (141), `BP_HorrorMirror` (142), `BP_FakeWindow` (143)
- **Engine/Plugin Requirements:** Renderer module
## Class Info
| Property | Value |
|----------|-------|
| **Parent Class** | `Actor` (C++ `ABP_PlanarCaptureActor`) |
| **Class Type** | Blueprint Actor |
| **Asset Path** | `Content/Framework/Capture/` |
| **C++ Header** | `Source/PG_Framework/Public/Capture/BP_PlanarCaptureActor.h` |
| **C++ Status** | ✅ Full Implementation |
| **BP Asset** | BP children: `BP_Mirror`, `BP_Portal`, `BP_Monitor`, `BP_HorrorMirror`, `BP_FakeWindow` |
## 1. Components
| Component | Type | Description |
|-----------|------|-------------|
| `Root` | SceneComponent | Root transform |
| `SurfaceMesh` | StaticMeshComponent | Surface plane/quad mesh, collision enabled |
| `ProximityTrigger` | BoxComponent | Overlap volume for player proximity scoring (500x500x500 default) |
| `CaptureComponent` | UBPC_PlanarCapture | Core capture logic |
## 2. Variables
### Configuration
| Variable | Type | Default | Category | Description |
|----------|------|---------|----------|-------------|
| `SurfaceDisplayName` | FString | "" | `Capture\|Config` | Debug/display name |
| `bStartEnabled` | bool | true | `Capture\|Config` | Start active on BeginPlay |
| `bDestructible` | bool | false | `Capture\|Config` | Can be destroyed (shattered mirror) |
| `SurfaceMPC` | UMaterialParameterCollection* | — | `Capture\|Material` | Global MPC reference |
### Runtime
| Variable | Type | Description |
|----------|------|-------------|
| `bIsActive` | bool | Current active state |
| `SurfaceMaterialInstance` | UMaterialInstanceDynamic* | Created dynamic material instance |
### Replicated
| Variable | Type | Condition | Description |
|----------|------|-----------|-------------|
| `bRepIsActive` | bool | ReplicatedUsing OnRep_IsActive | Server-authoritative active state |
## 3. Functions
#### `EnableSurface()`
- **Description:** Activates the surface, initializes capture component
- **Flow:** Set bIsActive=true → CaptureComponent.InitializeCapture()
#### `DisableSurface()`
- **Description:** Deactivates the surface, shuts down capture
- **Flow:** Set bIsActive=false → CaptureComponent.ShutdownCapture()
#### `SetCaptureMode(NewMode: EPlanarCaptureMode)`
- **Description:** Change capture mode at runtime
- **Flow:** Shutdown → Change CaptureComponent.CaptureMode → Re-initialize → Broadcast OnModeChanged
#### `SetSurfaceMaterial(NewMaterial: UMaterialInterface*)`
- **Description:** Swap surface material at runtime (clean ↔ dirty mirror, etc.)
- **Flow:** SurfaceMesh.CreateDynamicMaterialInstance(NewMaterial) → Store as SurfaceMaterialInstance
#### `SetSurfaceMPCParameter(ParameterName: FName, Value: float)`
- **Description:** Set a single MPC scalar parameter on the surface's MID
#### `DestroySurface()`
- **Description:** Destroy the surface (shatter mirror, break monitor). Respects bDestructible flag.
- **Flow:** DisableSurface → Broadcast OnSurfaceDestroyed → (BP child handles visual FX)
## 4. Event Dispatchers
| Dispatcher | Parameters | Description |
|------------|-----------|-------------|
| `OnModeChanged` | NewMode: EPlanarCaptureMode | Mode changed at runtime |
| `OnSurfaceDestroyed` | Surface: ABP_PlanarCaptureActor* | Surface destroyed |
## 5. Overlap Events
| Event | Logic |
|-------|-------|
| `OnProximityBeginOverlap` | If OtherActor has Tag "Player" → CaptureComponent.SetScriptedPriority(0.3) |
| `OnProximityEndOverlap` | If OtherActor has Tag "Player" → CaptureComponent.SetScriptedPriority(0.0) |
## 6. Communication Matrix
| Target System | Method | What |
|---------------|--------|------|
| `SS_PlanarCaptureManager` | Direct (RegisterSurface) | Registers on BeginPlay |
| `BPC_PlanarCapture` | Direct (owns) | Full component access |
| `BPC_ScareEventSystem` (101) | Dispatcher / Interface | Horror mirror scare triggers |
| `SS_AudioManager` (132) | Direct | Surface audio (shatter, portal whoosh) |
## 7. Manual Implementation Guide
### 7.1 Blueprint Child Setup
1. Create Blueprint Class: Parent = `BP_PlanarCaptureActor`, Name = `BP_Mirror` (or `BP_Portal`, etc.)
2. Assign a plane/quad StaticMesh to `SurfaceMesh` in Components panel
3. Set `CaptureComponent.CaptureMode` in Class Defaults
4. Assign `SurfaceMPC` to `MPC_CaptureSurface`
5. Assign material to SurfaceMesh slot 0
### 7.2 Proximity Trigger Adjustments
- Resize `ProximityTrigger.BoxExtent` per surface (larger mirrors = larger trigger)
- The trigger boosts priority when player is near — adjust size for desired quality bump radius
### 7.3 Destruction Handling
```
Event OnSurfaceDestroyed
→ Play shatter sound via SS_AudioManager.PlaySoundAtLocation()
→ Spawn particle effect at actor location
→ (Optional) Notify BPC_ScareEventSystem for jump scare
→ (Optional) Set narrative flag via BPC_NarrativeStateSystem
```
## 8. Build Checklist
- [ ] C++ base class compiles
- [ ] Create BP child with correct mesh
- [ ] Assign material and MPC
- [ ] Configure CaptureComponent defaults
- [ ] Adjust proximity trigger size
- [ ] Test BeginPlay registration with manager
- [ ] Test Enable/Disable surface
- [ ] Test proximity overlap quality boost

View File

@@ -0,0 +1,108 @@
# 138 — Planar Capture Manager Subsystem (`SS_PlanarCaptureManager`)
## Purpose
Global budget manager for all planar capture surfaces in the world. One instance per World (World Subsystem). Scores every registered surface each frame and assigns quality tiers to stay within configurable budget limits. Owns the shared render target pool.
## Dependencies
- **Requires:** `BP_PlanarCaptureActor` (137) for surface registration, `BPC_PlanarCapture` (136) for tier assignment
- **Required By:** All capture surfaces in the world
- **Engine/Plugin Requirements:** WorldSubsystem (auto-created)
## Class Info
| Property | Value |
|----------|-------|
| **Parent Class** | `WorldSubsystem` (C++ `ASS_PlanarCaptureManager`) |
| **Class Type** | World Subsystem |
| **Asset Path** | N/A (auto-created by engine) |
| **C++ Header** | `Source/PG_Framework/Public/Capture/SS_PlanarCaptureManager.h` |
| **C++ Status** | ✅ Full Implementation |
| **BP Asset** | None — engine auto-creates |
## 1. Variables
### Configuration (Budget)
| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| `GlobalQualityCap` | EPlanarCaptureQualityTier | High | Max quality tier for any surface |
| `MaxHeroSurfaces` | int32 | 1 | Max simultaneous Hero-tier captures |
| `MaxHighSurfaces` | int32 | 3 | Max simultaneous High-tier captures |
| `MaxMediumSurfaces` | int32 | 6 | Max simultaneous Medium-tier captures |
| `MaxTotalRenderTargetMemoryMB` | float | 128.0 | Total RT memory budget |
| `MaxCaptureDistance` | float | 10000.0 | Distance at which surface goes Off |
| `FullEvaluationInterval` | float | 0.5 | Seconds between full re-evaluation |
## 2. Functions
#### `RegisterSurface(Surface: ABP_PlanarCaptureActor*)`
- **Description:** Register a surface with the manager. Called by BP_PlanarCaptureActor.BeginPlay.
- **Flow:** Check duplicates → Add to RegisteredSurfaces → Log → Broadcast OnSurfaceRegistered → EvaluateAllSurfaces
#### `UnregisterSurface(Surface: ABP_PlanarCaptureActor*)`
- **Description:** Remove a surface. Called on EndPlay.
- **Flow:** Remove from RegisteredSurfaces → Log → Broadcast OnSurfaceUnregistered
#### `RequestRenderTarget(Size: int32)` → `UTextureRenderTarget2D*`
- **Description:** Get a render target from the pool (or allocate new). Returns nullptr if pool exhausted.
- **Flow:** Check pool for matching size + not in use → If found, mark in use → If not, CreateRenderTarget
#### `ReleaseRenderTarget(RT: UTextureRenderTarget2D*)`
- **Description:** Return a render target to the pool. Marks as free for reuse.
#### `ForceAllSurfacesToTier(Tier: EPlanarCaptureQualityTier)`
- **Description:** Override all surfaces to a specific tier (e.g., Hero during a cutscene mirror moment).
#### `ReleaseForceTier()`
- **Description:** Remove force override, resume normal scoring.
#### `GetNearestSurfaceOfMode(Mode, Location, MaxDistance)` → `ABP_PlanarCaptureActor*`
- **Description:** Find nearest surface of a given mode (e.g., find nearest portal for teleport).
## 3. Event Dispatchers
| Dispatcher | Parameters | Description |
|------------|-----------|-------------|
| `OnSurfaceRegistered` | Surface, TotalSurfaces | Surface added |
| `OnSurfaceUnregistered` | Surface, TotalSurfaces | Surface removed |
| `OnGlobalQualityCapChanged` | NewCap | Quality cap changed |
## 4. Scoring Algorithm (Internal)
```
CompositeScore = (ScreenCoverage × 0.5) + (FacingAngle × 0.3) + (DistanceFactor × 0.1) + (ScriptedPriority × 0.1)
Tier: Score ≥ 0.8 → Hero | ≥ 0.5 → High | ≥ 0.2 → Medium | > 0 → Low | 0 → Off
Budget enforcement: demote if tier count exceeds Max*Surfaces limits
Apply GlobalQualityCap: clamp tier to cap
```
## 5. Communication Matrix
| Target System | Method | What |
|---------------|--------|------|
| `BP_PlanarCaptureActor` | Direct (registry) | Surface tracking |
| `BPC_PlanarCapture` | Direct (ApplyQualityTier) | Tier assignment |
| `UTextureRenderTarget2D` | Direct (create/release) | RT pool management |
| Player Camera Manager | UGameplayStatics (indirect via Capture) | View transform for scoring |
## 6. Manual Implementation Guide
*No Blueprint implementation needed — the C++ subsystem auto-creates per world.*
### 6.1 Budget Tuning
Adjust the following in `Project Settings → Plugins → PG_Framework → Planar Capture` (or via Config in DefaultEngine.ini):
- **High-end GPU (RTX 4080+):** MaxHeroSurfaces=2, MaxHighSurfaces=5
- **Mid-range (RTX 3060):** MaxHeroSurfaces=1, MaxHighSurfaces=3
- **Console (PS5/Xbox):** MaxHeroSurfaces=1, MaxHighSurfaces=2, GlobalQualityCap=High
- **Low-end (Steam Deck):** MaxHeroSurfaces=0, MaxHighSurfaces=1, GlobalQualityCap=Medium
### 6.2 Debug Commands
```
SS_PlanarCaptureManager.GetSurfaceCount() → Blueprint: print count
SS_PlanarCaptureManager.GetPoolMemoryUsageMB() → Blueprint: print memory
ForceAllSurfacesToTier(Hero) → test all at max quality
ReleaseForceTier() → resume normal scoring
```
## 7. Build Checklist
- [ ] C++ subsystem compiles
- [ ] Auto-creates per world (no manual creation needed)
- [ ] Budget limits tested with multiple surfaces
- [ ] RT pool reuses targets (not leaking)
- [ ] Force tier override works for cutscenes

View File

@@ -0,0 +1,110 @@
# 139 — Mirror Surface Actor (`BP_Mirror`)
## Purpose
Standard planar mirror surface. Designer configures mode, dirt layers, steam parameters, and surface aging. Extends `BP_PlanarCaptureActor` with default mirror configuration.
## Dependencies
- **Requires:** `BP_PlanarCaptureActor` (137), `BPC_PlanarCapture` (136)
- **Required By:** `BP_HorrorMirror` (142) — extends this for horror features
- **Engine/Plugin Requirements:** M_CaptureSurface_Master material, MPC_CaptureSurface
## Class Info
| Property | Value |
|----------|-------|
| **Parent Class** | `BP_PlanarCaptureActor` (C++ `ABP_PlanarCaptureActor`) |
| **Class Type** | Blueprint Actor |
| **Asset Path** | `Content/Framework/Capture/BP_Mirror.uasset` |
| **C++ Status** | 🔵 BP Spec Only — extends C++ parent |
| **BP Asset** | Create in editor: `BP_Mirror` |
## 1. Configuration (Class Defaults)
| Variable | Value | Description |
|----------|-------|-------------|
| `CaptureComponent.CaptureMode` | `Mirror` | Fixed to Mirror mode |
| `bStartEnabled` | `true` | Active by default |
| `bDestructible` | `false` | Can be shattered (override per instance) |
| `SurfaceMPC` | `MPC_CaptureSurface` | Assign the global MPC |
### Mirror-Specific Properties (Set via `SetSurfaceMPCParameter`)
| Parameter | Default | Range | Description |
|-----------|---------|-------|-------------|
| `DirtOpacity` | 0.0 | 0.01.0 | Dirt/scratch layer intensity |
| `SteamIntensity` | 0.0 | 0.01.0 | Steam fog visibility |
| `CondensationFlow` | 0.0 | 0.01.0 | Condensation rivulet normal intensity |
| `SurfaceAge` | 0.0 | 0.01.0 | Oxidation/yellowing tint |
## 2. Material Setup
| Slot | Material Instance | Description |
|------|------------------|-------------|
| SurfaceMesh[0] | `MI_Mirror_Clean` | Default clean mirror |
Pre-configured material instances to assign per mirror:
- `MI_Mirror_Clean` — Pristine mirror, no effects
- `MI_Mirror_Dirty` — DirtOpacity preset at 0.4
- `MI_Mirror_Steam` — SteamIntensity preset at 0.6, animated noise enabled
## 3. Event Graph
### Event BeginPlay
```
Event BeginPlay
├─ Parent: BeginPlay (registers with manager)
├─ Set CaptureComponent.CaptureMode = Mirror
├─ Set SurfaceMaterial(MI_Mirror_Clean) // or designer-chosen MI
└─ [If bStartEnabled] EnableSurface()
```
### Event: SetMirrorDirtLevel(Level: float)
```
SetMirrorDirtLevel(Level)
├─ Clamp Level to 0.01.0
├─ Call SetSurfaceMPCParameter("DirtOpacity", Level)
└─ [If Level > threshold] Swap material to MI_Mirror_Dirty
```
### Event: SetMirrorSteamLevel(Level: float)
```
SetMirrorSteamLevel(Level)
├─ Clamp Level to 0.01.0
├─ Call SetSurfaceMPCParameter("SteamIntensity", Level)
└─ Call SetSurfaceMPCParameter("CondensationFlow", Level * 0.5)
```
## 4. Communication Matrix
| Target | Method | What |
|--------|--------|------|
| `SS_PlanarCaptureManager` | Direct (inherited) | Registration |
| `BPC_PlanarCapture` | Direct (inherited) | Capture driving |
| `MPC_CaptureSurface` | SetScalarParameterValue (via PushMPCParameters) | Visual parameters |
| `SS_AudioManager` (132) | Direct (on shatter) | Shatter sound |
## 5. Manual Implementation Guide
### 5.1 Create BP_Mirror
1. Create Blueprint Class: Parent = `BP_PlanarCaptureActor`, Name = `BP_Mirror`
2. Open Class Defaults, set `CaptureComponent.CaptureMode` to `Mirror`
3. In Components: select `SurfaceMesh`, assign a plane mesh (e.g., `SM_Plane_200x200`)
4. Assign `MI_Mirror_Clean` to SurfaceMesh material slot 0
5. Set `SurfaceMPC` to `MPC_CaptureSurface`
### 5.2 Add Steam/Dirt Controls
1. In Event Graph, create custom event `SetMirrorDirtLevel(Float)`
2. Wire: `SetSurfaceMPCParameter("DirtOpacity", Level)`
3. Create custom event `SetMirrorSteamLevel(Float)`
4. Wire: `SetSurfaceMPCParameter("SteamIntensity", Level)` + `SetSurfaceMPCParameter("CondensationFlow", Level * 0.5)`
### 5.3 Level Placement
1. Drag `BP_Mirror` into level
2. Rotate so surface normal faces toward player viewing area
3. Set `SurfaceDisplayName` for debug identification
4. Adjust `ProximityTrigger.BoxExtent` to cover expected viewing area
## 6. Build Checklist
- [ ] Create BP_Mirror Blueprint child
- [ ] Assign plane mesh and MI_Mirror_Clean material
- [ ] Set CaptureMode=Mirror in defaults
- [ ] Assign MPC_CaptureSurface reference
- [ ] Test: place in level, walk up, verify reflection appears
- [ ] Test: walk away, verify quality drops to Off
- [ ] Test: call SetMirrorDirtLevel/SetMirrorSteamLevel from gameplay code

View File

@@ -0,0 +1,124 @@
# 140 — Portal Surface Actor (`BP_Portal`)
## Purpose
Portal surface with linked target. Renders the view from another location in the world through a planar surface. Supports one-way vs two-way rendering, teleport on overlap, and clip plane for flush geometry placement.
## Dependencies
- **Requires:** `BP_PlanarCaptureActor` (137), `BPC_PlanarCapture` (136), `BPC_StateManager` (130) for teleport gating
- **Required By:** Narrative sequences, level transitions, horror portal variants
- **Engine/Plugin Requirements:** Oblique clip plane requires Renderer module (C++)
## Class Info
| Property | Value |
|----------|-------|
| **Parent Class** | `BP_PlanarCaptureActor` (C++ `ABP_PlanarCaptureActor`) |
| **Class Type** | Blueprint Actor |
| **Asset Path** | `Content/Framework/Capture/BP_Portal.uasset` |
| **C++ Status** | 🔵 BP Spec Only |
| **BP Asset** | Create in editor: `BP_Portal` |
## 1. Configuration (Class Defaults)
| Variable | Value | Description |
|----------|-------|-------------|
| `CaptureComponent.CaptureMode` | `Portal` | Fixed to Portal mode |
| `CaptureComponent.LinkedTargetSurface` | (Set per instance) | Destination portal actor |
| `bStartEnabled` | `true` | Active by default |
| `SurfaceMPC` | `MPC_CaptureSurface` | Global MPC |
### Portal-Specific Properties (Custom Variables — add to BP)
| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| `bTeleportOnOverlap` | bool | true | Teleport player when they enter the portal volume |
| `bOneWay` | bool | true | True = only source→target; false = bidirectional |
| `TeleportTrigger` | BoxComponent | — | Overlap volume for teleport (separate from ProximityTrigger) |
## 2. Material Setup
| Slot | Material | Description |
|------|----------|-------------|
| SurfaceMesh[0] | `MI_Portal_Standard` | Portal surface with edge fade |
| Frame (optional) | Designer mesh + material | Portal frame decoration |
## 3. Event Graph
### Event BeginPlay
```
Event BeginPlay
├─ Parent: BeginPlay (registers with manager)
├─ Set CaptureComponent.CaptureMode = Portal
├─ Validate CaptureComponent.LinkedTargetSurface != nullptr
│ └─ If null → Log Warning: "BP_Portal missing LinkedTargetSurface!"
├─ Bind TeleportTrigger.OnComponentBeginOverlap → OnPortalOverlap
└─ EnableSurface()
```
### Event: OnPortalOverlap(OtherActor, OtherComp, ...)
```
OnPortalOverlap(OtherActor)
├─ Cast OtherActor to Player Pawn
├─ [If bTeleportOnOverlap and HasAuthority]
│ ├─ Query BPC_StateManager.IsActionPermitted(Framework.Action.Teleport)
│ │ └─ If denied → return (play denied feedback)
│ ├─ Get LinkedTargetSurface actor transform
│ ├─ Compute exit location: TargetTransform + offset
│ ├─ Teleport player: SetActorLocation + SetActorRotation
│ └─ Play portal travel SFX via SS_AudioManager
└─ [If client] Call Server_TeleportThroughPortal RPC
```
### Server RPC: Server_TeleportThroughPortal
```
Server_TeleportThroughPortal (Server, Reliable)
├─ Validate HasAuthority
├─ Validate portal still active
├─ Validate LinkedTargetSurface still valid
├─ Teleport player (same as OnPortalOverlap logic)
└─ Multicast_OnPlayerTeleported to notify all clients
```
## 4. Communication Matrix
| Target | Method | What |
|--------|--------|------|
| `BPC_StateManager` (130) | `IsActionPermitted()` | Teleport gating |
| `SS_AudioManager` (132) | Direct | Portal whoosh/disappear SFX |
| `SS_EnhancedInputManager` (128) | Direct (optional) | Context switch during portal transition |
| `BPC_CameraStateLayer` (14) | Direct (optional) | Camera FOV transition during teleport |
## 5. Manual Implementation Guide
### 5.1 Create BP_Portal
1. Create Blueprint Class: Parent = `BP_PlanarCaptureActor`, Name = `BP_Portal`
2. In Components: add `BoxComponent` named `TeleportTrigger`
3. Size `TeleportTrigger` slightly larger than surface mesh (50-100 units deep)
4. Set `TeleportTrigger.CollisionEnabled = QueryOnly`, response to Pawn = Overlap
5. Set `CaptureComponent.CaptureMode = Portal` in Class Defaults
6. Assign `MI_Portal_Standard` to SurfaceMesh
### 5.2 Portal Link Setup
1. Place `BP_Portal_Source` and `BP_Portal_Target` in level
2. On Source: set `CaptureComponent.LinkedTargetSurface` → Target actor
3. On Target: set `CaptureComponent.LinkedTargetSurface` → Source actor (if two-way)
4. Position surfaces facing each other's expected viewing directions
### 5.3 Teleport Implementation
```
Create custom event OnPortalOverlap (bind to TeleportTrigger)
→ Switch HasAuthority
Authority:
→ Get LinkedTargetSurface → Get Actor Transform
→ Teleport: Set Actor Location (target location + forward * 200)
→ Set Actor Rotation (target rotation)
→ Play Sound 2D (portal whoosh cue via SS_AudioManager)
Remote:
→ Call Server_TeleportThroughPortal (RPC)
```
## 6. Build Checklist
- [ ] Create BP_Portal with TeleportTrigger component
- [ ] Set CaptureMode=Portal
- [ ] Assign MI_Portal_Standard material
- [ ] Implement overlap teleport logic with HasAuthority gate
- [ ] Add Server_TeleportThroughPortal RPC
- [ ] Test one-way portal: source renders target view
- [ ] Test teleport: player overlaps and appears at target
- [ ] Test with BPC_StateManager gating (block teleport during certain states)

View File

@@ -0,0 +1,129 @@
# 141 — Monitor Surface Actor (`BP_Monitor`)
## Purpose
Security screen, TV, or diegetic display monitor. Uses a fixed camera actor reference instead of dynamic mirror/portal math. Runs at low FPS by default (5fps) with scanline and static noise effects.
## Dependencies
- **Requires:** `BP_PlanarCaptureActor` (137), `BPC_PlanarCapture` (136)
- **Required By:** `BPC_DiegeticDisplay` (18) — can display diegetic HUD content
- **Engine/Plugin Requirements:** None additional
## Class Info
| Property | Value |
|----------|-------|
| **Parent Class** | `BP_PlanarCaptureActor` (C++ `ABP_PlanarCaptureActor`) |
| **Class Type** | Blueprint Actor |
| **Asset Path** | `Content/Framework/Capture/BP_Monitor.uasset` |
| **C++ Status** | 🔵 BP Spec Only |
| **BP Asset** | Create in editor: `BP_Monitor` |
## 1. Configuration (Class Defaults)
| Variable | Value | Description |
|----------|-------|-------------|
| `CaptureComponent.CaptureMode` | `Monitor` | Fixed to Monitor mode |
| `CaptureComponent.CaptureFOV` | `70.0` | Narrower FOV for security camera feel |
| `CaptureComponent.QualityProfiles[0].CaptureInterval` | `0.2` | 5fps Low quality (override) |
| `SurfaceMPC` | `MPC_CaptureSurface` | Global MPC |
### Monitor-Specific Properties (Add to BP)
| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| `bPoweredOn` | bool | true | On/off state |
| `bShowScanlines` | bool | false | CRT scanline overlay |
| `StaticNoiseIntensity` | float | 0.0 | Static/noise overlay (0.01.0) |
| `FlickerCurve` | UCurveFloat | — | On/off flicker timing curve |
| `PoweredOffMaterial` | UMaterialInterface | — | Material shown when off (black screen, cracked) |
## 2. Material Setup
| Slot | Material | Description |
|------|----------|-------------|
| SurfaceMesh[0] | `MI_Monitor_Security` | Security screen with scanline support |
## 3. Event Graph
### Event BeginPlay
```
Event BeginPlay
├─ Parent: BeginPlay
├─ Set CaptureComponent.CaptureMode = Monitor
├─ Set CaptureComponent.CaptureFOV = 70.0
├─ [If bPoweredOn] EnableSurface
└─ [Else] SetSurfaceMaterial(PoweredOffMaterial)
```
### Event: PowerOn
```
PowerOn()
├─ Set bPoweredOn = true
├─ SetSurfaceMaterial(MI_Monitor_Security)
├─ EnableSurface()
└─ [If FlickerCurve valid] StartFlickerTimeline
```
### Event: PowerOff
```
PowerOff()
├─ Set bPoweredOn = false
├─ DisableSurface()
├─ SetSurfaceMaterial(PoweredOffMaterial)
└─ StopFlickerTimeline
```
### Event: SetStaticNoise(Intensity: float)
```
SetStaticNoise(Intensity)
├─ Clamp Intensity 0.01.0
├─ Set StaticNoiseIntensity = Intensity
└─ SetSurfaceMPCParameter("StaticNoiseIntensity", Intensity)
```
## 4. Flicker Timeline Setup
If `FlickerCurve` is assigned, create a Timeline that drives:
```
Timeline: FlickerTimeline
Curve: FlickerCurve (Float Track)
On Update:
├─ Read curve value → bIsFlickerOn
├─ If bIsFlickerOn and not bPoweredOn → PowerOn (brief)
└─ If not bIsFlickerOn and bPoweredOn → PowerOff (brief)
```
## 5. Communication Matrix
| Target | Method | What |
|--------|--------|------|
| `BPC_DiegeticDisplay` (18) | Interface (I_DiegeticDisplay) | Can display diegetic HUD content as secondary output |
| `SS_AudioManager` (132) | Direct | Monitor static/buzz/hum SFX |
| `BPC_ScareEventSystem` (101) | Dispatcher | Monitor flicker/horror image scare |
## 6. Manual Implementation Guide
### 6.1 Create BP_Monitor
1. Create Blueprint Class: Parent = `BP_PlanarCaptureActor`, Name = `BP_Monitor`
2. Set `CaptureComponent.CaptureMode = Monitor` in defaults
3. Set `CaptureComponent.CaptureFOV = 70.0`
4. Override QualityProfiles[0].CaptureInterval to 0.2 (5fps Low)
5. Assign `MI_Monitor_Security` to SurfaceMesh
6. Create `PoweredOffMaterial` — simple dark/black emissive material
### 6.2 Camera Placement
1. Create a `CameraActor` or `SceneCaptureCamera` (BP child of CameraActor) in the level
2. Position it where the monitor should "look from"
3. In BP_Monitor instance: set `CaptureComponent.FixedCameraActor` → your camera actor
### 6.3 Power Control
For narrative-driven power control:
```
External system calls: BP_Monitor → PowerOn() / PowerOff()
Trigger: Narrative flag set → Branch → PowerOn or PowerOff
```
## 7. Build Checklist
- [ ] Create BP_Monitor Blueprint child
- [ ] Assign MI_Monitor_Security material
- [ ] Create PoweredOffMaterial (dark screen)
- [ ] Place camera actor and assign FixedCameraActor
- [ ] Test PowerOn/PowerOff cycle
- [ ] Test flicker curve timeline
- [ ] Test static noise parameter
- [ ] Test: place multiple monitors, verify quality budget works

View File

@@ -0,0 +1,162 @@
# 142 — Horror Mirror Actor (`BP_HorrorMirror`)
## Purpose
Horror mirror extending `BP_Mirror` with wrong-reflection Metahuman, delayed frame ring buffer, steam text reveal, mirror darkness, UV distortion, and coordinated scare events.
## Dependencies
- **Requires:** `BP_Mirror` (139), `BP_PlanarCaptureActor` (137), `BPC_PlanarCapture` (136)
- **Requires (Horror Integration):** `BPC_ScareEventSystem` (101), `SS_AudioManager` (132), `BPC_StressSystem` (10)
- **Engine/Plugin Requirements:** M_CaptureSurface_Master material (horror layers)
## Class Info
| Property | Value |
|----------|-------|
| **Parent Class** | `BP_Mirror` (child of `BP_PlanarCaptureActor`) |
| **Class Type** | Blueprint Actor |
| **Asset Path** | `Content/Framework/Capture/BP_HorrorMirror.uasset` |
| **C++ Status** | 🔵 BP Spec Only — uses C++ horror API (ActivateHorrorReflection, PushDelayedFrame) |
| **BP Asset** | Create in editor: `BP_HorrorMirror` |
## 1. Configuration
| Variable | Value | Description |
|----------|-------|-------------|
| `CaptureComponent.CaptureMode` | `HorrorMirror` | Fixed to HorrorMirror mode |
| `CaptureComponent.WrongReflectionActor` | (Set per instance) | Metahuman/ghost actor for wrong reflection |
| `CaptureComponent.QualityProfiles[3].DelayedFrameCount` | `5` | Hero tier gets 5-frame delay |
### Horror-Specific Properties (Add to BP)
| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| `WrongReflectionBlendCurve` | UCurveFloat | — | 0→1→0 blend curve for wrong reflection event |
| `MirrorDarknessCurve` | UCurveFloat | — | 0→1 darkness ramp curve |
| `UVDistortionCurve` | UCurveFloat | — | Distortion amplitude over time |
| `SteamTextRevealTexture` | UTexture2D | — | Mask texture for "HELP ME" text in steam |
| `ScareEventTag` | FGameplayTag | — | Tag identifying this scare in BPC_ScareEventSystem |
| `HorrorAudioCue` | USoundBase | — | Audio cue for horror event (played via SS_AudioManager) |
| `ScareDuration` | float | 5.0 | Total duration of the scare event |
## 2. Material Setup
| Slot | Material | Description |
|------|----------|-------------|
| SurfaceMesh[0] | `MI_Mirror_Horror` | Horror mirror with wrong reflection and darkness layers enabled |
## 3. Event Graph
### Event BeginPlay
```
Event BeginPlay
├─ Parent: BeginPlay (from BP_Mirror)
├─ Set CaptureComponent.CaptureMode = HorrorMirror
├─ Validate CaptureComponent.WrongReflectionActor != nullptr
│ └─ If null → Log Warning: "BP_HorrorMirror missing WrongReflectionActor!"
└─ EnableSurface()
```
### Core Event: TriggerHorrorScare()
```
TriggerHorrorScare()
├─ [Check] BPC_StateManager.IsActionPermitted(Scare.Tag) → if denied, return
├─ [Notify] BPC_ScareEventSystem.TriggerScareEvent(ScareEventTag)
│ └─ This coordinates with other systems (lights, audio, pacing)
├─ [Audio] SS_AudioManager.PlaySoundAtLocation(HorrorAudioCue, GetActorLocation())
├─ [Reflection Swap] CaptureComponent.ActivateHorrorReflection()
│ └─ C++ swaps ShowOnly list to WrongReflectionActor
├─ [Start Timeline] Play HorrorScareTimeline
│ └─ Timeline drives: WrongReflectionBlend, MirrorDarkness, UVDistortion, TextReveal
└─ [After ScareDuration] Call FinalizeHorrorScare()
```
### Timeline: HorrorScareTimeline
```
HorrorScareTimeline (Float Track, Length = ScareDuration)
Track 0: WrongReflectionBlend
Curve: WrongReflectionBlendCurve (0→1→0)
→ SetSurfaceMPCParameter("WrongReflectionBlend", curve value)
Track 1: MirrorDarkness
Curve: MirrorDarknessCurve (0→0.8→0.2 linger)
→ SetSurfaceMPCParameter("MirrorDarkness", curve value)
Track 2: UVDistortion
Curve: UVDistortionCurve (0→0.3 breath cycle)
→ SetSurfaceMPCParameter("DistortionAmplitude", curve value)
Track 3: TextReveal
Curve: 0→1 after 1.5s delay
→ SetSurfaceMPCParameter("TextRevealProgress", curve value)
```
### Event: FinalizeHorrorScare()
```
FinalizeHorrorScare()
├─ CaptureComponent.DeactivateHorrorReflection()
│ └─ C++ restores original ShowOnly list
├─ SetSurfaceMPCParameter("WrongReflectionBlend", 0.0)
├─ SetSurfaceMPCParameter("MirrorDarkness", 0.0)
├─ SetSurfaceMPCParameter("DistortionAmplitude", 0.0)
├─ SetSurfaceMPCParameter("TextRevealProgress", 0.0)
└─ [Notify] BPC_ScareEventSystem.OnScareEventComplete(ScareEventTag)
```
## 4. Communication Matrix
| Target | Method | What |
|--------|--------|------|
| `BPC_ScareEventSystem` (101) | Direct (TriggerScareEvent) | Coordinated scare |
| `SS_AudioManager` (132) | Direct | Horror SFX |
| `BPC_StressSystem` (10) | Dispatcher (optional) | Add stress on scare |
| `BPC_StateManager` (130) | IsActionPermitted() | Gate before triggering scare |
| `BPC_LightEventController` (96) | Dispatcher (optional) | Sync lights with mirror scare |
| `BPC_PacingDirector` (98) | Dispatcher (optional) | Notify of scare for pacing |
## 5. Manual Implementation Guide
### 5.1 Create BP_HorrorMirror
1. Create Blueprint Class: Parent = `BP_Mirror`, Name = `BP_HorrorMirror`
2. Set `CaptureComponent.CaptureMode = HorrorMirror` in defaults
3. Assign `MI_Mirror_Horror` to SurfaceMesh
4. Set `CaptureComponent.QualityProfiles[3].DelayedFrameCount = 5`
### 5.2 Setup Wrong Reflection Actor
1. Place a skeletal mesh actor (Metahuman, ghost mesh) in a hidden room/box near the mirror
2. Set its visibility to false in BeginPlay
3. In BP_HorrorMirror instance: set `CaptureComponent.WrongReflectionActor` → your hidden actor
### 5.3 Create Curves
Create Float Curve assets:
- `Curve_WrongReflectionBlend`: Keys: (0,0), (1.0,1.0), (3.0,1.0), (4.0,0), (5.0,0)
- `Curve_MirrorDarkness`: Keys: (0,0), (0.5,0.8), (2.0,0.6), (4.0,0.3), (5.0,0)
- `Curve_UVDistortion`: Keys: (0,0), (1.0,0.3), (2.0,0.2), (3.0,0.35), (5.0,0)
### 5.4 Build Timeline
1. Create Timeline node with Float Track
2. Add 4 float output tracks
3. Wire each track to `SetSurfaceMPCParameter` with corresponding param name
4. Set Timeline length to `ScareDuration`
### 5.5 Integration Hook
From any gameplay system (narrative trigger, AI event, proximity):
```
BP_HorrorMirror → TriggerHorrorScare()
```
From Sequencer:
```
Event Track → BP_HorrorMirror → TriggerHorrorScare()
```
## 6. Build Checklist
- [ ] Create BP_HorrorMirror Blueprint child
- [ ] Place WrongReflectionActor in level (hidden)
- [ ] Create all 3 Float Curves
- [ ] Build HorrorScareTimeline with 4 tracks
- [ ] Wire MPC parameter sets
- [ ] Wire BPC_ScareEventSystem integration
- [ ] Wire SS_AudioManager audio cue
- [ ] Test TriggerHorrorScare event
- [ ] Verify wrong reflection appears and fades
- [ ] Verify MPC params return to zero after scare

View File

@@ -0,0 +1,109 @@
# 143 — Fake Window Actor (`BP_FakeWindow`)
## Purpose
Architectural fake window using planar capture to simulate an outdoor view or adjacent room. Supports parallax depth, sky environment reference, weather overlay, and sublevel visibility.
## Dependencies
- **Requires:** `BP_PlanarCaptureActor` (137), `BPC_PlanarCapture` (136)
- **Engine/Plugin Requirements:** Level Streaming (for sublevel reference)
## Class Info
| Property | Value |
|----------|-------|
| **Parent Class** | `BP_PlanarCaptureActor` (C++ `ABP_PlanarCaptureActor`) |
| **Class Type** | Blueprint Actor |
| **Asset Path** | `Content/Framework/Capture/BP_FakeWindow.uasset` |
| **C++ Status** | 🔵 BP Spec Only |
| **BP Asset** | Create in editor: `BP_FakeWindow` |
## 1. Configuration
| Variable | Value | Description |
|----------|-------|-------------|
| `CaptureComponent.CaptureMode` | `FakeWindow` | Fixed to FakeWindow mode |
| `CaptureComponent.CaptureFOV` | `100.0` | Wider FOV for window view |
### FakeWindow-Specific Properties (Add to BP)
| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| `LinkedRoomSublevel` | TSoftObjectPtr〈UWorld〉 | — | Sublevel containing the room to render |
| `SkyReference` | AActor* | — | Sky/directional light to include in capture |
| `ParallaxDepthScalar` | float | 1.0 | Depth exaggeration for parallax effect |
| `WeatherOverlayType` | EWeatherType | None | Rain/Frost overlay driven by game state |
| `bStreamSublevelOnProximity` | bool | true | Load/unload sublevel based on player distance |
| `StreamInDistance` | float | 3000.0 | Distance to load sublevel |
## 2. Material Setup
| Slot | Material | Description |
|------|----------|-------------|
| SurfaceMesh[0] | `MI_FakeWindow_Interior` | Window with parallax and weather overlay support |
## 3. Event Graph
### Event BeginPlay
```
Event BeginPlay
├─ Parent: BeginPlay
├─ Set CaptureComponent.CaptureMode = FakeWindow
├─ [If bStreamSublevelOnProximity] Start distance check timer
└─ EnableSurface()
```
### Timer: CheckPlayerDistance
```
CheckPlayerDistance (every 2 seconds)
├─ Get Player Pawn location
├─ Distance = VectorDist(Player, GetActorLocation())
├─ If Distance < StreamInDistance AND sublevel not loaded
│ └─ Load Stream Level (LinkedRoomSublevel)
└─ If Distance > StreamInDistance + 1000 AND sublevel loaded
└─ Unload Stream Level (LinkedRoomSublevel)
```
### Event: SetWeatherOverlay(Weather: EWeatherType)
```
SetWeatherOverlay(Weather)
├─ Set WeatherOverlayType = Weather
├─ Switch on Weather:
│ None: SetSurfaceMPCParameter("RainIntensity", 0.0)
│ SetSurfaceMPCParameter("FrostIntensity", 0.0)
│ Rain: SetSurfaceMPCParameter("RainIntensity", 1.0)
│ Frost: SetSurfaceMPCParameter("FrostIntensity", 1.0)
└─ Trigger material update
```
## 4. Communication Matrix
| Target | Method | What |
|--------|--------|------|
| Level Streaming | `Load Stream Level` / `Unload Stream Level` | Sublevel management |
| `BPC_AtmosphereStateController` (94) | Dispatcher | React to environment state changes |
| `GS_CoreGameState` (6) | Direct (read) | Current chapter/phase for weather state |
## 5. Manual Implementation Guide
### 5.1 Create BP_FakeWindow
1. Create Blueprint Class: Parent = `BP_PlanarCaptureActor`, Name = `BP_FakeWindow`
2. Set `CaptureComponent.CaptureMode = FakeWindow`
3. Set `CaptureComponent.CaptureFOV = 100.0`
4. Assign `MI_FakeWindow_Interior` to SurfaceMesh
### 5.2 Setup the View Room
1. Create a separate sublevel with the room/exterior you want to show through the window
2. Add a `SceneCaptureCamera` actor in the sublevel positioned to capture the desired view
3. In BP_FakeWindow instance: assign `CaptureComponent.FixedCameraActor` → the camera in the sublevel
4. Assign `LinkedRoomSublevel` → the sublevel asset
### 5.3 Performance Considerations
- Fake windows should run at Low or Medium tier by default
- Sublevel streaming avoids rendering room geometry when player is far away
- Consider using a static cubemap fallback at Low quality instead of live capture
## 6. Build Checklist
- [ ] Create BP_FakeWindow Blueprint child
- [ ] Create sublevel with view room
- [ ] Place SceneCaptureCamera in sublevel
- [ ] Configure LinkedRoomSublevel and FixedCameraActor
- [ ] Create stream distance timer
- [ ] Set quality profiles for Low default tier
- [ ] Test sublevel streams in/out based on distance
- [ ] Test weather overlay switching

View File

@@ -0,0 +1,156 @@
# 144 — Capture Surface Master Material (`M_CaptureSurface_Master`)
## Purpose
Single master material for ALL capture surface modes (mirror, portal, monitor, horror, fake window). All features are parameter-driven — inactive features have zero rendering cost.
## Dependencies
- **Requires:** `MPC_CaptureSurface` (145) for global scalar parameters
- **Required By:** All capture surface actors (139-143) via their material instances
- **Engine/Plugin Requirements:** None
## Class Info
| Property | Value |
|----------|-------|
| **Material Domain** | Surface |
| **Blend Mode** | Opaque |
| **Shading Model** | Unlit |
| **Asset Path** | `Content/Framework/Capture/M_CaptureSurface_Master.uasset` |
| **C++ Status** | N/A (Material asset) |
| **Asset to Create** | Material in UE5 editor |
## 1. Material Layer Stack (9 Layers)
### Layer 0: Render Target Sample
```
Texture Sample (parameter: "CaptureTexture", TextureRenderTarget2D)
├─ UVs: If Mirror mode → UV * (1, -1) + (0, 1) [flip vertically for mirror reflection]
│ If Portal/Monitor mode → straight UVs
└─ Output → Base Color input of Layer 1
```
**Switch:** `StaticSwitchParameter: bIsMirror` (true = UV flip, false = straight)
### Layer 1: Condensation UV Distortion
```
Condensation Normal Map (Texture Sample, parameter: "CondensationNormal")
├─ UVs: Panner (slow drift, driven by Time * CondensationFlow MPC param)
├─ Normal strength: DistortionAmplitude MPC param
└─ Output: Modified UVs for Layer 0's texture sample
```
**Note:** Layer 1 modifies the UVs of Layer 0, not its color.
### Layer 2: Fresnel Edge Fade
```
Fresnel node (Exponent = 2.0, BaseReflectFraction = 0.0)
├─ Dot product: CameraVector · VertexNormal
└─ Output: Opacity mask for edge darkening (subtle vignette)
```
### Layer 3: Dirt / Scratch Multiply
```
Dirt Mask (Texture Sample, parameter: "DirtMask")
├─ Multiply with DirtOpacity MPC param
├─ Lerp: Clean RT ←→ Dirty RT using DirtOpacity
└─ Tint: Mix with SurfaceAge MPC param (yellowing/oxidation)
```
### Layer 4: Steam / Fog Lerp
```
Animated Noise (Procedural noise, tiling, scrolling via Time)
├─ SteamIntensity MPC param → controls noise opacity
├─ Lerp: Clear view ←→ Fogged view
└─ Output: blended base color
```
### Layer 5: Steam Emissive Glow
```
Steam mask (same noise as Layer 4, separate brightness)
├─ Multiply by SteamEmissiveIntensity MPC param
├─ Color: Soft warm white (backlit fog look)
└─ Output → Emissive Color pin
```
### Layer 6: Text Reveal Mask
```
Text Mask (Texture Sample, parameter: "TextRevealMask")
├─ Reveal progress: TextRevealProgress MPC param (0→1 wipe)
├─ Blend with steam carrier (appears as text IN the steam)
└─ Output: emissive text overlay (optional) or color replacement
```
### Layer 7: Mirror Darkness Multiply
```
MirrorDarkness MPC param (0.0 = normal, 1.0 = black)
├─ Multiply base color by (1.0 - MirrorDarkness)
└─ Output: darkened reflection
```
### Layer 8: Wrong Reflection Crossfade
```
Second RT Input (parameter: "DelayedCaptureTexture" OR separate RT)
├─ Lerp: Current_RT ←→ Delayed/Wrong_RT using WrongReflectionBlend MPC param
└─ Final Output → Emissive Color (Unlit material)
```
## 2. Material Parameters (Exposed)
### Texture Parameters
| Name | Type | Default | Description |
|------|------|---------|-------------|
| `CaptureTexture` | TextureRenderTarget2D | — | Live capture render target |
| `CondensationNormal` | Texture2D | T_DefaultNormal | Condensation flow normal map |
| `DirtMask` | Texture2D | T_DefaultWhite | Dirt/scratch mask texture |
| `TextRevealMask` | Texture2D | T_DefaultBlack | Steam text mask |
### Scalar Parameters (Driven by MPC)
| Name | Default | Description |
|------|---------|-------------|
| `SteamIntensity` | 0.0 | Steam fog opacity |
| `DirtOpacity` | 0.0 | Dirt/scratch opacity |
| `CondensationFlow` | 0.0 | Condensation normal scroll speed |
| `DistortionAmplitude` | 0.0 | UV distortion magnitude |
| `MirrorDarkness` | 0.0 | Mirror darkening |
| `WrongReflectionBlend` | 0.0 | Wrong reflection crossfade |
| `TextRevealProgress` | 0.0 | Steam text reveal progress |
| `SteamEmissiveIntensity` | 0.0 | Steam glow brightness |
| `DelayedReflectionBlend` | 0.0 | Delayed frame blend |
| `SurfaceAge` | 0.0 | Oxidation/yellowing tint |
### Static Switch Parameters
| Name | Default | Description |
|------|---------|-------------|
| `bIsMirror` | true | Enable vertical UV flip for mirror mode |
| `bEnableHorrorLayers` | false | Enable Layers 6-8 (text reveal, darkness, wrong reflection) |
## 3. MPC Binding
All 10 scalar parameters are NOT material-instance parameters — they are driven by `MPC_CaptureSurface` (145) at runtime. The C++ component calls `PushMPCParameters()` each frame to update these values globally.
In the material: use `Collection Parameter` nodes referencing `MPC_CaptureSurface` for each of the 10 scalars listed above.
## 4. Manual Implementation Guide
### 4.1 Create Master Material
1. Create Material: Name = `M_CaptureSurface_Master`
2. Set Material Domain = Surface, Blend Mode = Opaque, Shading Model = Unlit
3. Build Layer 0: `Texture Sample Parameter` node named "CaptureTexture"
4. Add Static Switch: "bIsMirror" → UV flip branch (Custom UV × (1,-1) + (0,1))
5. Build Layers 1-8 as described above
6. Connect final color → Emissive Color (Unlit output)
### 4.2 MPC Integration
1. Create `Collection Parameter` nodes for each of the 10 MPC scalars
2. Set the Collection asset to `MPC_CaptureSurface`
3. Set the Parameter Name to match each MPC entry (e.g., "SteamIntensity")
### 4.3 Performance
- Use `StaticSwitchParameter` for `bEnableHorrorLayers` — when false, Layers 6-8 are compiled out (zero cost)
- Condensation normal Layer 1 is cheap (one texture sample + panner)
- All MPC reads are free (constant buffer lookup)
## 5. Build Checklist
- [ ] Create M_CaptureSurface_Master material in UE5 editor
- [ ] Set Domain=Surface, Blend=Opaque, Shading=Unlit
- [ ] Build all 9 layers (verify material compiles)
- [ ] Add 10 MPC Collection Parameter nodes
- [ ] Add bIsMirror and bEnableHorrorLayers static switches
- [ ] Compile material — no errors
- [ ] Create MI instances and verify parameter override works

View File

@@ -0,0 +1,72 @@
# 145 — Capture Surface Material Parameter Collection (`MPC_CaptureSurface`)
## Purpose
Global Material Parameter Collection with 10 scalar parameters that control all capture surface material effects at runtime. Pushed each frame by `UBPC_PlanarCapture::PushMPCParameters()`.
## Dependencies
- **Requires:** None (standalone MPC asset)
- **Required By:** `M_CaptureSurface_Master` (144), all capture surface actors (139-143)
- **Engine/Plugin Requirements:** None
## Class Info
| Property | Value |
|----------|-------|
| **Asset Type** | MaterialParameterCollection |
| **Asset Path** | `Content/Framework/Capture/MPC_CaptureSurface.uasset` |
| **C++ Status** | N/A (content asset) |
| **Asset to Create** | MPC in UE5 editor |
## 1. Scalar Parameters
| Parameter Name | Default Value | Range | Description |
|---------------|---------------|-------|-------------|
| `SteamIntensity` | 0.0 | 0.01.0 | Steam/fog opacity on mirror surface |
| `DirtOpacity` | 0.0 | 0.01.0 | Dirt/scratch layer opacity |
| `CondensationFlow` | 0.0 | 0.02.0 | Condensation normal map panning speed |
| `DistortionAmplitude` | 0.0 | 0.01.0 | UV distortion magnitude (breathing mirror) |
| `MirrorDarkness` | 0.0 | 0.01.0 | Mirror darkening (0=normal, 1=black) |
| `WrongReflectionBlend` | 0.0 | 0.01.0 | Wrong reflection crossfade (horror mode) |
| `TextRevealProgress` | 0.0 | 0.01.0 | Steam text reveal wipe progress |
| `SteamEmissiveIntensity` | 0.0 | 0.05.0 | Backlit fog emissive brightness |
| `DelayedReflectionBlend` | 0.0 | 0.01.0 | Delayed frame ring buffer blend |
| `SurfaceAge` | 0.0 | 0.01.0 | Oxidation / yellowing tint amount |
## 2. Vector Parameters (Optional — Legendary Tier)
| Parameter Name | Default Value | Description |
|---------------|---------------|-------------|
| `SurfaceTintColor` | (1.0, 1.0, 1.0, 1.0) | Oxidation/aging color tint |
| `SteamColor` | (0.8, 0.85, 0.9, 1.0) | Steam emissive color |
## 3. Runtime Control
All parameters are driven by C++ via `UBPC_PlanarCapture::PushMPCParameters()`. Blueprint actors call `SetSurfaceMPCParameter(Name, Value)` on the parent `BP_PlanarCaptureActor` to override specific values for that surface.
### Per-Surface Override Pattern
```
BP_HorrorMirror → SetSurfaceMPCParameter("WrongReflectionBlend", 1.0)
└─ This sets the scalar on the surface's MID, which overrides the MPC value
(MID overrides take priority over MPC in UE5 material system)
```
### Global Override Pattern
```
SS_PlanarCaptureManager → all surfaces get MPC pushed each frame
└─ A gameplay system changes MPC global → affects ALL mirrors/potals/monitors
```
## 4. Manual Implementation Guide
1. Create Material Parameter Collection: Name = `MPC_CaptureSurface`
2. Add all 10 scalar parameters with names and default values from Section 1
3. Add 2 optional vector parameters if using color tinting
4. Assign this MPC to every capture surface actor's `SurfaceMPC` variable
5. In `M_CaptureSurface_Master`, link all `Collection Parameter` nodes to this MPC
## 5. Build Checklist
- [ ] Create MPC_CaptureSurface in editor
- [ ] Add all 10 scalar parameters
- [ ] Add 2 vector parameters (optional)
- [ ] Assign to all BP_* capture actors' SurfaceMPC variable
- [ ] Verify material compiles with MPC references
- [ ] Test: change SteamIntensity in MPC, verify all mirrors fog

View File

@@ -0,0 +1,94 @@
# 146 — Planar Capture Profile Data Asset (`DA_PlanarCaptureProfile`)
## Purpose
Designer-configurable capture profile for individual surfaces. Defines default mode, quality profile overrides, actor lists, and surface material. Referenced by `BP_PlanarCaptureActor` at BeginPlay.
## Dependencies
- **Requires:** `PlanarCaptureCommon.h` (C++ enums/structs)
- **Required By:** All capture surface actors (139-143)
- **Engine/Plugin Requirements:** None
## Class Info
| Property | Value |
|----------|-------|
| **Parent Class** | `PrimaryDataAsset` (C++ may extend) |
| **Class Type** | Data Asset |
| **Asset Path** | `Content/Framework/Capture/DA_PlanarCaptureProfile.uasset` |
| **C++ Status** | N/A (Data Asset) |
| **Asset to Create** | Data Asset in UE5 editor |
## 1. Variables
| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| `DefaultMode` | EPlanarCaptureMode | Mirror | Default capture mode |
| `QualityProfileOverrides` | TArray〈FPlanarCaptureQualityProfile〉 | — | Override specific quality tier settings (0=Low, 1=Medium, 2=High, 3=Hero) |
| `DefaultShowOnlyActors` | TArray〈FPlanarCaptureActorListEntry〉 | — | Pre-configured ShowOnly actors |
| `DefaultHiddenActors` | TArray〈FPlanarCaptureActorListEntry〉 | — | Pre-configured Hidden actors |
| `bStartEnabled` | bool | true | Surface starts active |
| `bDestructible` | bool | false | Can be destroyed |
| `SurfaceMaterialOverride` | TSoftObjectPtr〈UMaterialInterface〉 | — | Override surface material |
| `SurfaceMPCOverride` | TSoftObjectPtr〈UMaterialParameterCollection〉 | — | Override MPC reference |
| `DefaultFOV` | float | 90.0 | Override capture FOV |
| `MaxViewDistance` | float | 5000.0 | Override max view distance |
## 2. Usage Pattern
### At BeginPlay (BP_PlanarCaptureActor)
```
Event BeginPlay
├─ If DA_PlanarCaptureProfile is assigned:
│ ├─ CaptureComponent.CaptureMode = Profile.DefaultMode
│ ├─ CaptureComponent.CaptureFOV = Profile.DefaultFOV
│ ├─ CaptureComponent.ShowOnlyActors = Profile.DefaultShowOnlyActors
│ ├─ CaptureComponent.HiddenActors = Profile.DefaultHiddenActors
│ ├─ bStartEnabled = Profile.bStartEnabled
│ ├─ bDestructible = Profile.bDestructible
│ ├─ [If SurfaceMaterialOverride] SetSurfaceMaterial(Override)
│ └─ [If SurfaceMPCOverride] SurfaceMPC = Override
└─ Continue with normal BeginPlay
```
This allows placing 20 BP_Mirror instances in a level, each referencing a different DA_PlanarCaptureProfile — no per-instance variable tweaking needed.
## 3. Profile Examples
### Profile: HeroMirror
| Variable | Value |
|----------|-------|
| DefaultMode | Mirror |
| QualityProfileOverrides[3] | Hero: RT 2048, 60fps, Full Lumen, Post |
| bStartEnabled | true |
| bDestructible | false |
### Profile: SecurityMonitor
| Variable | Value |
|----------|-------|
| DefaultMode | Monitor |
| DefaultFOV | 70.0 |
| QualityProfileOverrides[0] | Low: RT 256, 5fps |
| MaxViewDistance | 3000.0 |
### Profile: HorrorMirror_ScareReady
| Variable | Value |
|----------|-------|
| DefaultMode | HorrorMirror |
| QualityProfileOverrides[3] | Hero: RT 2048, 12fps, DelayedFrame=5 |
| bDestructible | true |
| SurfaceMaterialOverride | MI_Mirror_Horror |
## 4. Manual Implementation Guide
1. Create Data Asset: Parent = `PrimaryDataAsset`, Name = `DA_PlanarCaptureProfile`
2. Add variables as listed in Section 1 (create struct for QualityProfileOverrides if needed)
3. Create multiple profile instances per surface type
4. In each BP_* child, add variable: `CaptureProfile: DA_PlanarCaptureProfile` (Instance Editable, Expose on Spawn)
5. In BeginPlay override, read profile and apply all settings before EnableSurface()
## 5. Build Checklist
- [ ] Create DA_PlanarCaptureProfile Data Asset (or C++ struct)
- [ ] Add all 10 variables
- [ ] Create profile instances: DA_HeroMirror, DA_SecurityMonitor, DA_HorrorMirror
- [ ] Add CaptureProfile variable to BP_PlanarCaptureActor
- [ ] Wire BeginPlay to apply profile
- [ ] Test: place mirror with different profiles, verify settings apply

View File

@@ -0,0 +1,130 @@
# 147 — Capture Surface Material Instances (`MI_Mirror_*`, `MI_Portal_*`, `MI_Monitor_*`, `MI_FakeWindow_*`)
## Purpose
Pre-configured Material Instance Constants (MICs) for common capture surface states. These are children of `M_CaptureSurface_Master` (144) with static switches and default parameters pre-set for each use case.
## Dependencies
- **Requires:** `M_CaptureSurface_Master` (144), `MPC_CaptureSurface` (145)
- **Required By:** All capture surface actors (139-143)
- **Engine/Plugin Requirements:** None
## Class Info
| Property | Value |
|----------|-------|
| **Asset Type** | MaterialInstanceConstant |
| **Parent Material** | `M_CaptureSurface_Master` |
| **Asset Path** | `Content/Framework/Capture/Materials/` |
| **C++ Status** | N/A |
| **Assets to Create** | 7 material instances |
## 1. Material Instance Catalog
### MI_Mirror_Clean
| Static Switch | Value |
|---------------|-------|
| `bIsMirror` | `true` |
| `bEnableHorrorLayers` | `false` |
| Scalar Override | Value | Note |
|-----------------|-------|------|
| `SteamIntensity` | 0.0 | No fog |
| `DirtOpacity` | 0.0 | Clean |
| `SurfaceAge` | 0.0 | No oxidation |
### MI_Mirror_Dirty
| Static Switch | Value |
|---------------|-------|
| `bIsMirror` | `true` |
| `bEnableHorrorLayers` | `false` |
| Scalar Override | Value | Note |
|-----------------|-------|------|
| `DirtOpacity` | 0.4 | Moderate dirt |
| `SurfaceAge` | 0.3 | Slight yellowing |
### MI_Mirror_Steam
| Static Switch | Value |
|---------------|-------|
| `bIsMirror` | `true` |
| `bEnableHorrorLayers` | `false` |
| Scalar Override | Value | Note |
|-----------------|-------|------|
| `SteamIntensity` | 0.6 | Visible fog |
| `CondensationFlow` | 0.5 | Slow rivulet drift |
| `DistortionAmplitude` | 0.2 | Slight warp |
| `SteamEmissiveIntensity` | 0.3 | Subtle glow |
### MI_Mirror_Horror
| Static Switch | Value |
|---------------|-------|
| `bIsMirror` | `true` |
| `bEnableHorrorLayers` | `true` |
| Scalar Override | Value | Note |
|-----------------|-------|------|
| `WrongReflectionBlend` | 0.0 | Starts off (driven by MPC at runtime) |
| `MirrorDarkness` | 0.0 | Starts normal |
| `TextRevealProgress` | 0.0 | Hidden until scare |
| `DistortionAmplitude` | 0.0 | Normal until scare |
### MI_Portal_Standard
| Static Switch | Value |
|---------------|-------|
| `bIsMirror` | `false` |
| `bEnableHorrorLayers` | `false` |
| Texture Override | Value | Note |
|------------------|-------|------|
| `CaptureTexture` | (set at runtime by component) | RT assigned dynamically |
### MI_Monitor_Security
| Static Switch | Value |
|---------------|-------|
| `bIsMirror` | `false` |
| `bEnableHorrorLayers` | `false` |
| Scalar Override | Value | Note |
|-----------------|-------|------|
| `ScanlineIntensity` | 0.3 | CRT scanline overlay (add as custom parameter) |
### MI_FakeWindow_Interior
| Static Switch | Value |
|---------------|-------|
| `bIsMirror` | `false` |
| `bEnableHorrorLayers` | `false` |
| Scalar Override | Value | Note |
|-----------------|-------|------|
| `RainIntensity` | 0.0 | Weather overlay off (add as custom parameter) |
| `FrostIntensity` | 0.0 | Weather overlay off (add as custom parameter) |
## 2. Usage Assignment
| Actor | Default MI | Swap Options |
|-------|-----------|--------------|
| `BP_Mirror` | MI_Mirror_Clean | MI_Mirror_Dirty, MI_Mirror_Steam |
| `BP_Portal` | MI_Portal_Standard | — |
| `BP_Monitor` | MI_Monitor_Security | PoweredOffMaterial (custom) |
| `BP_HorrorMirror` | MI_Mirror_Horror | MI_Mirror_Clean (pre-scare), MI_Mirror_Steam |
| `BP_FakeWindow` | MI_FakeWindow_Interior | — |
## 3. Manual Implementation Guide
1. Create all 7 Material Instance Constants
2. Parent: `M_CaptureSurface_Master`
3. For each, set Static Switch Parameters as listed above
4. Set Scalar Parameter Overrides where non-zero
5. Assign to corresponding Blueprint actor defaults
6. Test: place mirror with MI_Mirror_Steam, verify fogged appearance
## 4. Build Checklist
- [ ] Create MI_Mirror_Clean (bIsMirror=true, all scalars=0)
- [ ] Create MI_Mirror_Dirty (DirtOpacity=0.4)
- [ ] Create MI_Mirror_Steam (SteamIntensity=0.6)
- [ ] Create MI_Mirror_Horror (bEnableHorrorLayers=true)
- [ ] Create MI_Portal_Standard (bIsMirror=false)
- [ ] Create MI_Monitor_Security (bIsMirror=false)
- [ ] Create MI_FakeWindow_Interior (bIsMirror=false)
- [ ] Assign defaults to each BP child's SurfaceMesh
- [ ] Verify all compile without material errors

View File

@@ -53,7 +53,8 @@ docs/blueprints/
├── 13-polish/ ← Tutorial, Loading, Credits, Debug (9 files)
├── 14-data-assets/ ← Data Asset definitions (16 files)
├── 15-input/ ← Enhanced Input System (1 file)
── 16-state/ ← State Management (2 files)
── 16-state/ ← State Management (2 files)
└── 17-capture/ ← Planar Capture System (12 files)
```
---
@@ -213,6 +214,19 @@ docs/blueprints/
| 133 | [`133_BP_RoomAudioZone`](10-adaptive/133_BP_RoomAudioZone.md) | `BP_` Actor | `TriggerVolume` | Room audio zone; auto-switches reverb on overlap via push/pop stack | 10-adaptive |
| 134 | [`134_DA_AudioSettings`](14-data-assets/134_DA_AudioSettings.md) | `DA_` Data Asset | `PrimaryDataAsset` | Audio bus configs, volume defaults, ducking, pool limits | 14-data-assets |
| 135 | [`135_DA_RoomAcousticPreset`](14-data-assets/135_DA_RoomAcousticPreset.md) | `DA_` Data Asset | `PrimaryDataAsset` | Room acoustic profile; 7 presets (Outdoor, SmallRoom, Cave, etc.) | 14-data-assets |
| — | — | — | — | — | — |
| 136 | [`136_BPC_PlanarCapture`](17-capture/136_BPC_PlanarCapture.md) | `BPC_` Component | `ActorComponent` | Core capture: SceneCapture2D lifecycle, camera math, RT management, horror ring buffer | 17-capture |
| 137 | [`137_BP_PlanarCaptureActor`](17-capture/137_BP_PlanarCaptureActor.md) | `BP_` Actor | `Actor` | Placeable surface actor: mesh, MDI, proximity trigger, manager registration | 17-capture |
| 138 | [`138_SS_PlanarCaptureManager`](17-capture/138_SS_PlanarCaptureManager.md) | `SS_` Subsystem | `WorldSubsystem` | Global budget manager: surface scoring, quality tier assignment, RT pool | 17-capture |
| 139 | [`139_BP_Mirror`](17-capture/139_BP_Mirror.md) | `BP_` Actor | `BP_PlanarCaptureActor` | Standard mirror: Mode=Mirror, dirt/steam/condensation layers, aging | 17-capture |
| 140 | [`140_BP_Portal`](17-capture/140_BP_Portal.md) | `BP_` Actor | `BP_PlanarCaptureActor` | Portal surface: Mode=Portal, linked target, teleport on overlap, clip plane | 17-capture |
| 141 | [`141_BP_Monitor`](17-capture/141_BP_Monitor.md) | `BP_` Actor | `BP_PlanarCaptureActor` | Security screen: Mode=Monitor, fixed camera, 5fps, scanlines | 17-capture |
| 142 | [`142_BP_HorrorMirror`](17-capture/142_BP_HorrorMirror.md) | `BP_` Actor | `BP_Mirror` | Horror mirror: wrong reflection, delayed frame, text reveal, scare events | 17-capture |
| 143 | [`143_BP_FakeWindow`](17-capture/143_BP_FakeWindow.md) | `BP_` Actor | `BP_PlanarCaptureActor` | Architectural fake window: Mode=FakeWindow, sublevel, weather overlay | 17-capture |
| 144 | [`144_M_CaptureSurface_Master`](17-capture/144_M_CaptureSurface_Master.md) | `M_` Material | `Material` | Master unlit material: 9-layer stack (RT, condensation, dirt, steam, horror) | 17-capture |
| 145 | [`145_MPC_CaptureSurface`](17-capture/145_MPC_CaptureSurface.md) | MPC | `MaterialParameterCollection` | Global MPC: 10 scalar params (SteamIntensity, DirtOpacity, MirrorDarkness, etc.) | 17-capture |
| 146 | [`146_DA_PlanarCaptureProfile`](17-capture/146_DA_PlanarCaptureProfile.md) | `DA_` Data Asset | `PrimaryDataAsset` | Per-surface capture config: mode, quality overrides, actor lists | 17-capture |
| 147 | [`147_MI_MirrorInstances`](17-capture/147_MI_MirrorInstances.md) | `MI_` Instances | `M_CaptureSurface_Master` | 7 pre-configured material instances (Clean/Dirty/Steam/Horror/Portal/Monitor/FakeWindow) | 17-capture |
---
@@ -233,7 +247,7 @@ docs/blueprints/
| `AI_` | AI Controller | 1 |
| `BB_` | Blackboard | 1 |
| `E_` | Enum | 5 |
| **Total** | | **146** |
| **Total** | | **158** |
---

View File

@@ -1,6 +1,6 @@
# C++ & Blueprint Status Checklist — All 135 Systems
# C++ & Blueprint Status Checklist — All 147 Systems
**Version:** 2.0 | **Generated:** 2026-05-21 | **C++ Files:** 22 `.h` + 22 `.cpp` (12 full implementations + 10 stubs)
**Version:** 2.1 | **Generated:** 2026-05-22 | **C++ Files:** 27 `.h` + 27 `.cpp` (15 full implementations + 10 stubs)
Complete status grid for every system in the UE5 Modular Game Framework. Use this to track: which systems have C++ code written, which Blueprint specs are complete, and what Blueprint assets remain to create.
@@ -213,6 +213,27 @@ Abbreviations:
---
## Phase 17: Planar Capture System (17-capture — 12 systems)
### Capture Components & Actors (17-capture)
| # | System | C++ | BP Spec | BP Asset |
|---|--------|-----|---------|----------|
| 136 | `BPC_PlanarCapture` | ✅ Full — `Capture/BPC_PlanarCapture` | ✅ | None (use C++ component directly) |
| 137 | `BP_PlanarCaptureActor` | ✅ Full — `Capture/BP_PlanarCaptureActor` | ✅ | BP children (139-143 extend this) |
| 138 | `SS_PlanarCaptureManager` | ✅ Full — `Capture/SS_PlanarCaptureManager` | ✅ | None (auto-created WorldSubsystem) |
| 139 | `BP_Mirror` | 🔵 BP-only | ✅ | BP actor child of BP_PlanarCaptureActor |
| 140 | `BP_Portal` | 🔵 BP-only | ✅ | BP actor child of BP_PlanarCaptureActor |
| 141 | `BP_Monitor` | 🔵 BP-only | ✅ | BP actor child of BP_PlanarCaptureActor |
| 142 | `BP_HorrorMirror` | 🔵 BP-only (extends BP_Mirror) | ✅ | BP actor child of BP_Mirror |
| 143 | `BP_FakeWindow` | 🔵 BP-only | ✅ | BP actor child of BP_PlanarCaptureActor |
| 144 | `M_CaptureSurface_Master` | ⬜ Content Asset | ✅ | Create Material in editor |
| 145 | `MPC_CaptureSurface` | ⬜ Content Asset | ✅ | Create MPC in editor |
| 146 | `DA_PlanarCaptureProfile` | 🔵 BP-only | ✅ | ⬜ Data Asset instances |
| 147 | `MI_MirrorInstances` | ⬜ Content Asset | ✅ | 7 Material Instance Constants |
---
## Quick Action List — What to Build Next
### Immediate (Phase 0 — Foundation)
@@ -261,7 +282,7 @@ Abbreviations:
## C++ Source File Index
### Full Implementations (12 systems — logic complete, no BP child needed for functionality)
### Full Implementations (15 systems — logic complete, no BP child needed for functionality)
| # | C++ Class | Header | Source | Size |
|---|-----------|--------|--------|------|
@@ -277,6 +298,9 @@ Abbreviations:
| 72 | `UBPC_DamageReceptionSystem` | `Public/Weapons/BPC_DamageReceptionSystem.h` | `Private/Weapons/BPC_DamageReceptionSystem.cpp` | 150 + cpp |
| 128 | `USS_EnhancedInputManager` | `Public/Input/SS_EnhancedInputManager.h` | `Private/Input/SS_EnhancedInputManager.cpp` | 232 + cpp |
| 130 | `UBPC_StateManager` | `Public/Player/BPC_StateManager.h` | `Private/Player/BPC_StateManager.cpp` | 246 + cpp |
| 136 | `UBPC_PlanarCapture` | `Public/Capture/BPC_PlanarCapture.h` | `Private/Capture/BPC_PlanarCapture.cpp` | 360 + cpp |
| 137 | `ABP_PlanarCaptureActor` | `Public/Capture/BP_PlanarCaptureActor.h` | `Private/Capture/BP_PlanarCaptureActor.cpp` | 250 + cpp |
| 138 | `ASS_PlanarCaptureManager` | `Public/Capture/SS_PlanarCaptureManager.h` | `Private/Capture/SS_PlanarCaptureManager.cpp` | 330 + cpp |
### C++ Stubs (10 systems — UCLASS + basic vars/delegates, need BP child for logic)
@@ -293,6 +317,26 @@ Abbreviations:
| 120 | `UDA_EquipmentConfig` | `Public/Inventory/DA_EquipmentConfig.h` | `Private/Inventory/DA_EquipmentConfig.cpp` | Equipment config stub |
| 131 | `UDA_StateGatingTable` | `Public/State/DA_StateGatingTable.h` | `Private/State/DA_StateGatingTable.cpp` | Gating table stub |
### Planar Capture Systems (3 full C++ implementations)
| # | C++ Class | Header | Source | Purpose |
|---|-----------|--------|--------|---------|
| 136 | `UBPC_PlanarCapture` | `Public/Capture/BPC_PlanarCapture.h` | `Private/Capture/BPC_PlanarCapture.cpp` | SceneCapture2D lifecycle, camera math, horror features |
| 137 | `ABP_PlanarCaptureActor` | `Public/Capture/BP_PlanarCaptureActor.h` | `Private/Capture/BP_PlanarCaptureActor.cpp` | Placeable surface actor with mesh, MDI, proximity trigger |
| 138 | `ASS_PlanarCaptureManager` | `Public/Capture/SS_PlanarCaptureManager.h` | `Private/Capture/SS_PlanarCaptureManager.cpp` | Global budget manager, RT pool, surface scoring |
### Capture Utility (Static Library)
| # | C++ Class | Header | Source | Purpose |
|---|-----------|--------|--------|---------|
| — | `UPlanarCaptureCameraUtils` | `Public/Capture/PlanarCaptureCameraUtils.h` | `Private/Capture/PlanarCaptureCameraUtils.cpp` | Mirror/portal/oblique projection math |
### Capture Common (Shared Types)
| # | C++ Class | Header | Source | Purpose |
|---|-----------|--------|--------|---------|
| — | `PlanarCaptureCommon.h` | `Public/Capture/PlanarCaptureCommon.h` | `Private/Capture/PlanarCaptureCommon.cpp` | Shared enums, structs, quality profiles |
---
*Status Checklist v2.0 — Updated 2026-05-21. See [`remaining-blueprint-build-order.md`](remaining-blueprint-build-order.md) for the prioritized build list.*
*Status Checklist v2.1 — Updated 2026-05-22. See [`remaining-blueprint-build-order.md`](remaining-blueprint-build-order.md) for the prioritized build list.*

View File

@@ -0,0 +1,197 @@
# Planar Capture System — Implementation Checklist
**Version:** 1.0 | **Phase:** 17 | **Systems:** 136-147 (12 systems)
Use this checklist to track implementation of the Planar Capture System. Each checkbox represents a discrete task.
---
## Phase 17a — C++ Core (Systems 136-138)
### C++ Files to Create
- [ ] `Source/PG_Framework/Public/Capture/PlanarCaptureCommon.h` — enums, structs, quality profiles
- [ ] `Source/PG_Framework/Private/Capture/PlanarCaptureCommon.cpp` — compilation stub
- [ ] `Source/PG_Framework/Public/Capture/PlanarCaptureCameraUtils.h` — static math library
- [ ] `Source/PG_Framework/Private/Capture/PlanarCaptureCameraUtils.cpp` — mirror/portal/oblique math
- [ ] `Source/PG_Framework/Public/Capture/BPC_PlanarCapture.h` — component header
- [ ] `Source/PG_Framework/Private/Capture/BPC_PlanarCapture.cpp` — component implementation
- [ ] `Source/PG_Framework/Public/Capture/BP_PlanarCaptureActor.h` — actor header
- [ ] `Source/PG_Framework/Private/Capture/BP_PlanarCaptureActor.cpp` — actor implementation
- [ ] `Source/PG_Framework/Public/Capture/SS_PlanarCaptureManager.h` — subsystem header
- [ ] `Source/PG_Framework/Private/Capture/SS_PlanarCaptureManager.cpp` — subsystem implementation
### Build Configuration
- [ ] Update `PG_Framework.Build.cs` — add `"Renderer"` and `"RenderCore"` to PublicDependencyModuleNames
- [ ] Update `PG_Framework.h` — include `Capture/PlanarCaptureCommon.h`
- [ ] Compile and fix any errors
- [ ] Verify module loads in UE5 editor
### Initial Testing
- [ ] Spawn `BP_PlanarCaptureActor` in test level (use Blueprint child with mesh)
- [ ] Verify `SS_PlanarCaptureManager` is auto-created by engine
- [ ] Verify `BPC_PlanarCapture` initializes without crash
- [ ] Verify `RegisterSurface` logs to output log
- [ ] Test `CaptureNow()` — verify no crash during capture
- [ ] Test `ShutdownCapture()` — verify RT returned to pool
---
## Phase 17b — Material Foundation (Systems 144, 145, 147)
### M_CaptureSurface_Master
- [ ] Create Material: Name=`M_CaptureSurface_Master`, Domain=Surface, ShadingModel=Unlit
- [ ] Build Layer 0: Texture Sample Parameter "CaptureTexture" with UV flip branch (bIsMirror static switch)
- [ ] Build Layer 1: Condensation normal (Panner + Normal Strength driven by DistortionAmplitude MPC)
- [ ] Build Layer 2: Fresnel edge fade (CameraVector · VertexNormal)
- [ ] Build Layer 3: Dirt/scratch multiply (DirtMask × DirtOpacity, tinted by SurfaceAge)
- [ ] Build Layer 4: Steam/fog lerp (animated noise × SteamIntensity)
- [ ] Build Layer 5: Steam emissive glow (noise × SteamEmissiveIntensity → Emissive Color)
- [ ] Build Layer 6: Text reveal mask (TextRevealMask × TextRevealProgress)
- [ ] Build Layer 7: Mirror darkness (multiply by 1.0 - MirrorDarkness)
- [ ] Build Layer 8: Wrong reflection crossfade (lerp NormalRT ↔ DelayedRT by WrongReflectionBlend)
- [ ] Add bIsMirror static switch (true = UV flip)
- [ ] Add bEnableHorrorLayers static switch (false = Layers 6-8 compiled out)
- [ ] Add 10 MPC Collection Parameter nodes referencing MPC_CaptureSurface
- [ ] Compile → zero material errors
### MPC_CaptureSurface
- [ ] Create Material Parameter Collection: `MPC_CaptureSurface`
- [ ] Add 10 scalar parameters: SteamIntensity(default 0), DirtOpacity(0), CondensationFlow(0), DistortionAmplitude(0), MirrorDarkness(0), WrongReflectionBlend(0), TextRevealProgress(0), SteamEmissiveIntensity(0), DelayedReflectionBlend(0), SurfaceAge(0)
- [ ] Add 2 vector parameters: SurfaceTintColor(1,1,1,1), SteamColor(0.8,0.85,0.9,1)
### Material Instances
- [ ] Create `MI_Mirror_Clean` — bIsMirror=true, bEnableHorrorLayers=false
- [ ] Create `MI_Mirror_Dirty` — DirtOpacity=0.4, SurfaceAge=0.3
- [ ] Create `MI_Mirror_Steam` — SteamIntensity=0.6, CondensationFlow=0.5
- [ ] Create `MI_Mirror_Horror` — bEnableHorrorLayers=true
- [ ] Create `MI_Portal_Standard` — bIsMirror=false
- [ ] Create `MI_Monitor_Security` — bIsMirror=false
- [ ] Create `MI_FakeWindow_Interior` — bIsMirror=false
---
## Phase 17c — Blueprint Actors (Systems 139-143)
### BP_Mirror (139)
- [ ] Create Blueprint: Parent=`BP_PlanarCaptureActor`, Name=`BP_Mirror`
- [ ] Set `CaptureComponent.CaptureMode = Mirror` in Class Defaults
- [ ] Assign plane mesh to `SurfaceMesh`
- [ ] Assign `MI_Mirror_Clean` to SurfaceMesh Material[0]
- [ ] Set `SurfaceMPC` = `MPC_CaptureSurface`
- [ ] Add custom events: `SetMirrorDirtLevel(Float)`, `SetMirrorSteamLevel(Float)`
- [ ] Test: place in level, walk up, verify reflection renders
### BP_Portal (140)
- [ ] Create Blueprint: Parent=`BP_PlanarCaptureActor`, Name=`BP_Portal`
- [ ] Add `TeleportTrigger` BoxComponent
- [ ] Set `CaptureComponent.CaptureMode = Portal`
- [ ] Assign `MI_Portal_Standard` to SurfaceMesh
- [ ] Implement `OnPortalOverlap` event with `HasAuthority` gate
- [ ] Implement `Server_TeleportThroughPortal` RPC
- [ ] Add `LinkedTargetSurface` variable (set per instance)
- [ ] Test: place source + target portals, verify view renders and teleport works
### BP_Monitor (141)
- [ ] Create Blueprint: Parent=`BP_PlanarCaptureActor`, Name=`BP_Monitor`
- [ ] Set `CaptureComponent.CaptureMode = Monitor, CaptureFOV = 70`
- [ ] Override QualityProfiles[0].CaptureInterval = 0.2 (5fps)
- [ ] Assign `MI_Monitor_Security` to SurfaceMesh
- [ ] Add `bPoweredOn`, `StaticNoiseIntensity`, `FlickerCurve` variables
- [ ] Implement `PowerOn()`, `PowerOff()`, `SetStaticNoise()` functions
- [ ] Place CameraActor in level, assign to `FixedCameraActor`
- [ ] Test: power on/off cycle, static noise, scanline appearance
### BP_HorrorMirror (142)
- [ ] Create Blueprint: Parent=`BP_Mirror`, Name=`BP_HorrorMirror`
- [ ] Set `CaptureComponent.CaptureMode = HorrorMirror`
- [ ] Hero tier: set `DelayedFrameCount = 5`
- [ ] Place `WrongReflectionActor` (Metahuman/ghost) hidden in level
- [ ] Create Float Curves: `Curve_WrongReflectionBlend`, `Curve_MirrorDarkness`, `Curve_UVDistortion`
- [ ] Build `HorrorScareTimeline` with 4 tracks
- [ ] Implement `TriggerHorrorScare()` event
- [ ] Wire to `BPC_ScareEventSystem.TriggerScareEvent()`
- [ ] Wire audio to `SS_AudioManager.PlaySoundAtLocation()`
- [ ] Test: trigger scare, verify wrong reflection appears and fades, MPC params return to zero
### BP_FakeWindow (143)
- [ ] Create Blueprint: Parent=`BP_PlanarCaptureActor`, Name=`BP_FakeWindow`
- [ ] Set `CaptureComponent.CaptureMode = FakeWindow, CaptureFOV = 100`
- [ ] Assign `MI_FakeWindow_Interior` to SurfaceMesh
- [ ] Create sublevel with view room + SceneCaptureCamera
- [ ] Implement `CheckPlayerDistance` timer for sublevel streaming
- [ ] Implement `SetWeatherOverlay(Weather)` function
- [ ] Test: sublevel streams in/out based on distance
---
## Phase 17d — Data Asset (System 146)
### DA_PlanarCaptureProfile
- [ ] Create Data Asset: `DA_PlanarCaptureProfile` (PrimaryDataAsset or custom C++ class)
- [ ] Add variables: DefaultMode, QualityProfileOverrides, ShowOnly/Hidden actors, bStartEnabled, bDestructible, material override
- [ ] Create profile instances: `DA_HeroMirror`, `DA_SecurityMonitor`, `DA_HorrorMirror_ScareReady`
- [ ] Add `CaptureProfile` variable to `BP_PlanarCaptureActor` (Instance Editable, Expose on Spawn)
- [ ] Wire BeginPlay to apply profile
---
## Phase 17e — Integration
### Scare System Integration
- [ ] `BP_HorrorMirror.TriggerHorrorScare()``BPC_ScareEventSystem.TriggerScareEvent(Tag)` (101)
- [ ] Create `DA_ScareEvent` instance for mirror apparition scare (references existing 127 pattern)
### Audio Integration
- [ ] All sound triggers route through `SS_AudioManager` (132)
- [ ] Mirror shatter: `SS_AudioManager.PlaySoundAtLocation()`
- [ ] Portal whoosh: `SS_AudioManager.PlaySoundAtLocation()`
- [ ] Monitor static/hum: `SS_AudioManager.PlaySoundAtLocation()`
### State Manager Integration
- [ ] Portal teleport: `BPC_StateManager.IsActionPermitted(Teleport Tag)` (130)
- [ ] Horror scare: `BPC_StateManager.IsActionPermitted(Scare Tag)` before triggering
- [ ] Add `Framework.Action.Teleport`, `Framework.Action.Scare` tags to GameplayTag data tables
### Persistence Integration
- [ ] `BP_PlanarCaptureActor` implements `I_Persistable` (36)
- [ ] `CollectState()`: save bIsDestroyed, DirtOpacity, SteamIntensity, SurfaceAge
- [ ] `RestoreState()`: apply saved state, update MPC params
### Input Integration
- [ ] Portal transition pushes inspection input context via `SS_EnhancedInputManager` (128)
### Camera Integration
- [ ] Portal transition applies FOV animation via `BPC_CameraStateLayer` (14) (optional)
---
## Phase 17f — Polish & Performance
- [ ] Performance test: 1 mirror @ Hero → GPU profiling baseline
- [ ] Performance test: 3 mirrors @ High → verify budget enforcement
- [ ] Performance test: 10 mirrors, walk around → verify quality tiers scale correctly
- [ ] Edge case: mirror behind wall → verify frustum cull sets Off
- [ ] Edge case: player very far → verify distance sets Off
- [ ] Edge case: mirror destroyed during scene capture → no crash
- [ ] Edge case: rapid enable/disable cycle → no RT leak
- [ ] Memory test: verify RT pool releases all targets on level unload
- [ ] Multiplayer test: server destroys mirror, verify clients disable
- [ ] Multiplayer test: two players look at same mirror, verify both see correct reflection
---
## Documentation Verification
- [ ] `docs/blueprints/17-capture/` — 12 spec files created and reviewed
- [ ] `docs/blueprints/INDEX.md` — updated with 17-capture section
- [ ] `docs/developer/INDEX.md` — updated with 17-capture-systems entry
- [ ] `docs/developer/17-capture-systems.md` — developer reference created
- [ ] `CONTEXT.md` — Phase 17 added to Build Order, directory structure updated
- [ ] `UE5_Modular_Game_Framework.md` — systems 136-147 documented
- [ ] `docs/architecture/planar-capture-system.md` — architecture spec created
- [ ] `docs/architecture/blueprint-limitations-workarounds.md` — SceneCapture2D C++ workarounds added
- [ ] `docs/checklists/cpp-blueprint-status.md` — 12 new systems added to status grid
---
*Planar Capture System Checklist v1.0 — Track each checkbox as you implement.*

View File

@@ -773,6 +773,11 @@ STEP 22 — Adaptive BPs (89-101)
STEP 23 — Meta + Settings + Polish (102-114)
STEP 24 — SS_AudioManager + BP_RoomAudioZone (132-133)
STEP 25 — All DA_* Data Asset instances (content-populated, per project)
STEP 26 — Phase 17: Planar Capture C++ (136-138) — UBPC_PlanarCapture, ABP_PlanarCaptureActor, ASS_PlanarCaptureManager
STEP 27 — Phase 17b: Materials (144, 145, 147) — M_CaptureSurface_Master, MPC_CaptureSurface, 7 MI_ instances
STEP 28 — Phase 17c: Blueprint Actors (139-143) — BP_Mirror, BP_Portal, BP_Monitor, BP_HorrorMirror, BP_FakeWindow
STEP 29 — Phase 17d: Data Asset (146) — DA_PlanarCaptureProfile instances
STEP 30 — Phase 17e: Integration — wire to BPC_ScareEventSystem (101), SS_AudioManager (132), BPC_StateManager (130)
```
---
@@ -789,6 +794,7 @@ Every system has a complete spec in `docs/blueprints/` with node-by-node Manual
| `docs/architecture/sound-catalog.md` | 150+ sound triggers, 14 surface table entries |
| `docs/architecture/multiplayer-networking.md` | HasAuthority() gates, Server_ RPCs, RepNotify patterns |
| `docs/architecture/blueprint-limitations-workarounds.md` | C++-only functions you'll encounter during BP implementation |
| `docs/architecture/planar-capture-system.md` | Mirror/portal/monitor/horror capture system architecture (12 systems, Phase 17) |
| `docs/developer/cpp-integration-guide.md` | Per-C++-class setup steps, usage patterns, BP child requirements |
---
@@ -797,13 +803,17 @@ Every system has a complete spec in `docs/blueprints/` with node-by-node Manual
| Asset Type | Total | C++-Covered | BP to Build |
|-----------|-------|------------|-------------|
| **BP Components (BPC_)** | 79 | 4 full C++, 8 stubs | 67 BP children (8 have C++ stubs to extend) |
| **BP Actors (BP_)** | 11 | 0 | 11 BP actor children |
| **BP Components (BPC_)** | 80 | 5 full C++, 8 stubs | 67 BP children (8 have C++ stubs to extend) |
| **BP Actors (BP_)** | 16 | 1 full C++ | 15 BP actor children |
| **Widget BPs (WBP_)** | 14 | 0 | 14 Widget BPs |
| **Data Assets (DA_)** | 18 | 3 full C++, 2 stubs | ~200+ DA instances (content-driven) |
| **Data Assets (DA_)** | 19 | 3 full C++, 2 stubs | ~200+ DA instances (content-driven) |
| **GameInstance Subsystems (SS_)** | 7 | 3 full C++ | 4 BP children |
| **World Subsystems (SS_)** | 1 | 1 full C++ | 0 |
| **Materials (M_)** | 1 | 0 | 1 Material |
| **Material Instances (MI_)** | 7 | 0 | 7 MICs |
| **MPC** | 1 | 0 | 1 MPC |
| **Interfaces (I_)** | 10 | 9 in C++ | 1 (I_HidingSpot) |
| **Function Libraries (FL_)** | 1 | 1 in C++ | 0 |
| **Function Libraries (FL_)** | 2 | 2 in C++ | 0 |
| **GameInstance (GI_)** | 1 | 1 in C++ | 1 BP child |
| **GameMode (GM_)** | 1 | 1 in C++ | 1 BP child |
| **GameState (GS_)** | 1 | 1 in C++ | 1 BP child |

View File

@@ -0,0 +1,281 @@
# Developer Reference — Capture Systems (Systems 136-147)
**Version:** 1.0 | **Systems:** 136-147 (12 systems) | **Phase:** 17 | **Layer:** Rendering & Visual
---
## Architecture Overview
The Planar Capture System provides a unified rendering pipeline for mirrors, portals, monitors, and horror surfaces. All performance-critical work (camera math, render target management, scene capture lifecycle, quality budget enforcement) runs in C++, while designer-facing configuration, event scripting, and material authoring live in Blueprint.
### System Layers
```
┌──────────────────────────────────────────────────────────────────────┐
│ BLUEPRINT CONTENT LAYER │
│ BP_Mirror → BP_HorrorMirror Designer places in level, configures │
│ BP_Portal → BP_Monitor → BP_FakeWindow │
│ DA_PlanarCaptureProfile → MPC_CaptureSurface → MI_* material instances│
├──────────────────────────────────────────────────────────────────────┤
│ C++ RUNTIME LAYER │
│ ASS_PlanarCaptureManager ← Global budget, RT pool, scoring │
│ ABP_PlanarCaptureActor ← Surface mesh, MDI, registration │
│ UBPC_PlanarCapture ← SceneCapture2D, camera math, horror │
│ UPlanarCaptureCameraUtils ← Static math: mirror, portal, oblique │
├──────────────────────────────────────────────────────────────────────┤
│ UE5 ENGINE LAYER │
│ USceneCaptureComponent2D UTextureRenderTarget2D │
│ UMaterialParameterCollectionInstance UWorldSubsystem │
└──────────────────────────────────────────────────────────────────────┘
```
---
## Data Flow: Mirror Reflection
### Step-by-Step: Player Looks at a Mirror
1. **Registry:** `BP_Mirror.BeginPlay()` calls `SS_PlanarCaptureManager.RegisterSurface(this)` — the mirror is now tracked globally.
2. **Evaluation (0.5s interval):** `SS_PlanarCaptureManager.Tick()` calls `EvaluateAllSurfaces()`.
3. **Scoring:** For each registered surface, `BPC_PlanarCapture.GetCurrentScore()` computes:
- Screen coverage (how much screen space does the surface occupy?)
- Facing angle (is the player looking at the surface or edge-on?)
- Distance to viewer
- Scripted priority override
- Visibility frustum check
4. **Tier Assignment:** Based on composite score and budget limits, the manager calls `BPC_PlanarCapture.ApplyQualityTier(Tier)`.
5. **Capture Tick (per frame):** `BPC_PlanarCapture.TickComponent()` checks time since last capture vs the quality tier's `CaptureInterval`. If it's time to capture:
- Gets the player camera transform
- Calls `ComputeCaptureCameraTransform()` — for Mirror mode, this calls `UPlanarCaptureCameraUtils::ComputeMirroredTransform()` which reflects the player camera across the mirror plane
- Sets the `USceneCaptureComponent2D` world transform
- Calls `SceneCapture->CaptureScene()` — renders to the allocated `UTextureRenderTarget2D`
- Calls `PushMPCParameters()` to update the MPC with current horror/visual params
6. **Material Display:** `M_CaptureSurface_Master` samples the render target texture, applies UV flip (for mirror), and layers any active effects (dirt, steam, condensation). The output is displayed on the surface mesh.
### Quality Tier Transitions
```
Off ←──→ Low ←──→ Medium ←──→ High ←──→ Hero
(score=0) (>0) (≥0.2) (≥0.5) (≥0.8)
Demotion happens when:
- Score drops below threshold (player walks away)
- Budget limit exceeded (too many Hero surfaces)
- GlobalQualityCap clamps tier
- Force tier override is released
Promotion happens when:
- Score rises above threshold (player approaches)
- Budget slots open up (higher-tier surface destroyed or goes Off)
- Scripted priority boost kicks in
```
---
## State Machine: Quality Tier Lifecycle
```
[Surface Spawns]
┌─────────┐ score > 0 ┌─────────┐
│ OFF │ ────────────────► │ LOW │
└─────────┘ └────┬────┘
▲ │ score ≥ 0.2
│ score = 0 ┌────▼────┐
│ or !inFrustum │ MEDIUM │
│ └────┬────┘
│ │ score ≥ 0.5
│ ┌────▼────┐
│ │ HIGH │
│ └────┬────┘
│ │ score ≥ 0.8
│ ┌────▼────┐
│ │ HERO │
│ └─────────┘
┌────┴────────┐
│ SURFACE │ Called on EndPlay, DisableSurface, or DestroySurface
│ DESTROYED │
└─────────────┘
```
---
## Budget Enforcement
The `SS_PlanarCaptureManager` enforces three levels of budget:
1. **Per-Tier Count Limits:** `MaxHeroSurfaces` (default 1), `MaxHighSurfaces` (3), `MaxMediumSurfaces` (6). If 4 surfaces score ≥ 0.5, only the top 3 get High tier — the 4th gets Medium even if it scored for High.
2. **Total Memory Budget:** `MaxTotalRenderTargetMemoryMB` (default 128MB). If exceeded, the manager logs a warning. Future: automatic demotion of lowest-priority surfaces until under budget.
3. **Global Quality Cap:** `GlobalQualityCap` (default High). No surface exceeds this tier regardless of score. Set to Medium on Steam Deck / lower hardware.
---
## Render Target Pool
The pool reduces memory allocation overhead by reusing render targets:
```
RequestRenderTarget(Size):
1. Search pool for entry with matching Size AND !bInUse
2. If found → mark bInUse=true, return RT
3. If not → CreateRenderTarget(Size) → add to pool
ReleaseRenderTarget(RT):
1. Find pool entry for this RT
2. Mark bInUse=false (RT stays allocated, ready for next request)
```
This means the pool stabilizes after initial allocation — no new RTs are created unless a new size is requested.
---
## Horror Features Deep Dive
### Wrong Reflection (ActivateHorrorReflection)
```
1. UBPC_PlanarCapture saves current ShowOnlyActors → SavedShowOnlyActors
2. ShowOnlyActors is cleared
3. WrongReflectionActor is added to ShowOnlyActors
4. UpdateActorLists() pushes to USceneCaptureComponent2D::ShowOnlyActors
5. Next capture frame: SceneCapture2D now ONLY renders the WrongReflectionActor
6. Material: WrongReflectionBlend MPC param crossfades between normal RT and wrong reflection
```
### Delayed Frame Ring Buffer
```
Hero tier with DelayedFrameCount = 5:
1. FrameRingBuffer array has 5 render targets
2. Each capture frame: RingBufferWriteIndex = (index + 1) % 5
3. Material: DelayedReflectionBlend MPC param blends between current frame and oldest ring buffer frame
4. Effect: Player's reflection lags 5 frames behind — unsettling
```
### Steam Text Reveal
```
TriggerHorrorScare() → Timeline → TextRevealProgress MPC param ramps 0→1
Material Layer 6: TextRevealMask texture is wiped from 0 to 1
Appearance: "HELP ME" appears to write itself in the steam on the mirror
```
---
## Integration Points
### BPC_StateManager (130)
```cpp
// Portal teleport must be gated
if (!StateManager->IsActionPermitted(FGameplayTag::RequestGameplayTag("Framework.Action.Teleport")))
return; // Blocked — player is dead, in cutscene, etc.
```
### BPC_ScareEventSystem (101)
```cpp
// Horror mirror triggers coordinated scare
ScareEventSystem->TriggerScareEvent(ScareEventTag);
// This coordinates lights (96), audio (132), pacing (98), stress (10)
```
### SS_AudioManager (132)
```cpp
// All surface audio routes through audio subsystem
AudioManager->PlaySoundAtLocation(MirrorShatterCue, GetActorLocation());
AudioManager->PlaySoundAtLocation(PortalWhooshCue, GetActorLocation());
```
### I_Persistable (36)
```cpp
// Surface state persists across saves
// BP_PlanarCaptureActor implements I_Persistable:
CollectState() { bIsDestroyed, CurrentDirtLevel, CurrentSteamLevel }
RestoreState() { Apply saved state }
```
### SS_EnhancedInputManager (128)
```cpp
// Portal transition switches input context
InputManager->PushContext(PortalTransitionContext, EInputContextPriority::Inspection);
// Player exits portal → PopContext
```
---
## Multiplayer Networking
### What Replicates
- **`bRepIsActive`** on `BP_PlanarCaptureActor` — server tells all clients whether a surface is active (e.g., a mirror was shattered by another player)
### What Does NOT Replicate (Local-Only)
- **All capture rendering** — each client renders their own view with their own camera perspective. There is zero reason to replicate render targets.
- **Quality tiers** — each client evaluates surfaces independently (different camera positions mean different scores)
- **Horror effects** — triggered server-side (scare event), executed locally on each client
### Server-Authoritative Pattern
```
Server: BP_Mirror.DestroySurface() [HasAuthority]
→ Set bRepIsActive = false
→ OnRep_IsActive fires on all clients
→ Each client independently: DisableSurface() → ShutdownCapture()
```
---
## Performance Characteristics
| Tier | GPU Cost (relative) | VRAM per Surface | CPU Cost |
|------|---------------------|------------------|----------|
| Hero | 16x baseline | 16 MB | High (60 captures/sec) |
| High | 4x baseline | 4 MB | Medium (30/sec) |
| Medium | 1x baseline | 1 MB | Low (15/sec) |
| Low | 0.25x baseline | 256 KB | Minimal (4/sec) |
| Off | 0 | 0 | Zero |
### Optimization Tips
1. **MaxCaptureDistance:** Set lower (3000-5000) for indoor levels — mirrors far away go Off
2. **FullEvaluationInterval:** Increase to 1.0s for large levels with many mirrors to reduce CPU scoring cost
3. **GlobalQualityCap:** Set to Medium on Steam Deck. Set to High on consoles.
4. **ShowOnly lists:** Use aggressively. Capturing only 5 actors is vastly cheaper than capturing 500.
5. **Monitor FPS:** Monitors should use 5fps Low tier — they don't need real-time updates.
6. **Lumen on capture:** Only enable on Hero tier. Each Lumen-enabled capture is ~3x more expensive.
---
## Debugging
### Console Commands
```
// Show all registered capture surfaces
SS_PlanarCaptureManager.GetSurfaceCount()
// Show pool memory usage
SS_PlanarCaptureManager.GetPoolMemoryUsageMB()
// Force all to max quality (for visual debugging)
SS_PlanarCaptureManager.ForceAllSurfacesToTier(Hero)
SS_PlanarCaptureManager.ReleaseForceTier()
// Show capture FPS (add to BPC_PlanarCapture debug mode)
stat SceneRendering
```
### Visual Debug
- **Unlit view mode:** See raw render target output without material effects
- **Wireframe:** Verify camera frustum on SceneCaptureComponent2D
- **Stat GPU:** SceneCapture passes appear under "SceneCapture" category
---
## Build Order (Phase 17)
| Sub-Phase | Systems | Dependencies |
|-----------|---------|-------------|
| 17a — C++ Core | 136, 137, 138, `PlanarCaptureCommon`, `PlanarCaptureCameraUtils` | Renderer module |
| 17b — Materials | 144, 145, 147 | 17a (for MPC parameter names) |
| 17c — Blueprint Actors | 139, 140, 141, 142, 143 | 17a + 17b |
| 17d — Data Assets | 146 | 17a |
| 17e — Integration | Wire to 101, 132, 130, 128, 36 | 17c |
---
*Developer Reference — Capture Systems v1.0. Companion to Blueprint Spec files in `docs/blueprints/17-capture/`.*

View File

@@ -1,6 +1,6 @@
# Developer Reference — UE5 Modular Game Framework
**Version:** 1.5 | **Generated:** 2026-05-21 | **Files:** 18 (1 index + 2 overview + 1 migration + 1 integration + 1 prototype + 1 starter + 10 category docs + 1 combined) | **C++:** 12 full + 10 stubs = 22 systems
**Version:** 1.6 | **Generated:** 2026-05-22 | **Files:** 19 (1 index + 2 overview + 1 migration + 1 integration + 1 prototype + 1 starter + 10 category docs + 1 combined + 1 capture) | **C++:** 15 full + 10 stubs = 25 systems
This directory contains developer-facing reference documentation for every system in the framework. Unlike the blueprint spec files (which define *what* to build), these documents explain *how each system works internally* — the data flow, state machines, integration points, and design rationale. Use these when you need to understand a system's behavior to implement, debug, or extend it.
@@ -32,7 +32,8 @@ docs/developer/
├── 08-weapons-systems.md ← Weapons, equipment & damage (systems 69-79)
├── 09-ai-systems.md ← AI, perception & encounters (systems 80-88)
├── 10-adaptive-systems.md ← Adaptive environment & atmosphere (systems 89-101, 132-133)
── 11-16-systems.md ← Meta, Settings, Polish, Data Assets, Input, State (systems 102-135)
── 11-16-systems.md ← Meta, Settings, Polish, Data Assets, Input, State (systems 102-135)
└── 17-capture-systems.md ← Planar Capture System — Mirrors, Portals, Monitors, Horror (systems 136-147)
```
## Quick Reference — Every System at a Glance

View File

@@ -199,8 +199,21 @@ Content/Game/ ← ALL game content (NEVER modify Fr
│ ├── BP_LightEvent_Flicker.uasset
│ ├── BP_ScareEvent_LockerBang.uasset
│ ├── BP_ScareEvent_Mirror.uasset
│ ├── BP_HorrorMirror_Morgue.uasset ← Horror mirror (wrong reflection scare)
│ ├── BP_Mirror_NurseStation.uasset ← Standard mirror (checkpoint reflection)
│ └── BP_AtmosphereController_WardA.uasset
├── Capture/ ← Planar Capture surface actors
│ ├── BP_Mirror_NurseStation.uasset ← Standard mirror: Mode=Mirror, aged, checkpoint
│ ├── BP_HorrorMirror_Morgue.uasset ← Horror mirror: wrong reflection, steam scare
│ ├── BP_HorrorMirror_WardensOffice.uasset ← Horror mirror: final entity confrontation
│ ├── BP_Monitor_Security.uasset ← Security monitor: hallway camera feed, scanlines
│ ├── BP_Monitor_Morgue.uasset ← Morgue monitor: static noise, flicker, Shade cameo
│ ├── BP_Portal_VoidEntrance.uasset ← Void portal entrance (Basement → VoidSpace)
│ ├── BP_Portal_VoidExit.uasset ← Void portal exit (VoidSpace → Basement)
│ ├── BP_FakeWindow_WardensOffice.uasset ← Atmospheric window: rain, night, parallax
│ └── DA_PlanarCaptureProfile_Mirror.uasset← Capture profile Data Assets
├── Audio/ ← Game-specific audio assets
│ ├── DA_AudioSettings_Horror.uasset ← Audio bus config
│ ├── BP_RoomAudioZone_WardA.uasset ← Room audio zone volumes
@@ -600,6 +613,22 @@ Each game asset proves a specific framework system works. Below: every framework
| 130 | BPC_StateManager | Hiding blocks fire; death blocks interaction; cutscene blocks all |
| 131 | DA_StateGatingTable | Designer-configurable state permission rules |
### 17-capture (Planar Capture — 12 systems)
| # | Framework System | Demonstrated By |
|---|-----------------|----------------|
| 136 | BPC_PlanarCapture | All capture surfaces (component managing SceneCapture2D lifecycle) |
| 137 | BP_PlanarCaptureActor | BP_Mirror, BP_Portal, BP_Monitor, BP_HorrorMirror, BP_FakeWindow (all extend this) |
| 138 | SS_PlanarCaptureManager | Auto-created WorldSubsystem — manages quality budget across all 8 surfaces |
| 139 | BP_Mirror | BP_Mirror_NurseStation — standard reflection mirror with aging |
| 140 | BP_Portal | BP_Portal_VoidEntrance/Exit — void portal teleport with clip plane |
| 141 | BP_Monitor | BP_Monitor_Security/Morgue — security camera feeds, scanlines, static noise |
| 142 | BP_HorrorMirror | BP_HorrorMirror_Morgue/WardensOffice — wrong reflection, steam, text, scare events |
| 143 | BP_FakeWindow | BP_FakeWindow_WardensOffice — atmospheric window with weather overlay |
| 144 | M_CaptureSurface_Master | All mirror/portal/monitor surfaces (9-layer material stack) |
| 145 | MPC_CaptureSurface | All 10 MPC scalar params (SteamIntensity, DirtOpacity, MirrorDarkness, etc.) |
| 146 | DA_PlanarCaptureProfile | DA_PlanarCaptureProfile_Mirror — per-surface quality config |
| 147 | MI_MirrorInstances | MI_Mirror_Clean/Dirty/Steam/Horror, MI_Portal_Standard, MI_Monitor_Security, MI_FakeWindow_Interior |
---
## Build Order (Dependency-Safe)
@@ -625,7 +654,8 @@ Follow this order when creating uasset files in UE5:
| 14 | **Data Assets (Content)** — Encounters, Atmosphere, Scares, Puzzles, Objectives, Behaviour, Acoustic | DA_* parents | 20+ |
| 15 | **Checkpoints** — BP_Checkpoint_SafeRoom, _Mirror | BP_Checkpoint | 2 |
| 16 | **Room Audio Zones** — BP_RoomAudioZone_* | BP_RoomAudioZone | 3 |
| 17 | **Encounter Spawners** — BP_EncounterSpawner_* | BPC_ProceduralEncounter | 3 |
| 17 | **Capture Surfaces** — BP_Mirror_NurseStation, BP_HorrorMirror_Morgue/WardensOffice, BP_Monitor_Security/Morgue, BP_Portal_VoidEntrance/Exit, BP_FakeWindow_WardensOffice | BP_PlanarCaptureActor | 9 |
| 18 | **Encounter Spawners** — BP_EncounterSpawner_* | BPC_ProceduralEncounter | 3 |
| 18 | **Atmosphere Actors** — BP_LightEvent_*, BP_ScareEvent_*, BP_AtmosphereController_* | BPC_* parent | 6 |
| 19 | **Tutorial Triggers** — BP_TutorialTrigger_* | BPC_TutorialSystem | 3 |
| 20 | **Polish** — BP_CreditsSequence, dev cheats, debug menu | Framework | 3 |
@@ -657,6 +687,7 @@ Each `docs/game/` file explains how to build a specific section of the prototype
| [`enemies-index.md`](enemies-index.md) | All enemies — Patient, Shade, Orderly — AI controllers, BT, perception | 12 |
| [`narrative-progression.md`](narrative-progression.md) | Objectives, dialogue, cutscenes, ending accumulator, branching | 13 |
| [`atmosphere-audio.md`](atmosphere-audio.md) | Atmosphere profiles, scares, lighting, room audio zones, adaptive environment | 14, 16, 17, 18 |
| [`planar-capture-examples.md`](planar-capture-examples.md) | Mirrors, horror mirrors, security monitors, void portals, fake windows — all 8 capture surfaces | 17 |
| [`save-checkpoints.md`](save-checkpoints.md) | Save system, checkpoints, death loop, void space, persistence | 15 |
| [`polish-loading-credits.md`](polish-loading-credits.md) | Tutorials, loading screen, credits, debug, analytics | 19, 20 |
| [`state-gating-examples.md`](state-gating-examples.md) | DA_StateGatingTable game-specific rules | 14 |

View File

@@ -0,0 +1,409 @@
# Planar Capture System Examples — Project Void Horror Game
**Game:** Project Void | **Build Phase:** 17e (Capture System Integration)
**Framework Systems:** 136-147 (12 Planar Capture systems)
---
## Purpose
Defines how the Planar Capture System is used in the Project Void horror game — mirrors that show wrong reflections, security monitors that display camera feeds, and void portals that warp reality. Every capture surface mode is demonstrated.
---
## Capture Surface Placement Map
| Surface | Level | Location | Mode | Purpose |
|---------|-------|----------|------|---------|
| `BP_Mirror_NurseStation` | WardA | Nurses Station | Mirror | Checkpoint mirror, also shows player reflection |
| `BP_HorrorMirror_Morgue` | WardB | Morgue | HorrorMirror | Wrong reflection scare (face appears behind player) |
| `BP_HorrorMirror_WardensOffice` | WardensOffice | Above desk | HorrorMirror | Final confrontation — entity speaks through mirror |
| `BP_Monitor_Security` | WardA | Security Office | Monitor | Shows hallway camera feed (live) |
| `BP_Monitor_Morgue` | WardB | Morgue office | Monitor | Shows morgue interior (static noise, flicker) |
| `BP_Portal_VoidEntrance` | Basement | Crematorium | Portal | Void portal — links to BP_Portal_VoidExit in VoidSpace |
| `BP_Portal_VoidExit` | VoidSpace | Memory Shrine 3 | Portal | Exit portal back to Basement |
| `BP_FakeWindow_WardensOffice` | WardensOffice | Window behind desk | FakeWindow | Shows "outside" view (rain, night, distant asylum) |
---
## 1. BP_Mirror_NurseStation — Standard Mirror
**Asset Path:** `Content/Game/Actors/BP_Mirror_NurseStation.uasset`
**Parent:** `BP_Mirror` (139)
**Framework Systems:** 136-139, 144-147
### Level Placement
```
L_Asylum_WardA → Nurses Station
├─ BP_Mirror_NurseStation (640×320 plane, wall-mounted)
├─ Position: Above sink counter, eye-level
├─ Material: MI_Mirror_Dirty (aged, slight oxidation)
├─ MPC params: DirtOpacity=0.3, SurfaceAge=0.2
└─ ProximityTrigger: 1000uu radius
```
### Gameplay Integration
- **Checkpoint:** This mirror doubles as `BP_Checkpoint_Mirror` — player touches it to save
- **Reflection quality:** Player is in a small room → mirror stays at High/Medium tier (close proximity)
- **No horror features** — this is a normal mirror at this point in the game
- **Easter egg:** Player's reflection blinks slightly out of sync (1 in 100 chance, very subtle)
### Blueprint Setup
```
BP_Mirror_NurseStation (child of BP_Mirror)
├─ Class Defaults:
│ ├─ CaptureComponent.CaptureMode = Mirror
│ ├─ CaptureComponent.QualityProfiles[1] = Medium (512px, 15fps, shadows)
│ ├─ CaptureComponent.QualityProfiles[2] = High (1024px, 30fps, Lumen)
│ ├─ SurfaceMesh → SM_WallMirror_640x320
│ └─ SurfaceMaterial → MI_Mirror_Dirty
└─ Event BeginPlay:
├─ SetSurfaceMPCParameter("DirtOpacity", 0.3)
├─ SetSurfaceMPCParameter("SurfaceAge", 0.2)
└─ EnableSurface()
```
---
## 2. BP_HorrorMirror_Morgue — Wrong Reflection Scare
**Asset Path:** `Content/Game/Actors/BP_HorrorMirror_Morgue.uasset`
**Parent:** `BP_HorrorMirror` (142)
**Framework Systems:** 136-138, 142, 144-147 + 101_BPC_ScareEventSystem
### Level Placement
```
L_Asylum_WardB → Morgue
├─ BP_HorrorMirror_Morgue (800×600 plane)
├─ Position: On morgue wall, facing dissection table
├─ Material: MI_Mirror_Horror (horror layers enabled)
├─ WrongReflectionActor: BP_Enemy_Shade placed behind camera (hidden)
└─ Trigger: Player looks at mirror > 2 seconds
```
### Scare Sequence
```
Trigger: BPC_InteractionDetector focus remains on mirror for 2+ seconds
├─ [Anticipation Phase] (5 seconds)
│ ├─ Steam slowly fogs mirror:
│ │ └─ Timeline: SteamIntensity MPC 0.0 → 0.4 over 3s
│ ├─ Audio: SS_AudioManager.PlaySFX("mirror_steam_hiss")
│ ├─ BPC_StressSystem.AddStress(+3) — subtle unease
│ └─ Player is still watching their reflection
├─ [Payoff Phase] (3 seconds)
│ ├─ BPC_ScareEventSystem.TriggerScareEvent("MirrorApparition")
│ │ └─ Coordinates with lights (flicker), audio (stinger)
│ │
│ ├─ CaptureComponent.ActivateHorrorReflection()
│ │ └─ Swaps ShowOnly list from Self to WrongReflectionActor
│ │ └─ Next capture frame: Shade appears in mirror instead of player
│ │
│ ├─ Timeline: WrongReflectionBlend MPC 0.0 → 1.0 over 0.5s (instant crossfade)
│ ├─ Timeline: MirrorDarkness MPC 0.0 → 0.6 (mirror darkens)
│ ├─ Timeline: DistortionAmplitude MPC 0.0 → 0.3 (mirror "breathes")
│ │
│ ├─ Steam text reveal: TextRevealProgress MPC 0.0 → 1.0
│ │ └─ Text "JOIN ME" appears in steam on mirror surface
│ │
│ └─ Audio: SS_AudioManager.PlaySFX("mirror_scare_stinger")
│ └─ Loud glass crack + whisper voice
└─ [Recovery Phase] (3 seconds)
├─ CaptureComponent.DeactivateHorrorReflection()
│ └─ Restores player's reflection
├─ All MPC params return to 0.0 over 1.5s
├─ BPC_StressSystem.AddStress(+15) — spike
└─ Mirror returns to normal (player can continue)
```
### Blueprint Setup
```
BP_HorrorMirror_Morgue (child of BP_HorrorMirror)
├─ Class Defaults:
│ ├─ CaptureComponent.CaptureMode = HorrorMirror
│ ├─ CaptureComponent.WrongReflectionActor = BP_Enemy_Shade_Reflection
│ │ └─ (This Shade instance is placed behind a wall — invisible to player
│ │ but visible to the capture camera due to ShowOnly list)
│ ├─ CaptureComponent.QualityProfiles[2].DelayedFrameCount = 3
│ │ └─ Reflection lags 3 frames at High tier
│ ├─ ScareEventTag = "Game.Environment.Scare.MirrorApparition"
│ └─ ScareDuration = 8.0
├─ Curves:
│ ├─ Curve_WrongReflectionBlend: (0,0) → (0.5,1.0) → (2.5,1.0) → (3.0,0)
│ ├─ Curve_MirrorDarkness: (0,0) → (0.5,0.6) → (2.0,0.4) → (3.0,0)
│ ├─ Curve_UVDistortion: (0,0) → (0.5,0.3) → (1.5,0.15) → (3.0,0)
│ └─ Curve_SteamTextReveal: (1.0,0) → (2.0,1.0) → (3.0,1.0)
└─ Event Graph:
├─ Bind to BPC_InteractionDetector.OnFocusGained
│ └─ If FocusedActor == Self → Start LookTimer (2.0s)
│ └─ On Timer Complete → TriggerHorrorScare()
└─ TriggerHorrorScare() (implemented as described above)
```
---
## 3. BP_Monitor_Security — Security Camera Display
**Asset Path:** `Content/Game/Actors/BP_Monitor_Security.uasset`
**Parent:** `BP_Monitor` (141)
**Framework Systems:** 136-138, 141, 144-147
### Level Placement
```
L_Asylum_WardA → Security Office
├─ BP_Monitor_Security (screen quad on desk)
├─ FixedCameraActor: SecurityCamera_HallwayA (placed in hallway)
├─ Shows live feed of hallway → player can see enemies patrolling
└─ Power: ON by default
```
### Monitor Behavior
```
BP_Monitor_Security
├─ Class Defaults:
│ ├─ CaptureComponent.CaptureMode = Monitor
│ ├─ CaptureComponent.CaptureFOV = 70
│ ├─ CaptureComponent.QualityProfiles[0].CaptureInterval = 0.2 (5fps)
│ │ └─ Security monitors don't need high FPS
│ ├─ CaptureComponent.FixedCameraActor = SecurityCamera_HallwayA
│ └─ SurfaceMaterial → MI_Monitor_Security
├─ Features:
│ ├─ Static noise overlay: StaticNoiseIntensity = 0.1 (subtle grain)
│ ├─ Scanline effect: bShowScanlines = true (CRT-like lines)
│ └─ Power state reacts to fusebox puzzle:
│ ├─ Fusebox power OFF → Monitor flickers and dies (PowerOff)
│ └─ Fusebox power ON → Monitor boots up with flicker (PowerOn)
└─ Narrative hook:
└─ At specific narrative flag ("ShadeEncountered"):
└─ Shade briefly appears on monitor for 1 frame (rare event)
└─ BPC_RareEventSystem check every 30s, 2% chance
```
### Blueprint Setup
```
BP_Monitor_Security (child of BP_Monitor)
├─ Class Defaults:
│ ├─ CaptureComponent.CaptureMode = Monitor
│ ├─ CaptureComponent.CaptureFOV = 70
│ ├─ bPoweredOn = true
│ ├─ bShowScanlines = true
│ ├─ StaticNoiseIntensity = 0.1
│ └─ SurfaceMaterial = MI_Monitor_Security
└─ Event Graph:
├─ Event BeginPlay → EnableSurface
├─ [Bind to fusebox puzzle]
│ ├─ Listen for BPC_UsableWorldObjectSystem.OnActivated (fusebox power)
│ │ └─ PowerOn() (with 1s flicker delay)
│ └─ Listen for BPC_UsableWorldObjectSystem.OnDeactivated
│ └─ PowerOff() (immediate)
└─ [Rare event: Shade on monitor]
└─ Timer (30s loop) → Check narrative flag "ShadeEncountered"
└─ If true → Random Float 0-1 < 0.02
└─ True: Show Shade frame (capture swap to Shade actor for 0.2s)
```
---
## 4. BP_Portal_VoidEntrance / BP_Portal_VoidExit — Void Portal
**Asset Path:** `Content/Game/Actors/BP_Portal_VoidEntrance.uasset`
**Parent:** `BP_Portal` (140)
**Framework Systems:** 136-138, 140, 144-147 + 130_BPC_StateManager
### Level Placement
```
L_Asylum_Basement → Crematorium
├─ BP_Portal_VoidEntrance (wall-mounted portal frame)
├─ LinkedTargetSurface: BP_Portal_VoidExit in L_Asylum_VoidSpace
├─ TeleportOnOverlap: true
├─ Appearance: Shimmering purple-black void surface
└─ Trigger: Player walks into it
```
```
L_Asylum_VoidSpace → Exit Chamber (behind Memory Shrine 3)
├─ BP_Portal_VoidExit (floating portal in void)
├─ LinkedTargetSurface: BP_Portal_VoidEntrance (back to Basement)
├─ Shows: Basement Crematorium view (player's return destination)
└─ Only visible after all 3 Memory Shrines activated
```
### Portal Teleport Flow
```
Player overlaps BP_Portal_VoidEntrance.TeleportTrigger
├─ [Server-authoritative check]
│ └─ Switch HasAuthority
│ ├─ Authority:
│ │ ├─ BPC_StateManager.IsActionPermitted(Framework.Action.Teleport)?
│ │ │ └─ True → proceed
│ │ │ └─ False → Show blocked feedback, return
│ │ │
│ │ ├─ Get LinkedTargetSurface → Get ActorTransform
│ │ ├─ Teleport player: SetActorLocation + SetActorRotation
│ │ │ └─ Offset: targetForward * 300 (spawn 3m in front of exit)
│ │ │
│ │ ├─ [Transition Effects]
│ │ │ ├─ WBP_ScreenEffectController.Flash(purple, 0.5s)
│ │ │ ├─ BPC_CameraStateLayer.PushLayer("PortalTransition", 1.0s)
│ │ │ │ └─ FOV 120 → 90 over 1s, chromatic aberration
│ │ │ └─ SS_AudioManager.PlaySFX("portal_travel")
│ │ │
│ │ └─ Multicast_OnPlayerTeleported (visual feedback for all clients)
│ │
│ └─ Remote (client):
│ └─ Call Server_TeleportThroughPortal RPC
└─
```
### Blueprint Setup
```
BP_Portal_VoidEntrance (child of BP_Portal)
├─ Class Defaults:
│ ├─ CaptureComponent.CaptureMode = Portal
│ ├─ bTeleportOnOverlap = true
│ ├─ bOneWay = false (two-way — player can return)
│ ├─ SurfaceMaterial = MI_Portal_Standard
│ └─ CaptureComponent.QualityProfiles[2].bEnableClipPlane = true
│ └─ Clip plane prevents geometry behind portal from clipping in
├─ Components:
│ ├─ SurfaceMesh (portal plane)
│ ├─ ProximityTrigger (quality scoring, large: 2000uu)
│ └─ TeleportTrigger (overlap detection, same size as surface)
└─ Event Graph:
├─ BeginPlay → EnableSurface → RegisterWithManager
├─ TeleportTrigger.OnComponentBeginOverlap
│ └─ Cast to PlayerCharacter → If valid:
│ └─ HasAuthority → Teleport player
│ └─ Client → Server_TeleportThroughPortal RPC
└─ Server_TeleportThroughPortal (RPC, Reliable, Server)
├─ Validate portal still active
├─ Get LinkedTargetSurface
├─ Teleport player to exit location
└─ Multicast_OnPlayerTeleported (play FX on all clients)
```
---
## 5. BP_FakeWindow_WardensOffice — Atmospheric Window
**Asset Path:** `Content/Game/Actors/BP_FakeWindow_WardensOffice.uasset`
**Parent:** `BP_FakeWindow` (143)
**Framework Systems:** 136-138, 143, 144-147
### Level Placement
```
L_Asylum_WardensOffice → Behind Warden's desk
├─ BP_FakeWindow_WardensOffice (large window frame)
├─ Shows: "Outside" view — rain, night sky, distant asylum building
├─ Weather: Rain overlay based on game state
└─ Parallax: Slight depth effect when player moves
```
### Behavior
```
BP_FakeWindow_WardensOffice
├─ Class Defaults:
│ ├─ CaptureComponent.CaptureMode = FakeWindow
│ ├─ CaptureComponent.CaptureFOV = 100 (wide window view)
│ ├─ CaptureComponent.QualityProfiles[0] = Low (256px, 4fps)
│ │ └─ Window is far from action — low priority
│ └─ SurfaceMaterial → MI_FakeWindow_Interior
├─ Weather Integration:
│ └─ Listen to GS_HorrorGameState.OnGlobalFearChanged
│ ├─ Fear < 0.3: Clear night, distant lights
│ ├─ Fear 0.3-0.6: Light rain, overcast
│ └─ Fear > 0.6: Heavy rain, lightning flashes, dark
└─ Sublevel Streaming:
└─ bStreamSublevelOnProximity = true
├─ Stream in when player within 3000uu
└─ Stream out when player beyond 4000uu
```
---
## Capture Integration Checklist (for Project Void)
### Mirrors
- [ ] Create `BP_Mirror_NurseStation` in WardA Nurses Station
- [ ] Create `BP_HorrorMirror_Morgue` in WardB Morgue
- [ ] Create `BP_HorrorMirror_WardensOffice` in WardensOffice
- [ ] Place `BP_Enemy_Shade_Reflection` (hidden) for morgue horror mirror
- [ ] Create `DA_Scare_MirrorApparition` Data Asset (references BPC_ScareEventSystem)
- [ ] Wire morgue mirror scare to BPC_ScareEventSystem.TriggerScareEvent()
- [ ] Wire audio through SS_AudioManager for mirror crack/steam/whisper sounds
### Monitors
- [ ] Create `BP_Monitor_Security` in WardA Security Office
- [ ] Create `BP_Monitor_Morgue` in WardB Morgue office
- [ ] Place `SecurityCamera_HallwayA` CameraActor in WardA hallway
- [ ] Wire monitor power to fusebox puzzle completion
### Portals
- [ ] Create `BP_Portal_VoidEntrance` in Basement Crematorium
- [ ] Create `BP_Portal_VoidExit` in VoidSpace (behind Memory Shrine 3)
- [ ] Wire portal visibility to Memory Shrine 3 completion
- [ ] Add BPC_StateManager.IsActionPermitted(Teleport) check before teleport
### Fake Windows
- [ ] Create `BP_FakeWindow_WardensOffice` in WardensOffice
- [ ] Create sublevel with window view room + camera
- [ ] Wire weather overlay to GS_HorrorGameState.GlobalFearLevel
### Quality & Performance
- [ ] Test 8 capture surfaces active simultaneously → verify budget enforcement
- [ ] Monitor GPU cost with `stat GPU` in PIE
- [ ] Verify mirrors go Off when player is far away
- [ ] Verify Hero tier assigned to mirror player is looking directly at
---
## Notes for Expansion
- Add **mirror puzzle**: player must look at specific angle in mirror to see hidden key reflected
- Add **portal network**: multiple interconnected portals create non-Euclidean maze
- Add **monitor hacking**: player can switch security cameras to find hidden items
- Add **weather system**: fake windows sync weather with game narrative progression
- Add **mirror memory**: some mirrors show "echoes" of past events (scripted timeline sequences)
- Multiplayer: portals teleport all players; mirrors render each client's own reflection
---
*Planar Capture Examples for Project Void. See [GAMEINDEX.md](GAMEINDEX.md) for full game structure. See [planar-capture-system.md](../architecture/planar-capture-system.md) for architecture spec.*