203 lines
10 KiB
Python
203 lines
10 KiB
Python
import math
|
|
import numpy as np
|
|
from PIL import Image, ImageDraw, ImageFilter
|
|
|
|
SIZE = 1024
|
|
CENTER = SIZE / 2.0
|
|
|
|
# 1. ПРИРОДНЫЙ ЧИСТЫЙ КОСМОС ИНТЕРСТЕЛЛАРА С НУЛЯ (БЕЗ РУН, БЕЗ СТАРЫХ КАРТИНОК)
|
|
# Создаем процедурный глубокий космос с мягким галактическим рукавом и аккреционным диском
|
|
bg = Image.new('RGBA', (SIZE, SIZE), (2, 3, 10, 255))
|
|
|
|
# Плавная галактическая дымка (пылевые туманности)
|
|
galaxy_arm = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
|
|
gdraw = ImageDraw.Draw(galaxy_arm)
|
|
|
|
# Наклонный галактический рукав (Млечный путь / Интерстеллар)
|
|
for r in range(12):
|
|
angle = math.radians(-35)
|
|
cx = CENTER + (r - 6) * 40 * math.cos(angle + math.pi/2)
|
|
cy = CENTER + (r - 6) * 40 * math.sin(angle + math.pi/2)
|
|
w = 550 - abs(r - 6) * 35
|
|
h = 220 - abs(r - 6) * 15
|
|
col = (35, 20, 65, 50) if r % 2 == 0 else (15, 45, 85, 55)
|
|
gdraw.ellipse([cx - w, cy - h, cx + w, cy + h], fill=col)
|
|
|
|
galaxy_arm = galaxy_arm.filter(ImageFilter.GaussianBlur(90))
|
|
bg = Image.alpha_composite(bg, galaxy_arm)
|
|
|
|
# Золотой аккреционный ореол вокруг центрального горизонта событий
|
|
accretion = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
|
|
adraw = ImageDraw.Draw(accretion)
|
|
# Эллипс гравитационного линзирования
|
|
adraw.ellipse([CENTER - 380, CENTER - 260, CENTER + 380, CENTER + 260], fill=(220, 130, 25, 45))
|
|
adraw.ellipse([CENTER - 280, CENTER - 280, CENTER + 280, CENTER + 280], fill=(255, 170, 40, 55))
|
|
accretion = accretion.filter(ImageFilter.GaussianBlur(60))
|
|
bg = Image.alpha_composite(bg, accretion)
|
|
|
|
# Мягкие круглые звёзды (настоящие гауссовы сферы разного размера, БЕЗ крестиков)
|
|
stars = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
|
|
sdraw = ImageDraw.Draw(stars)
|
|
np.random.seed(137)
|
|
for _ in range(500):
|
|
x = float(np.random.randint(0, SIZE))
|
|
y = float(np.random.randint(0, SIZE))
|
|
# Плотнее к краям и галактике, чисто в центре
|
|
dist = math.hypot(x - CENTER, y - CENTER)
|
|
if dist < 120 and np.random.rand() > 0.15:
|
|
continue
|
|
rad = np.random.choice([0.8, 1.2, 1.8, 2.8], p=[0.7, 0.2, 0.08, 0.02])
|
|
br = np.random.randint(140, 255)
|
|
t_options = [(255, 255, 255), (180, 220, 255), (255, 235, 190)]; tint = t_options[np.random.randint(0, len(t_options))]
|
|
sdraw.ellipse([x - rad, y - rad, x + rad, y + rad], fill=tint + (br,))
|
|
|
|
stars_bloom = stars.filter(ImageFilter.GaussianBlur(2))
|
|
bg = Image.alpha_composite(bg, stars)
|
|
bg = Image.alpha_composite(bg, stars_bloom)
|
|
|
|
# 2. СТРОГО 13 ПЛАВНЫХ ЛЕПЕСТКОВ СВЕТА (ТРИДЕКАГРАММА)
|
|
N_POINTS = 13
|
|
R_TIP = SIZE * 0.465
|
|
R_INNER = SIZE * 0.28
|
|
R_MEDALLION = SIZE * 0.255
|
|
R_CORE = SIZE * 0.092
|
|
start_angle = -math.pi / 2.0 # Верхний луч строго вертикально на 12 часов
|
|
|
|
tips = [(CENTER + R_TIP * math.cos(start_angle + i * 2 * math.pi / N_POINTS),
|
|
CENTER + R_TIP * math.sin(start_angle + i * 2 * math.pi / N_POINTS)) for i in range(N_POINTS)]
|
|
valleys = [(CENTER + R_INNER * math.cos(start_angle + (i + 0.5) * 2 * math.pi / N_POINTS),
|
|
CENTER + R_INNER * math.sin(start_angle + (i + 0.5) * 2 * math.pi / N_POINTS)) for i in range(N_POINTS)]
|
|
|
|
# Создаем сглаженный суперсэмплинг (для идеального антиалиасинга)
|
|
star_glow = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
|
|
sgdraw = ImageDraw.Draw(star_glow)
|
|
|
|
star_lines = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
|
|
sldraw = ImageDraw.Draw(star_lines)
|
|
|
|
for i in range(N_POINTS):
|
|
p_tip = tips[i]
|
|
p_vl = valleys[(i - 1) % N_POINTS]
|
|
p_vr = valleys[i]
|
|
ang_tip = start_angle + i * 2 * math.pi / N_POINTS
|
|
ang_vl = ang_tip - math.pi / N_POINTS
|
|
ang_vr = ang_tip + math.pi / N_POINTS
|
|
|
|
# Мягкий изгиб лепестка пламени Безье
|
|
ctrl_r = (R_TIP + R_INNER) * 0.49
|
|
p_cl = (CENTER + ctrl_r * math.cos((ang_tip + ang_vl)*0.5 + 0.025), CENTER + ctrl_r * math.sin((ang_tip + ang_vl)*0.5 + 0.025))
|
|
p_cr = (CENTER + ctrl_r * math.cos((ang_tip + ang_vr)*0.5 - 0.025), CENTER + ctrl_r * math.sin((ang_tip + ang_vr)*0.5 - 0.025))
|
|
|
|
steps = 35
|
|
pts_l = [((1-t)**2 * p_vl[0] + 2*(1-t)*t * p_cl[0] + t**2 * p_tip[0],
|
|
(1-t)**2 * p_vl[1] + 2*(1-t)*t * p_cl[1] + t**2 * p_tip[1]) for t in np.linspace(0, 1, steps)]
|
|
pts_r = [((1-t)**2 * p_tip[0] + 2*(1-t)*t * p_cr[0] + t**2 * p_vr[0],
|
|
(1-t)**2 * p_tip[1] + 2*(1-t)*t * p_cr[1] + t**2 * p_vr[1]) for t in np.linspace(0, 1, steps)]
|
|
|
|
poly = [(CENTER, CENTER)] + pts_l + pts_r
|
|
# Объемное свечение тела лепестка
|
|
sgdraw.polygon(poly, fill=(255, 160, 40, 60))
|
|
|
|
# Плавные контуры света (широкое мягкое сияние + яркая золотая нить + платиновый блик)
|
|
for edge in [pts_l, pts_r]:
|
|
for p in range(len(edge) - 1):
|
|
sgdraw.line([edge[p], edge[p+1]], fill=(255, 175, 40, 140), width=8)
|
|
sldraw.line([edge[p], edge[p+1]], fill=(255, 230, 120, 240), width=3)
|
|
sldraw.line([edge[p], edge[p+1]], fill=(255, 255, 240, 255), width=1)
|
|
|
|
# Мягкое внутреннее ребро луча
|
|
sldraw.line([CENTER, CENTER, p_tip[0], p_tip[1]], fill=(255, 250, 200, 210), width=2)
|
|
# Мягкий оптический шарик света на вершине луча (НЕ крестик!)
|
|
sldraw.ellipse([p_tip[0]-3, p_tip[1]-3, p_tip[0]+3, p_tip[1]+3], fill=(255, 255, 255, 255))
|
|
|
|
# 3. ВНУТРЕННИЙ ПОРТАЛ (КОЛЬЦО И ГОРИЗОНТ СОБЫТИЙ)
|
|
med = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
|
|
mdraw = ImageDraw.Draw(med)
|
|
|
|
# Глубокий обсидиановый портал (черная дыра Интерстеллара)
|
|
mdraw.ellipse([CENTER - R_MEDALLION, CENTER - R_MEDALLION, CENTER + R_MEDALLION, CENTER + R_MEDALLION], fill=(1, 2, 7, 245), outline=(255, 215, 70, 255), width=4)
|
|
mdraw.ellipse([CENTER - R_MEDALLION - 3, CENTER - R_MEDALLION - 3, CENTER + R_MEDALLION + 3, CENTER + R_MEDALLION + 3], outline=(60, 200, 255, 180), width=2)
|
|
mdraw.ellipse([CENTER - R_MEDALLION + 6, CENTER - R_MEDALLION + 6, CENTER + R_MEDALLION - 6, CENTER + R_MEDALLION - 6], outline=(255, 240, 160, 160), width=1)
|
|
|
|
# 4. CHROME TRISKELION: ИДЕАЛЬНО ЧИСТЫЕ ШЕЛКОВИСТЫЕ ДЕВЯТКИ С ЗАВИТУШКАМИ (БЕЗ РУН!)
|
|
# Центральное кольцо (общее ядро всех трех 9)
|
|
mdraw.ellipse([CENTER - R_CORE, CENTER - R_CORE, CENTER + R_CORE, CENTER + R_CORE], fill=(0, 1, 5, 255), outline=(255, 225, 90, 255), width=5)
|
|
mdraw.ellipse([CENTER - R_CORE + 4, CENTER - R_CORE + 4, CENTER + R_CORE - 4, CENTER + R_CORE - 4], outline=(80, 220, 255, 200), width=2)
|
|
|
|
trisk_glow = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
|
|
tdraw_glow = ImageDraw.Draw(trisk_glow)
|
|
|
|
for k in range(3):
|
|
rot = start_angle + k * (2.0 * math.pi / 3.0)
|
|
outer = []
|
|
inner = []
|
|
steps = 80
|
|
for s in range(steps + 1):
|
|
t = s / float(steps)
|
|
t_curv = 0.5 * (1.0 - math.cos(t * math.pi))
|
|
cr = R_CORE + t_curv * (R_MEDALLION - R_CORE - 10)
|
|
ca = rot + t * 1.50
|
|
|
|
bx = CENTER + cr * math.cos(ca)
|
|
by = CENTER + cr * math.sin(ca)
|
|
outer.append((bx, by))
|
|
|
|
thick = math.sin(t * math.pi) * 16.0
|
|
ir = max(R_CORE, cr - thick)
|
|
inner.append((CENTER + ir * math.cos(ca + 0.08), CENTER + ir * math.sin(ca + 0.08)))
|
|
|
|
ribbon = outer + inner[::-1]
|
|
# Чистый шелковистый градиентный залив без единого знака/руны
|
|
tdraw_glow.polygon(ribbon, fill=(255, 175, 40, 170))
|
|
|
|
# Плавные контурные линии
|
|
for p in range(len(outer) - 1):
|
|
tdraw_glow.line([outer[p], outer[p+1]], fill=(255, 190, 40, 220), width=7)
|
|
mdraw.line([outer[p], outer[p+1]], fill=(255, 255, 235, 255), width=3)
|
|
mdraw.line([outer[p], outer[p+1]], fill=(255, 255, 255, 255), width=1)
|
|
for p in range(len(inner) - 1):
|
|
mdraw.line([inner[p], inner[p+1]], fill=(60, 200, 255, 200), width=2)
|
|
|
|
# Изящный спиральный завиток девяточки (закручивается вовнутрь)
|
|
tip_pt = outer[-1]
|
|
tip_ang = rot + 1.50
|
|
flourish = []
|
|
for f in range(30):
|
|
ft = f / 29.0
|
|
# Логарифмическая спираль завитушки
|
|
f_r = 16.0 * (1.0 - ft * 0.75)
|
|
f_a = tip_ang + ft * math.pi * 1.7
|
|
fx = tip_pt[0] + f_r * math.cos(f_a) - 16.0 * math.cos(tip_ang)
|
|
fy = tip_pt[1] + f_r * math.sin(f_a) - 16.0 * math.sin(tip_ang)
|
|
flourish.append((fx, fy))
|
|
|
|
for p in range(len(flourish) - 1):
|
|
tdraw_glow.line([flourish[p], flourish[p+1]], fill=(255, 190, 40, 190), width=5)
|
|
mdraw.line([flourish[p], flourish[p+1]], fill=(255, 255, 255, 255), width=2)
|
|
|
|
# Центр сингулярности: гладкий фотонный светящийся шар (НЕ крестик!)
|
|
core_spark = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
|
|
cdraw = ImageDraw.Draw(core_spark)
|
|
for r_c in range(24, 0, -2):
|
|
alpha = int(255 * (1.0 - r_c / 24.0)**1.5)
|
|
cdraw.ellipse([CENTER - r_c, CENTER - r_c, CENTER + r_c, CENTER + r_c], fill=(255, 250, 230, alpha))
|
|
# Нежная оптическая горизонтальная анаморфотная нить света (киношный Interstellar lens flare)
|
|
for dx in range(-120, 120):
|
|
fade = 1.0 - (abs(dx) / 120.0)**2
|
|
cdraw.ellipse([CENTER + dx - 1, CENTER - 1, CENTER + dx + 1, CENTER + 1], fill=(180, 235, 255, int(180 * fade)))
|
|
|
|
# Сборка композиции
|
|
comp = Image.alpha_composite(bg, star_glow.filter(ImageFilter.GaussianBlur(14)))
|
|
comp = Image.alpha_composite(comp, trisk_glow.filter(ImageFilter.GaussianBlur(10)))
|
|
comp = Image.alpha_composite(comp, star_lines)
|
|
comp = Image.alpha_composite(comp, med)
|
|
comp = Image.alpha_composite(comp, core_spark)
|
|
|
|
# Финальный мягкий кинематографический Bloom
|
|
bloom = comp.filter(ImageFilter.GaussianBlur(8))
|
|
final_img = Image.blend(comp, bloom, 0.22)
|
|
|
|
out_file = '/home/alexives/.gemini/antigravity-ide/brain/4ff924d9-3d7f-4202-9066-3ac5c3088b8e/star_13_interstellar_pure_magic.png'
|
|
final_img.save(out_file, 'PNG')
|
|
print("Successfully generated PURE INTERSTELLAR 13-STAR at", out_file)
|