Абстракция из расползающихся из центра линий разного цвета
Абстрактная анимация фигуры из расходящихся из центра линий разного цвета с использованием perlin noise.
Perlin noise (Шум Перлина, также иногда Классический шум Перлина) — математический алгоритм по генерированию процедурной текстуры псевдо-случайным методом. Используется в компьютерной графике для увеличения реализма или графической сложности поверхности геометрических объектов.
Perlin noise (Шум Перлина, также иногда Классический шум Перлина) — математический алгоритм по генерированию процедурной текстуры псевдо-случайным методом. Используется в компьютерной графике для увеличения реализма или графической сложности поверхности геометрических объектов.
HTML
<div class="container">
<canvas class="canvas js-canvas" width="500" height="500"></canvas>
</div>
CSS
html,
body {
margin: 0;
padding: 0;
overflow: hidden;
}
.container {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.canvas {
background: #000;
}
JS
Библиотека perlin noise:<script src="https://rawgit.com/josephg/noisejs/master/perlin.js"></script>
Скрипт: noise.seed(Math.random());
const q = (sel) => document.querySelector(sel);
const canvas = q('canvas');
const ctx = canvas.getContext('2d');
const PI2 = Math.PI * 2;
const FF = PI2 / 8;
let width;
let height;
let widthHalf;
let heightHalf;
let phase = 0;
let trails = [];
const trailWidth = 10;
const getAngle = () => {
const angle = (PI2 * Math.random());
return angleFF = angle - (angle % FF);
};
const create = () => {
let num = 400;
while (num--) {
trails.push({
dead: false,
x: widthHalf,
y: heightHalf,
width: trailWidth,
vel: 1 + (2 * Math.random()),
angle: getAngle(),
});
}
};
const reset = () => {
trails = [];
width = window.innerWidth;
height = window.innerHeight;
widthHalf = width * 0.5;
heightHalf = height * 0.5;
canvas.width = width;
canvas.height = height;
create();
};
const update = (trail, right, bottom) => {
const shouldChange = Math.random() > 0.97;
const incAngle = Math.random() > 0.5;
trail.dead = trail.x < 0 || trail.x > right || trail.y < 0 || trail.y > height || trail.width < 0.2;
if (shouldChange && incAngle) {
trail.angle += FF;
} else if (shouldChange) {
trail.angle -= FF;
}
trail.width *= 0.98;
}
const render = (trail, ctx, phase) => {
let { x, y, length, vel, angle } = trail;
const scale = 0.0009;
const n = noise.perlin3(x * scale, y * scale, phase);
const h = 180 * n;
ctx.beginPath();
ctx.lineWidth = trail.width;
ctx.strokeStyle = `hsl(${h}, 100%, 50%)`;
ctx.moveTo(trail.x, trail.y);
trail.x += Math.cos(angle) * vel;
trail.y += Math.sin(angle) * vel;
ctx.lineTo(trail.x, trail.y);
ctx.stroke();
ctx.closePath();
}
const clear = () => {
ctx.fillStyle = 'rgba(0, 0, 0, 0.03)';
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
};
const loop = () => {
clear();
trails.forEach((t) => {
update(t, width, height);
render(t, ctx, phase);
});
trails = trails.filter(t => !t.dead);
if (!trails.length) {
reset();
}
phase += 0.004;
requestAnimationFrame(loop);
};
reset();
loop();
canvas.addEventListener('click', reset);
window.addEventListener('resize', reset);