[recovery mode] Знакомство с p5.js

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:





Давайте создадим наш первый проект на 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 можно посмотреть в этом видео.

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


  • -Processing
  • -Processing.js
  • -P5.js

Комментарии (0)

© Habrahabr.ru