Знакомство с p5.js

в 7:38, , рубрики: javascript, javascript p5, метки:

P5.js был создан командой Processing в 2014 году. Это JavaScript библиотека, с особым акцентом на изобразительное искусство. Цель P5.js совпадает с изначальной целью Processing — это снизить порог входа в программирование для художников, дизайнеров, учителей. С P5.js можно легко создавать бесконечно большое количество вариантов отображения информации: от веб-формата, статичных картинок для печати, до анимированных и интерактивных схем.

Processing был создан в 2001 году с целью обучить программированию непрограммистов, но с тех пор он стал основным языком для десятков тысяч художников и дизайнеров. P5.js делает рендеринг файлов PDE с исходным кодом Processing. При использовании этой библиотеки программист может вообще не знать JavaScript. Детально об отличиях Processing и p5 можно почитать в этой статье.

Для рендеринга используется canvas, а также p5.js поддерживает работу со звуком и видео. P5.js включает в себя совокупность обьектов, функций, констант с помощью которых можно создавать произвольные формы. Весь ряд возможностей p5.js можно найти в справочнике на официальном сайте.

P5 setup() выполняется один раз, когда проект загружается, так что это идеальное место, для инициализации. Подключить библиотеку можно с сервера или CDN:

<script src="../p5.min.js"></script>
<script src="//cdn.jsdelivr.net/p5.js/0.0.0/p5.min.js"></script>

Давайте создадим наш первый проект на p5.js. Наша цель состоит в том, чтобы создать инструмент для рисования, который преобразует простое изображение в область анимированных звезд. Для начала, мы определим несколько глобальных переменных и напишем setup(). Каждая отдельная графическая работа в p5.js называется «скетч», а каждый скетч состоит как минимум из двух функций — setup и draw.

Загрузить файлы вы можете здесь.

var hintImage, skyImage, stars = [];
function setup() {... }

Внутри нашей функции setup(), мы создадим холст и скроем курсор мыши чтоб иметь возможность рисовать от себя. P5 добавляет контур вокруг формы по умолчанию, в нашем случае, нам нужно отключить строки.

createCanvas(800,500);
noCursor();
noStroke();

image

Далее, мы загрузим два изображения. Одно будет служить в качестве фона — в нашем случае, сцена ночного неба. Другим будет «hint» изображение. Идея заключается в том, чтобы положить большинство звезд на черные пиксели нашего hint изображения, чтобы воссоздать дизайн фоновой сцены. Эти изображения достаточно легко создать с помощью p5 инструментов для рисования, но для краткости мы будем использовать статические изображения.

hintImage = loadImage("//bit.ly/hintImage");
skyImage = loadImage("//bit.ly/skyImage");

image

Еще одна ключевая функция это draw(). Она вызывается в непрерывном цикле, что полезно для анимации.

function draw() {... }

В функции Draw, наша первая задача состоит в том, чтобы заполнить canvas фоновым изображением. P5 не очистит холст между вызовами draw() автоматически, так что мы должны делать это каждый кадр, ибо в конечном итоге получим странные эффекты накопления. Чтобы поместить загруженное изображение на холст, используйте функцию image() и дайте ей координаты х и у для определения местоположения.

image(skyImage, 0, 0);

Далее, мы захватываем текущее местоположение мыши и сохраняем его в качестве p5.Vector используя createVector(). Этот объект включает в себя удобные функции, для работы с точками в пространстве, но мы будем в основном его использовать в качестве контейнера.

var position = createVector(mouseX, mouseY);

Используя недавно сохраненную позицию мыши, мы можем нарисовать наш курсор. Мы установим цвет курсора с помощью fill(), передавая значения RGB и будем использовать ellipse(), дабы нарисовать круг на месте мыши.

fill(255, 192, 0);
ellipse(position.x, position.y, 8, 8);

С помощью mouseIsPressed, мы сделаем так чтобы во время зажатия мыши рисовались новые звезды. Во время зажатия мыши, нам нужно вычислить хорошее место для следующей звезды. Мы сделаем это с помощью специальной функции под названием findPixel(), которую мы определим позже.

Как только у нас появится сигнал, мы создадим новый экземпляр объекта Star и прижмем его к концу нашего звездного массива. А если общее количество звезд превысит 2000, мы начнем отбрасывать самые старые из них.

if (mouseIsPressed) {
  var target = findPixel();
  var star = new Star(position, target);
  stars.push(star);
  if (stars.length > 2000) stars.shift();
}

В конце, мы пройдемся через наш массив звезд и вызовем update() и draw() на каждом из них. Мы рассмотрим эти методы позже.

for (var i = 0; i < stars.length; i++) {
  stars[i].update();
  stars[i].draw();
}

Теперь setup() и draw() на месте, а мы будем работать над вспомогательными функциями и объектами. Во-первых, мы определим функцию, которая находит место для каждой новой звезды. Все, что нам нужно сделать, это проверить рандомные пиксели в нашем изображении, используя get(), чтобы увидеть, черные они или белые.

На самом деле мы должны смотреть только на значение красного, так как в обоих случаях RGB значения совпадает.

function findPixel() {
  var x, y;
  for (var i = 0; i < 15; i++) {
    x = floor(random(hintImage.width));
    y = floor(random(hintImage.height));
    if (red(hintImage.get(x,y)) < 255) break;
  }
  return createVector(x,y);
}

Теперь нам нужен многоразовый контейнер, который хранит информацию о каждой звезде, а также будет обновлять и рисования их. В JavaScript нет классического способа для создания классов в традиционном смысле этого слова, но мы можем получить тот же результат, определив функцию и настроив ее для собственных нужд.

Каждая звезда имеет несколько свойств (исходное положение, конечное местоположение и диаметр генерируемый случайным образом), мы их определим в «функции конструкторе», которая вызывается для каждой новой звезды, созданной в нашем цикле отрисовки.

function Star(position, target) {
  this.position = position;
  this.target = target;
  this.diameter = random(1, 5);
}

Далее мы добавим метод update() для функции Star, который будет использовать p5.Vector lerp(), чтобы вычислить новое положение между текущим и целевым позициям звезды. В этом случае, мы движемся на 4% оставшегося расстояния на каждой итерации.

Star.prototype.update = function() {
    this.position = p5.Vector.lerp(
    this.position,
    this.target,
    0.04
  );
};

И, наконец, метод draw(), который рисует звезду на холсте. Еще раз, мы используем fill() и ellipse(), хотя на этот раз мы вызываем fill() со значением alpha для прозрачности.

Чтобы дать звездам огонька, значение alpha определяется с помощью функции noise(). Это возвращает значение шума Перлина для указанных координат, то есть вы получаете гладкую, последовательность случайных чисел. В третий параметр, мы вводим значение на основе времени, с помощью него шум будет анимироваться в течение некоторого времени.

Star.prototype.draw = function() {
  var alpha = noise(
  this.target.x,
  this.target.y,
  millis()/1000.0
);
fill(255, alpha * 255);
  ellipse(
    this.position.x, this.position.y,
    this.diameter, this.diameter
  );
};

Вот что у нас в итоге получилось:

image

На этом работа над нашим первым скетчем закончена.

Еще один хороший пример работы с p5.js можно посмотреть в этом видео<a/>.

Справочный материал:

Автор: prince86

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js