add Wide Gate Leak (Asymmetric Bar) with sharp metal gate shadow, gap breaks, and multi-strip leaks inspired by reference photos
This commit is contained in:
@@ -147,8 +147,9 @@ Simulates physical camera optical lens falloff, film gate framing, and procedura
|
||||
## Features
|
||||
- **Procedural Organic Light Leaks**: Generated entirely via PyTorch tensor math—no overlay images required! Features core temperature saturation (`C-41 Fiery Core Flare` transitioning from deep red-orange to white-hot yellow cores), `Tungsten Blue Burn`, `Vintage Magenta Leak`, `Sunburst Golden Flare`, `Rainbow Prism Flare`, `Dual-Tone Cyan & Amber`, and `Random Organic Multi-Layer`.
|
||||
- **Realistic Film Burn Patterns**: Modeled directly after authentic analog camera light leaks:
|
||||
* **`Wide Gate Leak (Asymmetric Bar)`**: Asymmetric wide vertical light band with a sharp right edge boundary (metal film gate shadow), soft left gradient, vertical intensity modulation, mid-strip gap breaks, and a secondary sub-strip flare on the opposite edge.
|
||||
* **`Vertical Curtain Gap`**: Vertical light seam running top-to-bottom with soft edge gradients and vertical intensity fluctuations.
|
||||
* **`Bottom Frame Burn`**: Fiery upward orange/yellow light flare originating from the bottom edge of the film frame.
|
||||
* **`Vertical Curtain Gap`**: Thin vertical light seam running top-to-bottom caused by degraded camera back door gaskets.
|
||||
* **`Dual-Edge Cross Burn`**: Multi-layer opposing leaks (warm bottom flare combined with cool upper corner burn).
|
||||
* **`Random / Scattered`**, `Center Specular Flare`, `Diagonal Streak`, `Sprocket Hole Leaks`, corners, and edge strips.
|
||||
- **Seed-Driven Spatial & Organic Randomness**: Setting a seed dynamically randomizes center offsets, ellipse scale/aspect ratios, and non-uniform organic burn cloud shapes!
|
||||
|
||||
+72
-11
@@ -37,8 +37,9 @@ class AfterDarkFilmOpticsArtifacts:
|
||||
"leak_location": (
|
||||
[
|
||||
"Random / Scattered",
|
||||
"Bottom Frame Burn",
|
||||
"Wide Gate Leak (Asymmetric Bar)",
|
||||
"Vertical Curtain Gap",
|
||||
"Bottom Frame Burn",
|
||||
"Dual-Edge Cross Burn",
|
||||
"Top Left Corner",
|
||||
"Top Right Corner",
|
||||
@@ -156,50 +157,110 @@ class AfterDarkFilmOpticsArtifacts:
|
||||
low_noise = torch.rand((1, 1, 8, 8), device=device, dtype=dtype, generator=generator)
|
||||
noise_cloud = F.interpolate(low_noise, size=(H, W), mode="bicubic", align_corners=False).squeeze()
|
||||
|
||||
# Primary Leak Distance Geometry Calculation
|
||||
if leak_location == "Bottom Frame Burn":
|
||||
# Primary Leak Distance & Mask Geometry Calculation
|
||||
if leak_location in ("Wide Gate Leak (Asymmetric Bar)", "Vertical Curtain Gap"):
|
||||
# Inspired directly by user reference images (Image 1 & 2):
|
||||
# 1. Asymmetric sharp right gate edge (shadow of metal gate) + soft left bleed
|
||||
# 2. Vertical intensity modulation & gap break in upper-middle
|
||||
# 3. Secondary subtle strip on opposite edge
|
||||
bar_center = 0.60 + jitter_x * 0.4 if leak_location == "Wide Gate Leak (Asymmetric Bar)" else 0.75 + jitter_x * 0.4
|
||||
bar_width = 0.22 * scale_x if leak_location == "Wide Gate Leak (Asymmetric Bar)" else 0.08 * scale_x
|
||||
|
||||
dx = (grid_x - bar_center) / max(bar_width, 0.01)
|
||||
|
||||
# Asymmetric sharp drop-off on right edge vs smooth bleed on left edge
|
||||
left_edge = torch.clamp((dx + 1.0) * 3.0, 0.0, 1.0)
|
||||
right_edge = torch.clamp(1.0 - (dx - 0.2) * 14.0, 0.0, 1.0)
|
||||
asymmetric_profile = left_edge * right_edge
|
||||
|
||||
# Vertical intensity modulation & gap break (inspired by Image 1 break in upper middle)
|
||||
vert_modulation = 0.55 + 0.45 * torch.sin(grid_y * 3.14159 * 2.5 + jitter_y * 10.0)
|
||||
gap_break = torch.clamp(1.0 - torch.exp(-((grid_y - (0.35 + jitter_y * 0.2))**2) / 0.015) * 0.85, 0.15, 1.0)
|
||||
|
||||
bar_mask = asymmetric_profile * vert_modulation * gap_break
|
||||
|
||||
# Secondary thin strip on opposite side (like Image 1 near bus!)
|
||||
sec_x = 0.15 - jitter_x * 0.3
|
||||
sec_dist = torch.abs(grid_x - sec_x) / 0.06
|
||||
sec_mask = torch.exp(-(sec_dist**2) / 0.35) * 0.35 * vert_modulation
|
||||
|
||||
outer_mask = torch.clamp(bar_mask + sec_mask, 0.0, 1.0) * (0.75 + 0.25 * noise_cloud)
|
||||
core_mask = torch.clamp(bar_mask - 0.35, 0.0, 1.0) * (1.0 - grid_y) * 1.5 # Hot bottom core
|
||||
dist = torch.sqrt(torch.clamp(1.0 - outer_mask, 1e-4, 1.0))
|
||||
|
||||
elif leak_location == "Bottom Frame Burn":
|
||||
# Inspired by Ref Image 1 & 3: Upward fiery flare from bottom edge with uneven height
|
||||
dist_y = torch.clamp(1.0 - grid_y - jitter_y, 0.0, 1.0) / scale_y
|
||||
dist_x = torch.abs(grid_x - (0.4 + jitter_x)) / scale_x
|
||||
dist = torch.sqrt(dist_x**2 + dist_y**2)
|
||||
elif leak_location == "Vertical Curtain Gap":
|
||||
# Inspired by Ref Image 4: Thin vertical light bar along door seal
|
||||
bar_x = 0.20 + jitter_x
|
||||
dist = torch.abs(grid_x - bar_x) / (0.15 * scale_x)
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
elif leak_location == "Dual-Edge Cross Burn":
|
||||
# Inspired by Ref Image 2: Two opposing leaks (bottom flare + top corner leak)
|
||||
dist1 = torch.sqrt(((grid_x - (0.1 + jitter_x)) / scale_x)**2 + ((grid_y - (0.9 + jitter_y)) / scale_y)**2)
|
||||
dist2 = torch.sqrt(((grid_x - (0.9 - jitter_x)) / scale_x)**2 + ((grid_y - (0.1 - jitter_y)) / scale_y)**2)
|
||||
dist = torch.min(dist1, dist2)
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
elif leak_location == "Random / Scattered":
|
||||
cx = 0.5 + jitter_x
|
||||
cy = 0.5 + jitter_y
|
||||
dist = torch.sqrt(((grid_x - cx) / scale_x)**2 + ((grid_y - cy) / scale_y)**2)
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
elif leak_location == "Top Left Corner":
|
||||
dist = torch.sqrt(((grid_x - (0.0 + jitter_x)) / scale_x)**2 + ((grid_y - (0.0 + jitter_y)) / scale_y)**2)
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
elif leak_location == "Top Right Corner":
|
||||
dist = torch.sqrt(((grid_x - (1.0 + jitter_x)) / scale_x)**2 + ((grid_y - (0.0 + jitter_y)) / scale_y)**2)
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
elif leak_location == "Bottom Left Corner":
|
||||
dist = torch.sqrt(((grid_x - (0.0 + jitter_x)) / scale_x)**2 + ((grid_y - (1.0 + jitter_y)) / scale_y)**2)
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
elif leak_location == "Bottom Right Corner":
|
||||
dist = torch.sqrt(((grid_x - (1.0 + jitter_x)) / scale_x)**2 + ((grid_y - (1.0 + jitter_y)) / scale_y)**2)
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
elif leak_location == "Left Edge Strip":
|
||||
dist = torch.abs(grid_x - (0.0 + jitter_x)) / scale_x
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
elif leak_location == "Right Edge Strip":
|
||||
dist = torch.abs(grid_x - (1.0 + jitter_x)) / scale_x
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
elif leak_location == "Center Specular Flare":
|
||||
dist = torch.sqrt(((grid_x - 0.5) / scale_x)**2 + ((grid_y - 0.5) / scale_y)**2)
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
elif leak_location == "Diagonal Streak":
|
||||
dist = torch.abs((grid_x + grid_y) / 1.414 - (0.7 + jitter_x)) / scale_x
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
elif leak_location == "Sprocket Hole Leaks":
|
||||
sprocket_freq = torch.sin(grid_y * 3.14159 * 12.0) ** 4
|
||||
dist = torch.clamp((torch.min(grid_x, 1.0 - grid_x) * 4.0) + (1.0 - sprocket_freq) * 0.5, 0.0, 2.0)
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
else:
|
||||
dist = torch.sqrt((1.0 - grid_x)**2 + grid_y**2)
|
||||
|
||||
# C-infinity mathematically smooth Gaussian falloff mask
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask # Hot core saturation
|
||||
outer_mask = torch.exp(-(dist ** 2) / 0.35) * (0.80 + 0.20 * noise_cloud)
|
||||
core_mask = torch.exp(-(dist ** 2) / 0.06) * outer_mask
|
||||
|
||||
# Spectral color gradient blending (Outer Fringe -> White Hot Core)
|
||||
if light_leak_style == "Rainbow Prism Flare":
|
||||
|
||||
Reference in New Issue
Block a user