Fornax & Okolo
Привет, Форнакс, у меня в голове такие вихревые туманности крутятся, и я думаю, как нам превратить эти космические мечты в живое цифровое полотно – ну, типа программа, которая рисует звёзды по мере их движения. Как тебе идея смешать код с какой-то долей магии, чтобы создать постоянно меняющуюся галактику?
Это просто бомба, и в прямом, и в переносном смысле. Представь себе шейдер, который подтягивает случайные выбросы частиц – каждая из них как звезда, плывущая, светящаяся и затухающая. Потом алгоритм, который перекрашивает их цвета, словно заклинания из волшебной книги. Добавь немного псевдонауки – ну, например, seed, реагирующий на клики мыши или на время суток – и у тебя получится живая галактика, дышащая в такт твоим действиям. Давай закодируем основной цикл, а потом добавим немного случайности, и посмотрим, как расцветёт космос. Готова зажечь?
Кажется, это похоже на космический танец. Я готова запускать основной цикл и пусть звёзды начнут свой милый танец свечения и затухания. Добавим немного случайности, посмотрим, как задышит галактика. Дайте волшебства!
Вжух! Запусти этот цикл, добавь случайное затравку для каждой частицы и настрой таймер, чтобы они постепенно тускнели. Подбрось немного шума Перлина к их траекториям, чтобы они кружились, как туманности, а не просто дрейфовали. Как только увидишь первые мерцающие звёзды, подкрути интенсивность свечения с помощью функции "искры", которая на мгновение резко возрастает, а потом затухает. Вот и вся алхимия – код плюс щепотка хаоса. Зажжём небо!
Вот набросок на p5.js, иллюстрирующий основную идею.
Пока что он довольно простой, но можно поиграться с числами, добавить цветов, или заменить синусоидальный шум настоящей библиотекой Перлина – получится намного интереснее. Просто смотри, как красиво светится небо!
Скелет просто отличный – пожар немного дерганый, но вот этот вихревой эффект есть. Я бы чуть увеличила интенсивность шума, может, замени синусоиду на шум Симплекса или Перлина, если сможешь подключить библиотеку; звёзды тогда будут двигаться более естественно. Попробуй ещё, чтобы каждая частица начинала в случайной позиции, а не в центре – галактика покажется более раскидистой. Добавь небольшой цветовой градиент, который меняется с возрастом – пусть звёзды переходят от голубого к оранжевому по мере старения. И, кстати, если хочешь настоящую алхимию, добавь крошечное “гравитационное” поле, которое притягивает их к точке, куда ты кликнешь – посмотри, как всё задрожит. Продолжай подкручивать параметры, и у тебя получится живая вселенная, которая будет просто уникальной.
Звучит как следующий шаг – заменю синусоиду на нормальный алгоритм Перлина, разбросаю точки старта и добавлю этот градиент цвета от синего к оранжевому по мере их старения. А эффект клика-гравитации заставит все это танцевать вокруг. Готова дальше колдовать над вселенной?
Да, давай зажигать! Переходи на нормальную библиотеку Перлина, задавай каждой звезде случайную позицию и пусть цвет меняется с возрастом. Когда нажмешь – добавь гравитационный импульс и посмотри, как галактика задрожит. Вперед – время зажечь звезды!
Конечно, держи свежую версию. В ней подключена библиотека Perlin, рандомные начальные позиции, изменение цвета со временем и эффект гравитации от клика. Просто вставь её в свой скетч p5.js и запускай.
// p5.js – обновленная версия
let shader;
let particles = [];
const MAX = 200;
function preload() {
shader = loadShader(null, frag);
}
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
noStroke();
for (let i = 0; i < MAX; i++) {
particles.push({
pos: createVector(random(-1,1), random(-1,1), 0),
age: 0,
seed: random(1000),
lifespan: random(2,5)
});
}
}
function draw() {
background(0);
shader.setUniform('time', millis()/1000.0);
shader.setUniform('particles', particles.map(p=>({
pos:p.pos, age:p.age, seed:p.seed, lifespan:p.lifespan
})));
shader.setUniform('num', MAX);
shader.setUniform('resolution',[width,height]);
particles.forEach(p=>{
p.age+=deltaTime/1000;
p.opacity=map(p.age,0,p.lifespan,1,0);
});
shader(shader);
rect(0,0,width,height);
}
function mousePressed() {
// gravity burst – push particles toward click position
let click = createVector( (mouseX-width/2)/width*2, (mouseY-height/2)/height*2, 0 );
particles.forEach(p=>{
let dir = p5.Vector.sub(click, p.pos);
dir.mult(0.05);
p.pos.add(dir);
});
}
// Simple fragment shader with Perlin noise and color shift
const frag = `
#ifdef GL_ES
precision mediump float;
#endif
uniform float time;
uniform vec2 resolution;
uniform int num;
uniform struct Particle{ vec3 pos; float age; float seed; float lifespan;} particles[200];
float noise(vec2 p){
return (sin(p.x*12.9898+p.y*78.233)*43758.5453)%1.0;
}
void main(){
vec2 uv = gl_FragCoord.xy / resolution.xy;
vec3 col=vec3(0.0);
float alpha=0.0;
for(int i=0;i<num;i++){
float n = noise(particles[i].seed + time*0.5);
vec2 offset = vec2(n, n*0.5);
vec2 pos = uv + offset/10.0;
float dist = distance(pos, particles[i].pos.xy);
float glow = exp(-dist*30.0);
float life = 1.0 - particles[i].age / particles[i].lifespan;
glow *= life;
vec3 ageColor = mix(vec3(0.0,0.5,1.0), vec3(1.0,0.4,0.0), life);
col += ageColor * glow;
alpha += glow;
}
gl_FragColor = vec4(col, alpha);
}`
Всё! Теперь звёзды дрейфуют из случайных мест, светятся голубым, переходящим в оранжевый, и колышутся при клике. Развлекайся, зажигая галактику!
Отличный сок! Эти частицы теперь ощущаются как настоящие космические странники. Если хочешь добавить больше драматизма, попробуй добавить крошечный оттенок "сумерек", который плавно меняет цвет со временем – тогда всё полотно будет казаться вращающимся. И, может, добавь немного "рождения частиц" на пике гравитационного импульса, чтобы новые звёзды появлялись там, где идёт рябь. Не давай огоньку угаснуть!