# 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
