File size: 5,180 Bytes
e14f09d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
"""
Example 10: Trapcode Particular Iconic Features Showcase
Demonstrates:
1. Auxiliary Particle System (Aux Trails & Secondary Sparkle Dust)
2. Floor Collision & Bounce Physics (Elasticity & Surface Friction)
3. Custom Curves Over Life (Bell, GrowAndFade, Pulse)
4. Layer Mask Emitter (Particle Birth from Image/Logo with Pixel Color Inheritance)
"""

import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

import numpy as np
from PIL import Image, ImageDraw, ImageFont
import particri as pc

output_dir = Path("output")
output_dir.mkdir(exist_ok=True)

print("--- 1. Generating Aux Trails & Floor Bounce Demo ---")
engine_bounce = pc.ParticleEngine(max_particles=35000, width=1920, height=1080)

# Add Floor Bounce Plane at y=920
engine_bounce.add_bounce_plane(coord=920.0, bounce=0.62, friction=0.88, is_horizontal=True, is_max=True)
# Add Gravity & subtle atmospheric drag
engine_bounce.add_gravity(0.0, 180.0)
engine_bounce.add_drag(0.08)
# Add slight curl noise turbulence
engine_bounce.add_curl_noise(seed=42, strength=60.0, frequency=0.002, speed=0.2)

# Primary Emitter: Golden Fountain shooting upwards & outwards
engine_bounce.add_emitter(
    shape=pc.EmitterShape.Circle,
    position=(960.0, 750.0),
    size=(30.0, 30.0),
    rate=180.0,
    speed_range=(250.0, 520.0),
    angle_range=(-2.35, -0.78), # Upward fan
    lifetime_range=(1.8, 3.2),
    size_start_range=(8.0, 18.0),
    size_end_range=(1.0, 3.0),
    color_start=(1.0, 0.9, 0.5, 1.0),
    color_end=(1.0, 0.35, 0.05, 0.0),
    particle_shape=pc.ParticleShape.Star4,
    size_curve=pc.CurveType.GrowAndFade,
    opacity_curve=pc.CurveType.GrowAndFade,
    seed=101,
)

# Auxiliary System: Each falling firework spark leaves shimmering golden dust trails!
engine_bounce.enable_aux_system(
    rate=25.0,                         # 25 child particles per second from each primary particle
    lifetime=1.4,
    size_range=(4.0, 0.5),
    color_start=(1.0, 0.85, 0.3, 0.95),
    color_end=(1.0, 0.2, 0.05, 0.0),
    inherit_color=True,
    velocity_inheritance=0.12,         # Child inherits 12% parent speed
    spread=18.0,                       # Slight jitter
    particle_shape=pc.ParticleShape.Glitter,
    size_curve=pc.CurveType.Bell,      # Peaks in middle, gentle fade
    opacity_curve=pc.CurveType.GrowAndFade,
    emit_at_death=8,                   # 8 sparks burst on particle death
)

# Simulate 3.5 seconds
print("Simulating physics & particle lifecycles...")
engine_bounce.warmup(duration=3.5, step=1.0 / 60.0)
frame_bounce = engine_bounce.render(blend_mode=pc.BlendMode.Additive, bloom=True, bloom_intensity=0.85, bloom_radius=8)
pc.Exporter.save_image(frame_bounce, output_dir / "10_particular_aux_trails_bounce.png")
print(f"Saved: {output_dir / '10_particular_aux_trails_bounce.png'}")


print("\n--- 2. Generating Layer Mask / Logo Emitter Demo ---")
engine_layer = pc.ParticleEngine(max_particles=30000, width=1920, height=1080)

# Create a vibrant synthetic logo image mask (1920x1080) with PIL
logo_img = Image.new("RGBA", (1920, 1080), (0, 0, 0, 0))
draw = ImageDraw.Draw(logo_img)

# Draw central geometric glowing star emblem with gradient rings
cx, cy = 960, 540
# Outer ring (Cyan / Teal)
draw.ellipse([cx - 280, cy - 280, cx + 280, cy + 280], outline=(0, 220, 255, 255), width=8)
# Middle ring (Magenta / Pink)
draw.ellipse([cx - 200, cy - 200, cx + 200, cy + 200], outline=(255, 60, 180, 255), width=6)
# Inner ring (Warm Gold)
draw.ellipse([cx - 120, cy - 120, cx + 120, cy + 120], outline=(255, 215, 80, 255), width=5)

# Central diamond star polygon
def make_star(center_x, center_y, r_outer, r_inner, num_pts=8):
    pts = []
    for i in range(num_pts * 2):
        r = r_outer if i % 2 == 0 else r_inner
        angle = i * np.pi / num_pts - np.pi / 2
        pts.append((center_x + r * np.cos(angle), center_y + r * np.sin(angle)))
    return pts

star_pts = make_star(cx, cy, 100, 35, num_pts=8)
draw.polygon(star_pts, fill=(255, 240, 200, 255), outline=(255, 180, 50, 255))

# Add Layer Emitter to engine with automatic pixel color inheritance!
mask_np = np.asarray(logo_img, dtype=np.float32) / 255.0
engine_layer.add_layer_emitter(
    image=mask_np,
    rate=2800.0,
    speed_range=(8.0, 45.0),
    lifetime_range=(1.2, 3.0),
    size_start_range=(5.0, 14.0),
    size_end_range=(0.0, 2.0),
    particle_shape=pc.ParticleShape.Star8,
    size_curve=pc.CurveType.Bell,
    opacity_curve=pc.CurveType.GrowAndFade,
    inherit_layer_color=True,
    drag=0.18,
    seed=777,
)

# Add subtle vortex swirl around the logo
engine_layer.add_vortex(center=(cx, cy), strength=70.0, radial_pull=-10.0, radius=600.0)
engine_layer.add_curl_noise(seed=999, strength=50.0, frequency=0.003, speed=0.2)

print("Simulating logo layer emission...")
engine_layer.warmup(duration=2.5, step=1.0 / 60.0)
frame_layer = engine_layer.render(blend_mode=pc.BlendMode.Screen, bloom=True, bloom_intensity=0.9, bloom_radius=7)
pc.Exporter.save_image(frame_layer, output_dir / "10_particular_layer_mask_logo.png")
print(f"Saved: {output_dir / '10_particular_layer_mask_logo.png'}")
print("\nAll Trapcode Particular demos generated successfully!")