275 lines
12 KiB
Python
275 lines
12 KiB
Python
import math
|
|
import numpy as np
|
|
from PIL import Image, ImageDraw, ImageFilter
|
|
|
|
HI_SIZE = 4096
|
|
OUT_SIZE = 1024
|
|
CENTER = HI_SIZE / 2.0
|
|
|
|
# 1. ГЛУБОКИЙ КИНЕМАТОГРАФИЧЕСКИЙ КОСМОС: БОГАТЫЕ ГРАДИЕНТЫ И НЕБУЛЫ
|
|
bg = Image.new('RGBA', (HI_SIZE, HI_SIZE), (3, 3, 12, 255))
|
|
|
|
# Многослойная туманность (пурпурно-маджентовые и лазурные облака)
|
|
nebula = Image.new('RGBA', (HI_SIZE, HI_SIZE), (0, 0, 0, 0))
|
|
ndraw = ImageDraw.Draw(nebula)
|
|
|
|
# Спиральные рукава галактики
|
|
for arm in range(3):
|
|
arm_angle = arm * (2.0 * math.pi / 3.0)
|
|
for step in range(80):
|
|
t = step / 79.0
|
|
ang = arm_angle + t * math.pi * 1.5
|
|
dist = 120 + t * (HI_SIZE * 0.46)
|
|
cx = CENTER + dist * math.cos(ang)
|
|
cy = CENTER + dist * math.sin(ang)
|
|
r_cloud = 260 + t * 380
|
|
|
|
# Градиент: глубокий аметист -> сияющая маджента -> космический ультрамарин -> бирюза
|
|
if t < 0.33:
|
|
col = (75, 15, 90, int(50 * (1 - t)))
|
|
elif t < 0.66:
|
|
col = (30, 45, 120, int(55 * (1 - t*0.8)))
|
|
else:
|
|
col = (10, 85, 125, int(45 * (1 - t*0.8)))
|
|
|
|
ndraw.ellipse([cx - r_cloud, cy - r_cloud*0.75, cx + r_cloud, cy + r_cloud*0.75], fill=col)
|
|
|
|
nebula = nebula.filter(ImageFilter.GaussianBlur(280))
|
|
bg = Image.alpha_composite(bg, nebula)
|
|
|
|
# Золотой аккреционный вихрь Интерстеллара
|
|
accretion = Image.new('RGBA', (HI_SIZE, HI_SIZE), (0, 0, 0, 0))
|
|
adraw = ImageDraw.Draw(accretion)
|
|
|
|
# Наклонный эллипс аккреционного диска
|
|
for i in range(20):
|
|
t = i / 19.0
|
|
w = 1800 - t * 700
|
|
h = 650 - t * 280
|
|
alpha = int(60 * (1.0 - t**1.4))
|
|
adraw.ellipse([CENTER - w, CENTER - h, CENTER + w, CENTER + h], fill=(240, 130 + int(t*40), 30 + int(t*50), alpha))
|
|
|
|
# Центральная светящаяся корона
|
|
adraw.ellipse([CENTER - 1100, CENTER - 1100, CENTER + 1100, CENTER + 1100], fill=(255, 160, 40, 40))
|
|
adraw.ellipse([CENTER - 750, CENTER - 750, CENTER + 750, CENTER + 750], fill=(255, 205, 75, 50))
|
|
accretion = accretion.filter(ImageFilter.GaussianBlur(190))
|
|
bg = Image.alpha_composite(bg, accretion)
|
|
|
|
# Мерцающие цветные звезды
|
|
np.random.seed(999)
|
|
stars = Image.new('RGBA', (HI_SIZE, HI_SIZE), (0, 0, 0, 0))
|
|
sdraw = ImageDraw.Draw(stars)
|
|
for _ in range(700):
|
|
sx = np.random.uniform(40, HI_SIZE - 40)
|
|
sy = np.random.uniform(40, HI_SIZE - 40)
|
|
rad = np.random.uniform(2, 9)
|
|
alpha = np.random.randint(50, 220)
|
|
tints = [(255, 255, 255), (255, 225, 165), (185, 230, 255), (255, 195, 225)]
|
|
tint = tints[np.random.randint(len(tints))]
|
|
sdraw.ellipse([sx - rad, sy - rad, sx + rad, sy + rad], fill=(*tint, alpha))
|
|
|
|
stars = stars.filter(ImageFilter.GaussianBlur(3))
|
|
bg = Image.alpha_composite(bg, stars)
|
|
|
|
|
|
# 2. ОРГАНИЧЕСКИЙ ТРИСКЕЛИОН: БЕСШОВНОЕ ПЕРЕТЕКАНИЕ ШЕСТЕРОК/ДЕВЯТОК В ОКРУЖАЮЩИЕ ЛЕНТЫ
|
|
# Никаких резких обрывов или острых стыков!
|
|
trisk_glow = Image.new('RGBA', (HI_SIZE, HI_SIZE), (0, 0, 0, 0))
|
|
tgdraw = ImageDraw.Draw(trisk_glow)
|
|
|
|
trisk_body = Image.new('RGBA', (HI_SIZE, HI_SIZE), (0, 0, 0, 0))
|
|
tbdraw = ImageDraw.Draw(trisk_body)
|
|
|
|
silk_threads = Image.new('RGBA', (HI_SIZE, HI_SIZE), (0, 0, 0, 0))
|
|
st_draw = ImageDraw.Draw(silk_threads)
|
|
|
|
R_RING = HI_SIZE * 0.092
|
|
|
|
# 3 шестерки/девятки, плавно вытекающие из кольца и разворачивающиеся в мягкие светящиеся локоны
|
|
for k in range(3):
|
|
base_rot = -math.pi / 2.0 + k * (2.0 * math.pi / 3.0)
|
|
|
|
# Плавная траектория ленты
|
|
pts = []
|
|
widths = []
|
|
|
|
steps = 110
|
|
for s in range(steps):
|
|
t = s / float(steps - 1)
|
|
# Угол раскручивается
|
|
ang = base_rot - 0.5 + t * 2.35
|
|
# Радиус плавно нарастает от кольца
|
|
smooth_t = t * t * (3 - 2 * t)
|
|
rad = R_RING + smooth_t * (HI_SIZE * 0.190)
|
|
|
|
px = CENTER + rad * math.cos(ang)
|
|
py = CENTER + rad * math.sin(ang)
|
|
pts.append((px, py))
|
|
|
|
# Лента плавная: 42px на кольце, плавно тает до 16px на завитке, кончик МЯГКИЙ
|
|
w = 44.0 * (1.0 - smooth_t * 0.60)
|
|
widths.append(w)
|
|
|
|
# Скругленная раковина-завитушка на конце
|
|
tip = pts[-1]
|
|
tip_ang = base_rot - 0.5 + 2.35
|
|
for f in range(50):
|
|
ft = f / 49.0
|
|
f_r = 85.0 * (1.0 - ft * 0.8)
|
|
f_a = tip_ang + ft * math.pi * 1.85
|
|
fx = tip[0] + f_r * math.cos(f_a) - 85.0 * math.cos(tip_ang)
|
|
fy = tip[1] + f_r * math.sin(f_a) - 85.0 * math.sin(tip_ang)
|
|
pts.append((fx, fy))
|
|
widths.append(max(9.0, 16.0 * (1.0 - ft * 0.45)))
|
|
|
|
# Каллиграфическая лента
|
|
left = []
|
|
right = []
|
|
for i in range(len(pts)):
|
|
p = pts[i]
|
|
w = widths[i] / 2.0
|
|
if i == 0:
|
|
dx = pts[1][0] - p[0]
|
|
dy = pts[1][1] - p[1]
|
|
elif i == len(pts) - 1:
|
|
dx = p[0] - pts[i-1][0]
|
|
dy = p[1] - pts[i-1][1]
|
|
else:
|
|
dx = pts[i+1][0] - pts[i-1][0]
|
|
dy = pts[i+1][1] - pts[i-1][1]
|
|
length = math.hypot(dx, dy) + 1e-6
|
|
nx = -dy / length
|
|
ny = dx / length
|
|
left.append((p[0] + nx * w, p[1] + ny * w))
|
|
right.append((p[0] - nx * w, p[1] - ny * w))
|
|
|
|
poly = left + right[::-1]
|
|
tgdraw.polygon(poly, fill=(255, 175, 35, 210))
|
|
tbdraw.polygon(poly, fill=(255, 235, 125, 250))
|
|
|
|
# Внутренний шелковый сердечник
|
|
for p in range(len(pts) - 1):
|
|
st_draw.line([pts[p], pts[p+1]], fill=(255, 255, 255, 255), width=9)
|
|
|
|
# Единое кольцо (бесшовный общий исток для трех девяток)
|
|
tgdraw.ellipse([CENTER - R_RING, CENTER - R_RING, CENTER + R_RING, CENTER + R_RING], outline=(255, 175, 35, 230), width=48)
|
|
tbdraw.ellipse([CENTER - R_RING, CENTER - R_RING, CENTER + R_RING, CENTER + R_RING], outline=(255, 238, 128, 255), width=26)
|
|
st_draw.ellipse([CENTER - R_RING, CENTER - R_RING, CENTER + R_RING, CENTER + R_RING], outline=(255, 255, 255, 255), width=8)
|
|
|
|
|
|
# 3. 13 МЯГКИХ СКРУГЛЕННЫХ ЛЕПЕСТКОВ СВЕТА (ОРГАНИЧЕСКИЙ ЦВЕТОК ЖИЗНИ, НИКАКИХ ОСТРЫХ ИГЛ)
|
|
petals_glow = Image.new('RGBA', (HI_SIZE, HI_SIZE), (0, 0, 0, 0))
|
|
pgdraw = ImageDraw.Draw(petals_glow)
|
|
|
|
petals_body = Image.new('RGBA', (HI_SIZE, HI_SIZE), (0, 0, 0, 0))
|
|
pbdraw = ImageDraw.Draw(petals_body)
|
|
|
|
N_POINTS = 13
|
|
R_OUT = HI_SIZE * 0.435
|
|
R_IN = HI_SIZE * 0.180
|
|
R_WAIST = HI_SIZE * 0.300
|
|
|
|
angles = [(-math.pi / 2.0) + (2.0 * math.pi * i / N_POINTS) for i in range(N_POINTS)]
|
|
|
|
for i in range(N_POINTS):
|
|
a = angles[i]
|
|
# Вершина лепестка - МЯГКАЯ ДУГА, а не острый угол
|
|
tip_center = (CENTER + R_OUT * math.cos(a), CENTER + R_OUT * math.sin(a))
|
|
|
|
# Левый и правый бока лепестка расширяются и плавно сходятся
|
|
half_a = (math.pi / N_POINTS) * 0.75
|
|
|
|
ctrl_l = (CENTER + R_WAIST * math.cos(a - half_a * 0.8), CENTER + R_WAIST * math.sin(a - half_a * 0.8))
|
|
ctrl_r = (CENTER + R_WAIST * math.cos(a + half_a * 0.8), CENTER + R_WAIST * math.sin(a + half_a * 0.8))
|
|
|
|
base_l = (CENTER + R_IN * math.cos(a - half_a * 0.5), CENTER + R_IN * math.sin(a - half_a * 0.5))
|
|
base_r = (CENTER + R_IN * math.cos(a + half_a * 0.5), CENTER + R_IN * math.sin(a + half_a * 0.5))
|
|
|
|
# Строим скругленный контур лепестка через Безье
|
|
side_l = []
|
|
side_r = []
|
|
for step in range(35):
|
|
t = step / 34.0
|
|
lx = (1-t)**2 * base_l[0] + 2*(1-t)*t * ctrl_l[0] + t**2 * tip_center[0]
|
|
ly = (1-t)**2 * base_l[1] + 2*(1-t)*t * ctrl_l[1] + t**2 * tip_center[1]
|
|
side_l.append((lx, ly))
|
|
|
|
rx = (1-t)**2 * base_r[0] + 2*(1-t)*t * ctrl_r[0] + t**2 * tip_center[0]
|
|
ry = (1-t)**2 * base_r[1] + 2*(1-t)*t * ctrl_r[1] + t**2 * tip_center[1]
|
|
side_r.append((rx, ry))
|
|
|
|
poly = side_l + side_r[::-1]
|
|
|
|
# Тело лепестка: полупрозрачное свечение
|
|
pgdraw.polygon(poly, fill=(255, 185, 45, 55))
|
|
pbdraw.polygon(poly, fill=(255, 225, 95, 85))
|
|
|
|
# Скругленная кайма
|
|
for p in range(len(side_l) - 1):
|
|
pbdraw.line([side_l[p], side_l[p+1]], fill=(255, 235, 135, 180), width=12)
|
|
st_draw.line([side_l[p], side_l[p+1]], fill=(255, 255, 255, 220), width=4)
|
|
for p in range(len(side_r) - 1):
|
|
pbdraw.line([side_r[p], side_r[p+1]], fill=(255, 235, 135, 180), width=12)
|
|
st_draw.line([side_r[p], side_r[p+1]], fill=(255, 255, 255, 220), width=4)
|
|
|
|
# Центральный мягкий световой луч
|
|
p_b = (CENTER + R_IN * 0.9 * math.cos(a), CENTER + R_IN * 0.9 * math.sin(a))
|
|
pgdraw.line([p_b, tip_center], fill=(255, 180, 40, 160), width=36)
|
|
pbdraw.line([p_b, tip_center], fill=(255, 235, 115, 220), width=14)
|
|
st_draw.line([p_b, tip_center], fill=(255, 255, 255, 255), width=6)
|
|
|
|
# Мягкие дуги переплетения лепестков (бирюзовое северное сияние)
|
|
arcs = Image.new('RGBA', (HI_SIZE, HI_SIZE), (0, 0, 0, 0))
|
|
ardraw = ImageDraw.Draw(arcs)
|
|
for i in range(N_POINTS):
|
|
p1 = (CENTER + R_OUT * math.cos(angles[i]), CENTER + R_OUT * math.sin(angles[i]))
|
|
p2 = (CENTER + R_OUT * math.cos(angles[(i + 4) % N_POINTS]), CENTER + R_OUT * math.sin(angles[(i + 4) % N_POINTS]))
|
|
|
|
mid_a = (angles[i] + angles[(i + 4) % N_POINTS]) / 2.0
|
|
if abs(angles[(i + 4) % N_POINTS] - angles[i]) > math.pi:
|
|
mid_a += math.pi
|
|
ctrl = (CENTER + R_WAIST * 0.92 * math.cos(mid_a), CENTER + R_WAIST * 0.92 * math.sin(mid_a))
|
|
|
|
pts_arc = []
|
|
for step in range(35):
|
|
t = step / 34.0
|
|
ax = (1-t)**2 * p1[0] + 2*(1-t)*t * ctrl[0] + t**2 * p2[0]
|
|
ay = (1-t)**2 * p1[1] + 2*(1-t)*t * ctrl[1] + t**2 * p2[1]
|
|
pts_arc.append((ax, ay))
|
|
for p in range(len(pts_arc) - 1):
|
|
ardraw.line([pts_arc[p], pts_arc[p+1]], fill=(125, 230, 255, 130), width=12)
|
|
st_draw.line([pts_arc[p], pts_arc[p+1]], fill=(255, 255, 255, 190), width=3)
|
|
|
|
|
|
# 4. ФОТОННОЕ ЯДРО (СФЕРА СВЕТА И КИНО-ВСПЫШКА)
|
|
core = Image.new('RGBA', (HI_SIZE, HI_SIZE), (0, 0, 0, 0))
|
|
cdraw = ImageDraw.Draw(core)
|
|
for r_c in range(160, 0, -4):
|
|
alpha = int(255 * (1.0 - (r_c / 160.0)**1.2))
|
|
cdraw.ellipse([CENTER - r_c, CENTER - r_c, CENTER + r_c, CENTER + r_c], fill=(255, 253, 240, alpha))
|
|
|
|
for dx in range(-750, 750, 2):
|
|
fade = 1.0 - (abs(dx) / 750.0)**2
|
|
alpha = int(180 * fade)
|
|
h_w = int(16 * (1.0 - abs(dx) / 750.0) + 2)
|
|
cdraw.ellipse([CENTER + dx - 2, CENTER - h_w, CENTER + dx + 2, CENTER + h_w], fill=(185, 242, 255, alpha))
|
|
|
|
|
|
# 5. СБОРКА И LANCZOS 16x ДАУНСЕЙМПЛИНГ
|
|
comp = Image.alpha_composite(bg, petals_glow.filter(ImageFilter.GaussianBlur(55)))
|
|
comp = Image.alpha_composite(comp, trisk_glow.filter(ImageFilter.GaussianBlur(38)))
|
|
comp = Image.alpha_composite(comp, arcs.filter(ImageFilter.GaussianBlur(16)))
|
|
comp = Image.alpha_composite(comp, petals_body)
|
|
comp = Image.alpha_composite(comp, trisk_body)
|
|
comp = Image.alpha_composite(comp, silk_threads)
|
|
comp = Image.alpha_composite(comp, core)
|
|
|
|
bloom = comp.filter(ImageFilter.GaussianBlur(30))
|
|
comp = Image.blend(comp, bloom, 0.22)
|
|
|
|
final_1024 = comp.resize((OUT_SIZE, OUT_SIZE), Image.Resampling.LANCZOS)
|
|
|
|
out_file = '/home/alexives/.gemini/antigravity-ide/brain/4ff924d9-3d7f-4202-9066-3ac5c3088b8e/star_13_interstellar_aurora_petals.png'
|
|
final_1024.save(out_file, 'PNG')
|
|
print("Successfully generated Interstellar Aurora Petals at:", out_file)
|