Відділ освіти Кобеляцької райдержадміністрації
Опорний заклад «Білицька загальноосвітня школа
I –III ступенів №1 Кобеляцької районної ради Полтавської області»
Пісковий В.І.
учитель інформатики
Креативне програмування.
Основи програмування на мові Processing.
Білики – 2020
Пісковий Василь Іванович
учитель інформатики ОЗ “Білицька загальноосвітня школа І-ІІІ ступенів № 1 Кобеляцької районної ради Полтавської області”
Категорія: спеціаліст
У даному посібнику описуються основні поняття з мови програмування Processing, яка використовується при вивченні вибіркового модуля з інформатики «Креативне програмування».
Розглянуто основи мови Processing, починаючи з питань побудови графічних примітивів, управління кольорами, збереження зображень і включаючи методи обробки зображень, відео і аудіо матеріалів. Розкрито суть методів інтерактивних побудов, проблеми та технології їх реалізації.
Стане у пригоді вчителям інформатики при підготовці і проведенні уроків по вибірковому модулю «Креативне програмування».
ЗМІСТ
СЕРЕДОВИЩЕ PROCESSING.............................................. 5
Що таке Processing........................................................ 5
Візуальна взаємодія...................................................... 7
ПЕРШЕ ЗНАЙОМСТВО........................................................ 9
Малюємо коло............................................................... 9
Змінні і вбудовані функції.......................................... 12
Масиви......................................................................... 15
Працюємо з мишею..................................................... 16
Працюємо з клавіатурою............................................ 21
Працюємо з кольором................................................. 25
Вибір кольору.............................................................. 28
ГРАФІЧНІ ПРИМІТИВИ...................................................... 30
Малюємо криві............................................................ 30
Малюємо фігури.......................................................... 36
Зірка і квітка................................................................ 45
ПРАЦЮЄМО З РЯДКАМИ................................................. 51
НАЛАШТУВАННЯ PROCESSING..................................... 52
Установка бібліотеки.................................................. 52
Установка інструментів.............................................. 52
Перемикання режимів................................................. 53
Зберігаємо в PDF......................................................... 53
Експорт 3D-файлів...................................................... 53
ОБРОБКА ЗОБРАЖЕНЬ...................................................... 54
Працюємо з зображеннями........................................ 54
Збереження зображення............................................. 57
Позаекранне малювання............................................. 59
ОБРОБКА ВІДЕО.................................................................. 63
Підключення відео...................................................... 63
Експорт послідовності зображень............................. 64
Робота з окремими пікселями відео.......................... 67
Фільтри......................................................................... 69
ОБРОБКА АУДІО................................................................. 73
Підключення звукових файлів................................... 73
Аналіз звуку................................................................. 74
ANDROID............................................................................... 76
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ............................. 88
КОРИСНІ ПОСИЛАННЯ..................................................... 89
ДОДАТКИ.............................................................................. 90
Processing - відкрита мова програмування, що базується на Java. Вона призначена для написання графічних, анімаційних та інтерактивних програм. Надає легкий і швидкий інструментарій для людей, які хочуть програмувати зображення, анімації та інтерфейси.
Програма на мові Processing називається скетч, ескіз. Власне, спосіб мислення та творчості, за якого випробовується і оцінюється велика кількість ідей, називається скетчингом. Спочатку створюється загальний ескіз, який у процесі роботи уточняється, вдосконалюється, отримує додатковий функціонал, інтерактивність та поступово наближається до цілі.
Середовище програмування можна завантажити з офіційного сайту http://www.processing.org/ . До стандартної установки слід додати модулі, що відповідають за роботу із пристроями Android (при потребі) та JavaScript. Для того, щоб працював режим JavaScript, скористайтесь версією 3.5.4 середовища Processing та пакетом файлів JavaScriptMode (їх необхідно розпакувати з папки Додатки в папку Processing\modes в Моїх документах Вашого облікового запису).
Вікно новоствореного проекту містить робочу область для написання коду, а також кілька кнопок керування:
Запустити проект на виконання. Проект буде запущено у середовищі, обраному в правому верхньому куті вікна середовища (на малюнку - JavaScript, тобто проект запуститься у браузері; можна встановити і обирати й інші режими роботи)
Зупинити виконання проекту
Для того, щоб запустити створений застосунок на зовнішніх пристроях, потрібно увімкнути режим безпровідної мережі та підключити до неї усі потрібні пристрої. Для підключення потрібно запустити створений проект у браузері (режим Java Script), що дозволить отримати адресу працюючого порту
(127.0.0.1:55523)
Дізнавшись ІР-адресу комп'ютера із запущеним застосунком (можна скористатись стандартною програмою cmd; командою ipconfig), слід відкрити браузер на мобільному пристрої і ввести цю ІР-адресу з номером порту. Застосунок повинен відобразитись на мобільному пристрої.
Особливістю роботи у цьому середовищі є те, що відбувається не текстова взаємодія з користувачем, а візуальна. Роботу в традиційному середовищі навчання програмуванню Pascal можна охарактеризувати як:
TEXT IN - текстовий програмний код
TEXT OUT - текстовий результат програми
TEXT INTERACTION - текстова взаємодія (введення даних користувачем)
Тоді, як у Processing ця загальна схема виглядає інакше:
TEXT IN - текстовий програмний код
VISUALS OUT - графічний результат програми
MOUSE INTERACTION - взаємодія за допомогою миші /сенсорного пристрою.
Із загальних зауважень, слід вказати те, що мова є регістрозалежна (слід уважно вказувати великі та малі літери), а в кінці кожної команди потрібно ставити ;
Коментарі записуються після двох похилих рисок //
Блоки команд розміщуються у фігурних дужках { }
Проект записується всередині процедури
void setup()
{
...
}
Ці команди виконаються 1 раз при запуску застосунку.
Команди процедури малювання
void draw()
{
...
}
виконуються постійно (послідовно виконуються записані команди, після останньої виконується перша).
Запускаємо Processing і пишемо простий код з одного рядка:
ellipse(50, 50, 80, 80);
Цей рядок коду означає: намалюй еліпс, центр якого знаходиться на відстані 50 пікселів від лівого краю вікна і 50 пікселів від верхнього краю вікна, з шириною і висотою в 80 пікселів.
Клацніть на кнопку Run з трикутником або виберіть в меню Sketch | Run (Ctrl + R).
Якщо ви написали код без помилок, то побачите коло, хоча начебто написали ellipse. Так як ми вказали однакові висоту і ширину, то і отримали окружність. Відредагуйте код, щоб останні два значення стали різними і знову натисніть на трикутник для запуску програми. Тепер побачите еліпс.
Створений код можна зберегти в файл. У Processing такі файли називаються скетчами (начерками).
Хоча ми задали налаштування тільки для еліпса, насправді програма за нас використовувала інші параметри для розміру вікна, кольору еліпса і фону і так далі. Вони називаються параметрами за замовчуванням і дозволяють не відволікатися від завдання. Але іноді нас не влаштовують значення за замовчуванням, і тоді ми можемо перевизначити деякі з них.
size(300, 200); // розмір вікна в пікселях background(0, 0, 0); // колір фану вікна fill(244, 240, 125); // колів заливки noStroke(); // виключаємо рамку ellipse(150, 100, 100, 100); // малюємо еліпс
Якщо запустити програму, то побачимо повний місяць в нічному небі.
Напишемо інтерактивну програму. Код буде складніший.
void setup() { size(480, 120); } void draw() { if (mousePressed) { fill(0); } else { fill(255); } ellipse(mouseX, mouseY, 80, 80); } |
Ця програма створить вікно шириною 480 пікселів і 120 пікселів заввишки. Помістіть курсор миші в область вікна і починайте рухати їм. І ви побачите чудо - у вікні будуть малюватися білі кола, накладаючись один на одного. Але це ще не все! Натисніть і тримайте ліву чи праву кнопку миші і продовжуйте рухати миша всередині вікна. Тепер колір кола зміниться на чорний.
Запущену програму можна зупинити за допомогою кнопки Stop , яка знаходиться поруч з кнопкою Run . На цьому перше знайомство із середовищем розробки можна вважати закінченим.
Зверніть увагу, що середовище розробки поставляється з величезним числом готових прикладів для вивчення. Виберіть меню File | Examples або клацніть по значку Open, щоб відкрити список прикладів.
За замовчуванням використовується вікно розміром 100x100 пікселів. Ви можете задати власні розміри через функцію size(). Вам потрібно вказати два параметра - ширину і висоту.
size(400, 300);
Processing має ряд спеціальних змінних, що зберігають інформацію про програму в процесі її роботи. Наприклад, ширина і висота вікна зберігаються в змінних під назвою width і height . Значення змінної встановлюються в функції size(). Вони можуть бути використані для зображення об'єктів щодо розміру поточного вікна, навіть якщо параметри функції size() змінюються.
Активно використовуйте авто доповнення, якщо не пам'ятаєте точно ім'я функції. Введіть кілька перших символів, а потім натисніть комбінацію Ctrl+Space. Програма запропонує вам підходящі варіанти для продовження.
У перших прикладах ми використовували числа. Але в програмуванні зручніше використовувати змінні. А також добре б вивчити деякі вбудовані функції, які полегшують написання програм.
Крім того, не обов'язково виводити результати в вікні. У Processing в нижній частині IDE є спеціальна область для виведення повідомлень, яка називається Console. Давайте все це і спробуємо.
Але спочатку невелике зауваження. Якщо при введенні символів у вас виводяться «кракозяблики», значить у вас використовується шрифт, який не підтримує українську мову. В цьому випадку йдемо в File | Preferences ... і у вікні налаштувань вибираємо інший шрифт для настройки Editor and Console font. Вибираємо, наприклад, Courier New .
Напишемо програму.
int x = 100; int y = -150; float a = 32.75; float b = -70.38; float[] numbers = {a, b, x, y}; println("Абсолютне значення числа " + x + " дорівнює " + abs(x) ); println("Абсолютне значення числа " + y + " дорівнює " + abs(y) ); println("Квадрат числа " + x + " дорівнює " + sq(x) ); println("Квадратний корінь числа " + x + " дорівнює " + sqrt(x) ); println("Найменшим числом з масиву {" + a + "," + b + "," + x + "," + y + "} є " + min( numbers ) ); println("Найбільшим числом з масиву {" + a + "," + b + "," + x + "," + y + "} є " + max( numbers ) ); |
Отже, ми обійшлися без функцій setup() і draw(). В цьому випадку з'явиться невелике вікно розмірів 100 на 100 пікселів.
Далі ми оголошуємо змінні по їх типу. Цілі числа оголошуються як int, числа з плаваючою точкою - float.
Функція println() виводить повідомлення в нижньому вікні. Для знайомства я привів декілька готових вбудованих математичних функцій. Надалі ми будемо зустрічати інші функції. Також про них можна почитати в документації. Для конвертації одного типу змінних в інший є спеціальні функції.
println(float(9)); // int в float println(int(4.3)); // float в int println(binary(5)); // двійковий запис числа // строчку в двійковому запису в число println(unbinary("00100")); // 4 // число або строчку в булеву змінну println(boolean(1)); // true println( byte( 'A' ) ); // char в byte println(char(65)); // byte в char println(hex(33)); // number і color в hex string println(hex(color(255, 0, 255))); println(unhex( "FF00CC"));//hex string в number println(str(88)); // число в строчку |
Оголошення масивів
float[] array1 = {1.0, 2.6, 4.4 }; int[] array2 = {1, 2, 3, 4, 5 }
Функція append() дозволяє додати новий елемент в кінець масиву.
Функція arrayCopy() копіює масив або частина масиву в інший масив.
Функція concat() об'єднує кілька масивів в один новий масив.
Функція expand() збільшує розмір масиву.
Функція reverse() змінює порядок елементів в масиві.
Функція sort() сортує величини в масиві - числа від менших до більших, рядки - за алфавітом.
Ближче познайомимося з функціями для миші. Для початку напишемо скетч.
void setup() { size(500, 400); background(255); } void draw() { // empty } void mousePressed() { if (mouseButton == RIGHT) { background(255); } } |
|
void mouseMoved() { stroke(0, 64); strokeWeight(1); fill(255, 32); float distance = dist( mouseX, mouseY, pmouseX, pmouseY ); constrain(distance, 8, 100); ellipse( mouseX, mouseY, distance, distance ); } void mouseDragged() { stroke(0); float distance = dist( mouseX, mouseY, pmouseX, pmouseY ); constrain(distance, 0, 100); float weight = map(distance, 0, 100, 1, 10); strokeWeight(weight); line( mouseX, mouseY, pmouseX, pmouseY ); } void mouseReleased() { noStroke(); fill(255, 16); |
|
rect(0, 0, width, height); } void mouseClicked() { fill(255, 0, 0, 128); float size = random(20, 200); ellipse(mouseX, mouseY, size, size); } |
|
|
Функцію draw() ми залишили порожньою, а всі операції проводимо у функціях миші. Але сама функція draw() потрібна, інакше програма перестане бути інтерактивною.
Запустіть приклад. Тепер ви можете малювати мишею. Миша залишає слід у вигляді кіл. Коли ви натискаєте кнопку і відпускаєте її, з'являється червоне коло. Коли ви рухаєте мишею, утримуючи ліву кнопку миші, з'являється чорна лінія. При натисканні правої кнопки миші картинка стирається і ви можете почати спочатку.
Існує п'ять функцій і шість вбудованих змінних для роботи з мишею:
Функція mouseClicked() активується, коли ви натискаєте об’єкт мишею. Це означає натиснення і відпуск кнопки миші. У нас використовується ця функція для малювання прозорого червоного кола.
Функція mouseDragged() активується, коли ви натискаєте кнопку миші і рухаєте мишею, поки кнопка натиснута. За допомогою цієї функції ми малюємо лінії.
Функція mouseMoved() викликається кожен раз, коли миша пересувається, а кнопки не натиснуті. У нашому скетчі вона малює білі прозорі кола з чорним прозорим кордоном.
Функція mousePressed() викликається, коли ви натискаєте кнопку миші. Ми використовували цю функцію разом з вбудованою змінною mouseButton для очищення екрану правою кнопкою миші.
Функція mouseReleased() викликається, коли ви відпускаєте кнопку миші. За допомогою цієї функції ми малюємо білий прозорий прямокутник розміром з вікна скетчу поверх всіх зображень.
Вбудована змінна mouseX містить поточну координату x миші у вікні скетчу. Вона оновлюється з кожним кадром.
Вбудована змінна mouseY містить поточну координату y миші у вікні скетчу. Вона оновлюється з кожним кадром.
Вбудована змінна pmouseX містить координату x миші попереднього кадру. Вона оновлюється з кожним кадром.
Вбудована змінна pmouseY містить координату y миші попереднього кадру. Вона оновлюється з кожним кадром. Вбудована змінна mousePressed - це логічна змінна, що перевіряє, натиснута кнопка чи ні. Значення змінної істинно, коли кнопка миші натиснута і помилково, коли вона відтиснуті. Вбудована змінна mouseButton - це змінна, яка містить інформацію про те, яка кнопка миші натиснута. Вона приймає значення вбудованих констант LEFT , RIGHT і CENTER .
У Processing дуже легко взаємодіяти з клавіатурою. Ви легко можете визначити натискання клавіші і написати код для цієї події.
Напишемо невеликий скетч.
int x; int y; int radius; color circleColor; boolean isDrawStroke; void setup() { size(480, 320); strokeWeight( 2 ); x = width/2; y = height/2; radius = 80; circleColor = color(255, 0, 0); isDrawStroke = true; } void draw() { background(255); if (isDrawStroke == true) { |
stroke(0); } else { noStroke(); } fill(circleColor); ellipse(x, y, radius * 2, radius * 2); } void keyPressed() { if (key == CODED) { if (keyCode == RIGHT) { x += 10; } else if (keyCode == LEFT) { x -= 10; } else if (keyCode == UP) { y -= 10; } else if (keyCode == DOWN) { y += 10; } } x = constrain( x, radius, width - radius); y = constrain( y, radius, height - radius ); }
|
void keyReleased() { switch (key) { case 'r': circleColor = color(255, 0, 0); break; case 'g': circleColor = color(0, 255, 0); break; case 'b': circleColor = color(0, 0, 255); break; case 'c': circleColor = color(0, 255, 255); break; case 'm': circleColor = color(255, 0, 255); break; case 'y': circleColor = color(255, 255, 0); break; default: break; } }
|
void keyTyped()
{ if ( key == 's' ) { isDrawStroke = !isDrawStroke;
}
}
Розберемо код.
Спочатку ми оголосили кілька змінних для координат, радіусу і кольору кола. А також призначили булеву змінну для обведення.
У методі setup() задаємо початкові настройки для кола.
У методі draw() малюємо коло. Далі йдуть методи, пов'язані з клавіатурою: keyPressed() , keyReleased() і keyTyped() .
Функція keyPressed() виконується, коли ви натискаєте на клавішу. У нашому прикладі ми відстежуємо натискання клавішстрілок і зрушуємо коло в потрібному напрямку. Щоб коло не пішло за межі вікна, ми задаємо обмеження за допомогою функції constrain() .
Функція keyReleased() виконується, коли ви відпускаєте клавішу. У прикладі ми відстежуємо тільки деякі клавіші, чиї символи збігаються з першою літерою кольору: R - red
(червоний), G - green (зелений) і т.д.
Функція keyTyped() працює так само, як keyPressed() , але ігнорує спеціальні клавіші типу стрілок, Enter, Ctrl і Alt. У нашому прикладі відстежується клавіша S - при її натисканні у кола з'являється або зникає обведення.
У функціях використовуються кілька вбудованих змінних.
Вбудована змінна key містить значення останньої натиснутої клавіші.
Вбудована змінна keyCode використовується для зберігання останньої натиснутої спеціальної клавіші на кшталт Shift, Ctrl або стрілки. В цьому випадку keyCode приймає значення UP , DOWN , LEFT , RIGHT , ALT , CONTROL , SHIFT , BACKSPACE , TAB , ENTER , RETURN , ESC і DELETE .
Одночасне натискання клавіш, типу Ctrl + A, тут не розглядається.
Для роботи з кольором Processing підтримує системи RGB і HSB.
Оголосимо змінну color перед функцією setup() . Змінній дамо випадкове значення.
Далі намалюємо два прямокутника в різних режимах.
color mColor; void setup() { size(500, 300); |
mColor = color( random( 255 ), random( 255 ), random( 255 ) ); } void draw() { // RGB colorMode( RGB, 255 ); background( 255 ); // random color fill( mColor ); stroke( 0 ); rect( 10, 10, 480, 100 );
// HSB colorMode( HSB, 260, 100, 100, 100 ); float h = 200; float s = 45; noStroke(); for ( int i = 0; i < 80; i++ ) { fill(h, s, i); rect(10 + i * 6, 120, 6, 170 ); } noFill(); |
stroke(0); rect( 10, 120, 480, 170 );
}
Функції color() , stroke() і fill() дуже схожі. Якщо вхідний параметр - один, то кольором буде відтінок сірого. Режим кольору за замовчуванням - це RGB, який використовує величини від 0 до 255. Наприклад, color(0) встановить чорний, а color(255) - білий колір. Проміжні значення дають сірий колір. Якщо використовувати ці функції з двома параметрами, то другим буде прозорість кольору.
Якщо ви введете три параметра, то це буде червоний, зелений і синій компоненти кольору.
Додавання четвертого параметра дозволить отримати прозорий колір.
Функція color() використовується для створення змінної типу color . Це зручно, якщо ви хочете створити колір, щоб згодом використовувати всюди в скетчі.
Функція fill() використовується для установки кольору заливки фігур. У неї може бути від одного до чотирьох параметрів.
Функція noFill() використовується для відключення заливки перед малюванням фігури.
Функція stroke() встановлює колір контуру фігури.
Функція noStroke() використовується для відключення контуру перед малюванням фігури.
Функція background() встановлює колір фону. Зазвичай її застосовують у функції draw() , вона очищає екран.
Перший параметр функції colorMode() встановлює режим кольору. Це може бути RGB або HSB. Режим кольору, встановлений за замовчуванням - RGB, зі значеннями від 0 до 255. Функція colorMode(RGB, 1.0) для вказівки колірних компонентів використовує значення від 0 до 1. Якщо ви хочете перемкнути на режим HSB, запишіть colorMode(HSB, 360, 100 ,
100) .
У Processing є спеціальний інструмент для вибору кольору. Він доступний через меню Tools | Color Selector ...
Познайомимося з деякими функціями для малювання кривих.
void setup() { size(200, 240); } void draw() { background(255); noFill(); bezier(30, 20, 50, 10, 80, 100, 30, 200); curve(40, 40, 0, 20, 30, 200, -50, 250); } |
bezier() малює на екрані криву Безьє. Перші два параметри - координати початкової опорної точки. Третій і четвертий - координати першої керуючої опорної точки. П'ятий і шостий - координати другої керуючої опорної точки, а останні два параметри - координати кінцевої опорної точки.
Є ще функція bezierDetail() , яка встановлює параметр кривої Безьє. За замовчуванням він дорівнює 20.
Функція curve() виводить на екран криву. Це реалізація сплайна Катмулла-Рома. Вона працює аналогічно функції bezier() , але координати початкової, кінцевої і керуючих точок помінялися місцями. curveDetail() встановлює рівень кривої. Аналогічна функції bezierDetail() .
curveTightness() встановлює натяг кривої. Значення, встановлене за замовчуванням дорівнює 0.0. Якщо ви хочете з'єднати точки прямою лінією введіть 1.0. Якщо ви введете значення в діапазоні від -5.0 до 5.0, то ваша крива буде проходити через ті ж точки. Кожна нова величина дасть вам трохи змінену криву.
Напишемо ще один приклад з анімацією.
float noiseOffset; void setup() { size( 640, 480 ); smooth(); noiseOffset = 0.0; rectMode( CENTER ); } void draw() { noiseOffset += 0.01; background( 255 ); // Bézier curve stroke( 0 ); |
noFill(); bezier( 40, 200, 120, 40, 300, 240, 600, 40 ); stroke( 255, 0, 0 ); line( 40, 200, 120, 40 ); line( 600, 40, 300, 240 ); fill( 255 ); rect( 120, 40, 4, 4 ); rect( 300, 240, 4, 4 ); float n = noise( noiseOffset ); float x = bezierPoint( 40, 120, 300, 600, n ); float y = bezierPoint( 200, 40, 240, 40, n ); stroke( 0 ); rect( x, y, 6, 6 ); float t = map( mouseX, 0, width, -5.0, 5.0 ); curveTightness( t ); // Catmull-Rom spline stroke( 0 ); noFill(); curve( 120, 240, 40, 400, 600, 240, 300, 440 ); stroke( 255, 0, 0 ); line( 120, 240, 40, 400 ); line( 600, 240, 300, 440 ); fill( 255 ); rect( 120, 240, 4, 4 ); rect( 300, 440, 4, 4 ); x = curvePoint( 120, 40, 600, 300, n ); |
y = curvePoint( 240, 400, 240, 440, n ); stroke( 0 ); rect( x, y, 6, 6 );
}
Тут ми використовували кілька нових функцій для обчислення точок кривої Безьє і сплайнів КатмуллаРома.
Функція bezierPoint() має п'ять параметрів. Перші чотири - це координати опорних і керуючих точок кривої. П'ятий параметр - це число в діапазоні від 0 до 1. Для генерації цього параметра я використовував функцію noise() , вона видає число саме в цьому діапазоні. Якщо величина п'ятого параметра буде близька до 0, то обчислена точка буде знаходитися ближче до першої опорної точки, а якщо до 1, то до другої. Функція застосовується двічі - один раз для обчислення координати х нової точки, другий - для координати у.
Функція curvePoint() працює аналогічно функції bezierPoint() .
Ще один приклад.
float noiseOffset; void setup()
{ size( 640, 480 ); smooth(); noiseOffset = 0.0; rectMode( CENTER ); } void draw() { background( 255 ); noFill(); for ( int i = 0; i < 15; i++ ) { pushMatrix(); translate( (i * 40) + 20, 0 ); bezierDetail( i + 4 ); stroke( 0 ); bezier( 0, 20, 50, 10, 80, 100, 30, 200 ); stroke( 255, 0, 0, 128 ); line( 0, 20, 50, 10 ); line( 80, 100, 30, 200 ); popMatrix(); } float t = map( mouseX, 0, width, -5.0, 5.0 ); curveTightness( t ); for ( int i = 0; i < 15; i++ ) { pushMatrix(); translate( (i * 40) + 20, 220 ); |
curveDetail( i + 4 ); stroke( 0 ); curve( 10, 50, 0, 20, 30, 200, -50, 250 ); stroke( 255, 0, 0, 128 ); line( 10, 50, 0, 20 ); line( 30, 200, -50, 250 ); popMatrix();
}
}
Щоб створювати красиві програми, потрібно вміти малювати фігури. Почнемо з основ.
Спочатку трохи про систему координат. Нульова точка вікна в Processing знаходиться в лівому верхньому кутку. Функція size() встановлює розміри вікна вашого скетчу. Перший параметр присвоює значення вбудованої змінної width (ширина), другий - вбудованої змінної height (висота).
Для простих прикладів ми поки тимчасово не будемо використовувати функцію draw() , а весь код писатимемо в функції setup() .
Для малювання точки використовується функція point(). Тут також потрібно вказати два параметра - координати точки.
Створимо вікно розміром 480 на 120 і помістимо точку в центрі (розділимо розміри вікна навпіл).
void setup() { size(480, 120); point(240, 60); }
Точка дуже маленька, подивитися на неї складно. Але ви постарайтеся.
Якщо ви хочете намалювати крапку в нижньому правому куті, то можете зробити помилку, написавши код.
point(480, 120);
Насправді, потрібно використовувати координати (479, 119), тобто відняти одиницю від розмірів вікна.
Щоб намалювати лінію, потрібно викликати функцію line() c чотирма параметрами - координати початкової і кінцевої точки. А програма сама намалює лінію між ними. Розділимо вікно програми навпіл. Видалимо код для малювання точки, а замість неї надрукуємо інший код.
line(0, 60, 480, 60);
Отримаємо наступну картинку.
Подумайте, як намалювати вертикальну лінію. А по діагоналі?
А що якщо намалювати багато паралельний ліній по вертикалі і горизонталі через однакові проміжки? Тоді отримаємо сітку. Щоб не повторювати один і той же код багато разів, створимо окрему функцію для малювання сітки, а в неї можна застосувати два циклу. Код вийде набагато коротше.
void setup()
{ size(500, 300);
}
void draw() { drawGrid(); } void drawGrid() { stroke( 225 ); for ( int i = 0; i < 64; i++ ) { line(i * 10, 0, i * 10, height ); } for ( int i = 0; i < 48; i++ ) { line( 0, i * 10, width, i * 10 ); } } |
А ми йдемо далі і спробуємо намалювати трикутник. Для цього існує функція triangle() з шістьма параметрами - координати вершин трикутника. Навмання вибираємо різні числа. Вийшов трикутник. Захотілося намалювати поруч близнюка. Як це зробити? Щоб зрушити другий трикутник вправо, додаємо до параметрів, які відносяться до координати X, деяке значення. Це буде зміщенням. Перевіряємо.
void setup() { size(480, 120); triangle(10, 10, 100, 20, 40, 90); // Зміщуємо другий трикутник вправо на 90 пікселів triangle(10 + 90, 10, 100 + 90, 20, 40 + 90, 90); } |
Для багатокутників з чотирма точками потрібно вже вісім параметрів. А функція називається quad() .
void setup() { size(480, 120); quad(20, 10, 30,40, 90, 25, 20, 90); }
Вийшла якась галочка.
Ми могли б за допомогою цієї функції намалювати і прямокутник. Але писати вісім параметрів занадто утомливо. На щастя, Processing трохи розуміє в геометрії. Якщо вказати тільки координату першої точки, а потім ширину і висоту, то далі програма сама все розрахує і намалює. Функція називається rect(). Перевіримо.
void setup() { size(480, 120); rect(10, 10, 230, 100);
}
Як намалювати квадрат, ви самі здогадаєтеся.
Функція ellipse() нам вже знайома. Для малювання еліпса потрібно вказати центр, ширину і висоту.
Варто відзначити, що можна вказувати і негативні значення координат. Тоді може вийти, що в вікні ви побачите тільки частину фігури. Наприклад, частина еліпса.
ellipse(280, -100, 400, 400);
Також можна намалювати дугу (сектор) за допомогою функції arc() . Знову вказуємо центр, а також ширину і висоту. До того ж вказуємо початковий і кінцевий кут в радіанах. Але з радіанами працювати не дуже зручно. Що буде якщо вказати значення 0 і 2? Для величин 180, 45, 90 і 360 градусів можна використовувати готові константи в радіанах: PI , QUARTER_PI , HALF_PI , TWO_PI .
Спробуємо кілька варіантів.
void setup() { size(480, 120); arc(50, 60, 170, 80, 0, 2); arc(150, 60, 170, 80, 0, HALF_PI); arc(350, 60, 170, 80, 0, PI + HALF_PI);
}
Якщо вам відомо значення в градусах, то можете його перекласти в радіани за допомогою функції radians().
arc(90, 60, 80, 80, 0, radians(90));
Якщо ви малюєте багато фігур, які накладаються один на одного, то зверху буде та фігура, чий код у вашій програмі буде останнім.
У фігур можна управляти товщиною лінії і режимом згладжування.
За замовчуванням, товщина ліній становить один піксель. За допомогою функції strokeWeight()ви можете змінити дану поведінку. Товщину слід встановлювати до виведення фігури. Якщо малюєте кілька фігур, то у кожної треба встановлювати товщину ліній окремо. Інакше у фігури буде товщина, визначена для попередньої фігури.
strokeWeight(3); ellipse(175, 60, 90, 90);
Функція strokeJoin() визначає вид з'єднання ліній (кути), а функція strokeCap() - початкову і кінцеву точки ліній.
strokeJoin(ROUND); // округлитиstrokeJoin(BEVEL); // зробити косину
strokeCap(SQUARE); |
// кінці ліній - квадратні |
strokeCap(ROUND); |
// округлити кінці ліній |
За згладжування відповідає функція smooth() . Існує парна їй функція noSmooth() , яка відключає згладжування.
Для кольорів використовуються функції background(), fill(), stroke() , у яких потрібно вказати колір в межах від 0 (чорний) до 255 (білий). Проміжні величини будуть відтінками сірого.
Можна відключити обведення (функція noStroke() ) або зробити фігуру прозорою функцією noFill() :
void setup() { size(480, 120); smooth(); fill(153); ellipse(130, 80, 150, 150); noFill(); ellipse(228, -16, 200, 200); noStroke(); ellipse(268, 118, 200, 200);
}
Також можна вказувати колір. В цьому випадку використовуються три параметра:
background(0, 26, 51); |
// темно-синій колір |
fill(255, 0, 0); |
// червоний колір |
Перша функція зафарбовує вікно, друга - фігуру, яка буде малюватися після цієї функції.
Можна використовувати кольорову палітру через меню Tools | Color Selector .
Якщо додати четвертий параметр, то можна управляти прозорістю.
Також можна намалювати складну фігуру, наприклад, стрілку. Почніть створення вашої фігури з функції beginShape() . Функція vertex() використовується для визначення x і y – коордінат фігури.
Функція endShape() ставиться в кінці опису фігури і сигналізує про закінчення створення фігури.
void setup() { size(480, 120); smooth(); beginShape(); vertex(180, 82); vertex(207, 36); vertex(214, 63); vertex(407, 11); vertex(412, 30); vertex(219, 82); vertex(226, 109); endShape();
}
Коли ви запустите приклад, ви побачите, що перша і остання точки не пов'язані. Щоб зв’язати їх, додайте слово CLOSE як параметр функції endShape () :
endShape(CLOSE);
Перевага використання функції vertex() для створення фігур полягає в можливості побудови фігур зі складною структурою. Одна програма на Processing може намалювати тисячі ліній для відображення на екрані найнеймовірніших фігур.
Намалюємо зірку. Для неї створимо окрему функцію star() .
void setup()
{ size( 400, 400 ); smooth();
frameRate(1); } void draw() { translate(200, 200); star(5, 90, 190); } void star( int numSpikes, float innerRadius, float outerRadius ) { int numVertices = numSpikes * 2; float angleStep = TWO_PI / numVertices; beginShape(); for ( int i = 0; i < numVertices; i++ ) { float x, y; if ( i % 2 == 0 ) { x = cos( angleStep * i ) * outerRadius; y = sin( angleStep * i ) * outerRadius; } else { x = cos( angleStep * i ) * innerRadius; y = sin( angleStep * i ) * innerRadius; } vertex( x, y ); } endShape( CLOSE ); } |
Функція зірки має три параметри: одне ціле число для кількості променів і два параметра для внутрішнього і зовнішнього радіуса зірки.
Додамо функцію для малювання квітки.
outerRadius ) { float angleStep = TWO_PI / numLeafs; beginShape(); float startX = cos( 0 ) * innerRadius; float startY = sin( 0 ) * outerRadius; vertex( startX, startY ); for ( int i = 0; i < numLeafs; i++ ) { float cx1 = cos( angleStep * i ) * outerRadius; float cy1 = sin( angleStep * i ) * outerRadius; float x2 = cos( angleStep * (i + 1) ) * innerRadius;
float y2 = sin( angleStep * (i + 1) ) * innerRadius; float cx2 = cos( angleStep * (i + 1) ) * outerRadius; float cy2 = sin( angleStep * (i + 1) ) * outerRadius; bezierVertex( cx1, cy1, cx2, cy2, x2, y2 ); } endShape( CLOSE ); } |
Викличемо замість зірки.
void draw() { translate(200, 200); flower(5, 90, 190);
}
А тепер намалюємо зірки і квіти разом.
void draw() { background( 0 ); noStroke(); for ( int i = 0; i < 75; i++ ) { int numPoints = floor( random( 4, 8 ) ); float innerRadius = random( 20, 40 ); float outerRadius = random( 50, 100 ); pushMatrix(); translate( random( width ), random( height ) ); if ( random( 100 ) < 50 ) { fill( 255, 255, 0, 64 ); star( numPoints, innerRadius, outerRadius ); } else { fill( 255, 0, 0, 64 ); flower( numPoints, innerRadius, outerRadius ); } popMatrix(); } } |
Ми отримаємо анімацію з безлічі фігур. На скріншоті один з кадрів.
Рядок вказується в подвійних лапках. У рядків є багато функцій. Якщо ви знайомі з іншими мовами програмування, то вони вам знайомі. Тільки мала частина з них:
String cat = "Котяра"; void setup() { } void draw() { println(cat.length()); println(cat.charAt(1)); println(cat.substring(0, 3)); println(cat.toUpperCase()); } |
У першому рядку обчислюється довжина рядка, в другій - символ у вказаній позиції, в третій - підрядок, в четвертій – перевід рідка у верхній регістр.
Для з'єднання масиву рядків в один рядок використовується функція join() .
Для розбивки рядка на масив рядків використовується функція split() .
Функція trim() видаляє пробіли на початку і кінці рядка.
Для розширення функціональності Processing вам знадобляться додаткові бібліотеки. Встановити їх можна через середовище розробки.
Виберіть меню Sketch | Import Library | Add Library і ви побачите список бібліотек, які можна встановити. Виберіть потрібну бібліотеку зі списку і натисніть кнопку Install. Processing встановить бібліотеку в папку libraries вашого sketchbook.
Для швидкого пошуку потрібної бібліотеки використовуйте поле пошуку Filter .
Можливо, вам знадобиться бібліотека, не представлена в цьому списку. Тоді вам потрібно вручну завантажити файл з сайту розробника бібліотеки і розмістити в тій же папці libraries . Зазвичай, бібліотека являє собою окрему папку з підпапки типу examples, library, reference, src .
Інструменти (tools) - це невеликі додатки, що розширюють можливості самого середовища розробки. Процес установки аналогічний установці бібліотеки. Список інструментів потрібно дивитися на вкладці Tools (меню Tools | Add Tool ... ).
За замовчуванням Processing має один режим: Java. Ви можете додати інші режими: Android, Javascript, Python і ін. У правому верхньому куті натисніть на список, що випадає, щоб побачити список команд. Виберіть команду Add Mode ... На вкладці Modes ви зможете вибрати потрібні режими.
Скетч можна зберегти у форматі PDF. Якщо ви використовуєте фігури, то вони мають векторний формат і їх можна зберегти без втрати якості. Якщо ви використовуєте пікселі, то зберегти в PDF не вийде.
Спочатку потрібно імпортувати бібліотеку PDF через Sketch | Import Library | PDF Export .
Processing дозволяє працювати з тривимірними моделями. Спочатку потрібно імпортувати бібліотеку DXF ( Sketch | Import Library | DXF Import ).
Для створення тривимірних геометричних фігур можна використовувати бібліотеки Hemesh або Toxiclibs.
Processing може працювати і з зображеннями.
Створіть новий скетч. Перетягніть будь-яке зображення в текстовий редактор Processing. Це найпростіший спосіб додати файл до скетчу. Після цього можна писати код. Оголосимо кілька змінних.
PImage img; boolean pixelMode = false; int copyWidth = 50; int copyHeight = 3;
У функції setup() встановимо розмір вікна і завантажимо зображення, яке ми тільки що зберегли в папці data в об'єкт PImage .
void setup()
{ size(640, 480); smooth(); img = loadImage("cat.jpg"); }
У функції draw() отримаємо кілька випадкових чисел і застосуємо їх потім для заміни пікселів або частин зображення. У блоці if-else реалізований алгоритм заміни пікселів. Нарешті, ми виведемо на екран нове зображення за допомогою функції image() .
void draw()
{ int x1 = floor(random(width)); int y1 = floor(random(height)); int x2 = floor(random(width)); int y2 = floor(random(height)); if ( pixelMode == true) { color c1 = img.get(x1, y1); color c2 = img.get(x2, y2); img.set(x1, y1, c2); img.set(x2, y2, c1); } else { PImage crop1 = img.get(x1, y1, copyWidth, copyHeight); PImage crop2 = img.get(x2, y2, copyWidth, copyHeight); img.set(x1, y1, crop2); img.set(x2, y2, crop1); } image(img, 0, 0); } |
Коли ви перетягуєте зображення в текстовий редактор, Processing створює копію цього файлу і зберігає його в папці data вашого скетчу. Переглянути цю папку можна в меню Sketch | Show Sketch Folder .
Перед тим, як працювати з зображеннями в Processing, потрібно оголосити об'єкт класу PImage. Функція loadImage() завантажує зображення з папки data в цей об'єкт PImage .
Для копіювання пікселів і зміни їх кольору ми використовували методи get() та set() з класу PImage . Вони можуть використовуватися з двома або чотирма параметрами. Метод get() з двома параметрами повертає колір заданої координати.
Якщо ви використовуєте його з чотирма координатами, він повертає об'єкт класу PImage . Перші два параметри задають координати x / y верхнього лівого кута, третій і четвертий встановлюють ширину і висоту копійованого фрагмента в пікселях. Метод set() аналогічний get() , але він змінює колір заданого пікселя або прямокутної області пікселів.
У прикладі використовується логічна змінна pixelMode для перемикання з одного пікселя на групу пікселів. Змінні copyWidth і copyHeight встановлюють розмір копійованої / вставленої області пікселів.
Зберегти скетч на жорсткий диск можна за допомогою функції saveFrame () .
void setup() { size( 640, 480 ); } void draw() { background( 100 ); for ( int i = 0; i < 100; i++ ) { fill( random( 255 ), 128 ); stroke( 255, 128 ); ellipse( random( width ), random( height ), 60, 60 ); } if ( keyPressed ) { saveFrame("images/ellipses.png"); } } |
Скетч генерує окружності у випадковому порядку. При натисканні на будь-яку клавішу на жорсткий диск збережуться картинка. Її можна знайти в папці images запущеного скетчу. Причому повторне натискання перезапише файл. Щоб цього уникнути, використовуйте формат ellipses - ####. Png . У цьому випадку файли будуть створюватися заново під різними іменами, підставляючи замість символів # цифри.
Крім PNG, ви можете вказувати і інші формати зображень - JPG, TIF, TGA.
Іноді потрібно щось намалювати заздалегідь, перш ніж виводити на екран. Для цієї мети існує об'єкт PGraphics .
PGraphics pGraphics; float x; float y; void setup() { size(500, 400); pGraphics= createGraphics(64, 64, JAVA2D); background(255); imageMode(CENTER); x = 0; y = 0; } void draw() { pGraphics.beginDraw(); pGraphics.background(255, 10, 10, 10); pGraphics.smooth(); for (int i= 0; i < 8; i++) { pGraphics.stroke(random(255), 0, 0); pGraphics.line(random(pGraphics.width), random(pGraphics.height), |
random(pGraphics.width), random(pGraphics.height)); } pGraphics.endDraw(); image(pGraphics, x, y); x += random(4, 16); if ( x > width ) { x = 0; y += random( 32, 64 ); if ( y > height ) { y = 0; fill( 255, 32 ); noStroke(); rect( 0, 0, width, height ); } } }
void mousePressed() { if (random(100) < 50) { background(0); } else { background(255); } } |
У коді ми оголосили об'єкт класу PGraphics і ініціалізували його в методі setup() . У методі draw() малюємо кілька ліній в об'єкті PGraphics . Потім об'єкт виводиться на екран за допомогою функції image() . Потім доданий код для анімації, змінюючи значення x і y .
У функції mousePressed() робимо очищення екрану. Колір фону стане білим або чорним з однаковою ймовірністю.
Функція createGraphics() створює контекст, на якому ви будете малювати. Перші два параметри - це ширина і висота зображень, третій - рендерер. Для двомірних ліній підійде рендерер P2D. Початок малювання оголошується через beginDraw() . Завершення малювання відбувається через endDraw() . Між ними знаходиться сам код для малювання.
Даний об'єкт корисний при великій кількості виведених об'єктів. Наприклад, ви можете створити багато тексту в об'єктах PGraphics , а потім вивести текст на екран. Без застосування такого об'єкта скетч може гальмувати.
Створимо новий скетч під ім'ям playing_video.pde. Додамо відеофайл в папку data скетчу шляхом перетягування відеофайлу в вікно Processing.
Спочатку імпортуємо бібліотеку video . Відкрийте меню Sketch | ImportLibrary | video . Також потрібно оголосити об'єкт класу Movie перед функцією setup() . У функції setup() ми завантажимо відеофайл з жорсткого диска і запустимо відео в режимі повторення.
Функція movieEvent() потрібна для читання кадрів з відеофайлу. Функція movieEvent() автоматично викликається кожен раз, коли доступний новий кадр. Для захоплення кадру потрібно використовувати метод read() класу Movie . Вивести цей кадр на екран можна за допомогою функції image() .
У draw() виведемо на екран поточний кадр за допомогою функції image() .
|
import processing.video.*;
Movie m; void setup() { size( 640, 480 ); // Завантажемо файл із папки data m = new Movie( this, "cat.mov" ); |
|
m.loop(); } void draw() { background( 0 ); image( m, 0, 0, width, height ); } void movieEvent( Movie m ) { m.read(); } |
|
|
GStreamer framework дозволяє експортувати вашу роботу в вигляді послідовності зображень, щоб потім створити з них відео.
Нижче наведено повний код для цього прикладу. Використовуються об'єкти PVector для малювання на екрані ліній і кіл, що рухаються за принципом броунівського руху. Коли скетч досягне 900-го кадру, додаток зупиниться.
int randomNum;
PVector[] points; float radius = 2;
|
void setup() { size( 1280, 720 ); smooth(); background( 234, 228, 17 ); points = new PVector[64]; for ( int i = 0; i < points.length; i++ ) { points[i] = new PVector(random(width), random(height)); } frameRate( 30 ); randomNum = floor( random( 10000, 90000 ) ); noFill(); stroke( 0, 64 ); } void draw() { for ( int i = 0; i < points.length; i++ ) { float newX = points[i].x + random( -10, 10 ); float newY = points[i].y + random( -10, 10 ); stroke( i*4, 64 ); line( points[i].x, points[i].y, newX, newY ); ellipse( newX, newY, radius, radius ); points[i].x = newX; points[i].y = newY; |
|
} radius++; if ( radius > 10 ) { radius = 2; } saveFrame("images/export-"+randomNum+"-#####.tga"); // save 900 frames = 30 sec @ 30 fps if ( frameCount >= 900 ) { exit(); } } |
|
|
Після запуску скетчу ви знайдете в папці images в папці вашого скетчу послідовність зображень типу TGA.
Найважливіше в створенні відео - це правильно встановити розмір і частоту кадрів в функції setup() . У прикладі заданий розмір кадру 1280 x 720 пікселів і частоту кадрів 30 кадрів в секунду. Це дасть вам уявлення про те, як буде виглядати відео коли ви запустите скетч. Цей формат відео хороший для розміщення відео на таких вебсайтах як Vimeo і YouTube. Але зверніть увагу, що якщо в кожному кадрі ви робите складні обчислення, це може пригальмувати скетч і реальна частота кадрів буде менше, ніж та, яку ви вкажете в функції frameRate() .
Кожен кадр буде збережений за допомогою функції saveFrame() . В імені файлу зображення використовується випадкове ціле число під ім'ям randomNum , тому в одній і тій же папці можна зберегти кілька послідовностей зображень.
Зробити вихід з скетчу після збереження послідовності зображень також буде гарною ідеєю. Це робиться за допомогою функції exit() . Якщо потрібно 30-скекундне відео, знадобиться зберегти 900 кадрів. Розрахувати це кількість просто: число кадрів в секунду x число секунд = кількість кадрів.
Послідовність зображень зберігається в форматі TGA. Це найпростіший спосіб зберегти зображення в Processing, так як формат TGA не стискується. Ви можете використовувати PNG або JPEG, але пам'ятайте, що це сповільнить ваш скетч.
Ми можемо змінити відображення відео на екрані, змінивши колір деяких пікселів.
|
import processing.video.*;
Movie m; int numPixels; void setup() { size( 640, 480 ); numPixels = width * height; m = new Movie( this, "marbles.mov" ); m.loop(); }
|
|
void draw() { background( 0 ); image( m, 0, 0, width, height ); loadPixels(); for ( int i = 0; i < numPixels; i++ ) { float b = brightness( pixels[i] ); if ( b > 245 ) { pixels[i] = lerpColor( pixels[i], color(0, 0, 0), map(b, 0, 255, 0, 1)); } } updatePixels(); } void movieEvent( Movie m ) { m.read(); } |
|
|
Спочатку імпортуємо бібліотеку video , оголошуємо об'єкт Movie , завантажуємо відеофайл і запускаємо безперервне програвання.
У методі draw() виводимо кожен кадр на екран за допомогою функції image() . Після цього ми змінюємо колір тих пікселів, яскравість яких менше 245.
Після виведення зображень на екран викликається функція loadPixels() для завантаження всіх пікселів з екрану в масив пікселів. Для проходу по всім пікселям і перевірки яскравості використовується цикл for . Для тих пікселів, які яскравіше 245, колір пікселя змішується з чорним. Після заміни квітів викликається функція updatePixels() для показу на екрані нового зображення. Функція lerpColor() використовується для змішування двох кольорів. Перші два параметрицієї функції використовуються для вказівки кольорів, які ви хочете змішати, а третій параметр визначає, яким чином кольору будуть змішуватися. Цей параметр знаходиться в діапазоні від 0 до 1. Якщо ви напишете 0.1, результуючий колір буде ближче до першого кольору. Якщо ви напишете 0.9, то він буде більше схожий на другий колір. Для змішування кольорів в рівних пропорціях ви можете вказати в третьому параметрі 0.5.
Якщо яскравість вашого відео менше, ніж ви цього хочете, ви можете знизити межу яскравості. Це призведе до іншого результату. Також для установки кордону яскравості ви можете використовувати значення hue() і saturation() кожного пікселя.
Функція filter() дозволяє встановлювати фільтри на відео. Додайте нову сходинку коду після виклику image() з попереднього прикладу.
image( m, 0, 0, width, height ); filter( POSTERIZE, 4 );
Можна встановлювати різні режими.
BLUR : цей режим застосовує до пікселів на екрані фільтр розмивання Гаусса. Другий параметр встановлює радіус розмивання. Якщо ви не вкажете цей параметр то радіус розмиття буде дорівнює 1 пікселю. Але пам'ятайте, що якщо ви використовуєте великий радіус розмивання, ваш скетч сповільниться.
DILATE : цей режим збільшує освітлені області зображення. Це зручно, якщо ви хочете знизити контрастність. ERODE : цей режим діє протилежно режиму DILATE - зменшує освітлені ділянки зображення. Ви можете застосовувати його для зменшення контрастності зображення.
GRAY : цей режим конвертує всі кольори відео в відтінки сірого.
INVERT : в цьому режимі зображення перетворюється в негатив.
OPAQUE : цей режим перемикає канал альфа зображення на непрозорість.
POSTERIZE : цей режим зменшує кількість кольорів у зображенні. Другий параметр служить для установки кількості квітів.
THRESHOLD : цей режим робить все пікселі чорними і білими.
Можна збільшувати швидкість перегляду відео, а також зменшувати або переглядати в зворотному порядку. У setup() встановимо швидкість 1.0. У функції draw() виводимо на екран поточний кадр за допомогою функції image(). Також виведемо на екран значення змінної speed за допомогою функції text(). Функція mousePressed() буде встановлювати швидкість відео. Ми перетворимо значення змінної mouseX до діапазону від -2 до 2. Для установки швидкості програвання згідно з цією величиною ми використовуємо метод speed() класу Movie .
|
import processing.video.*;
Movie movie; float speed; void setup() { size(640, 480); movie = new Movie(this, "cats.mov"); movie.loop(); speed = 1.0; } void draw() { background(0); image(movie, 0, 0, width, height); fill(0); text("Speed: " + speed, 20, 20); } |
|
void movieEvent(Movie movie) { movie.read(); } void mousePressed() { speed = map(mouseX, 0, width, -2, 2); movie.speed(speed); } |
|
|
Метод speed() класу Movie використовується для установки швидкості програвання відео.
Якщо вказати швидкість 1.0, відео буде програватися з нормальною швидкістю. Якщо швидкість буде дорівнює 0.5, відео буде програватися з половинною швидкістю. Для прискорення відео встановіть швидкість більше 1.0. Негативне значення запустить програвання в зворотному порядку.
Для роботи зі звуком у проекті потрібно оголосити нові об'єкти (бібліотека аудіо-об'єктів та плеєр).
Звукові файли, так само, як і зображення для проекту, слід зберегти у каталозі data поточного проекту Processing.
У процедурі налаштування проекту задаються такі налаштування:
void setup() { maxim = new Maxim(this); //підключення бібліотеки player = maxim.loadFile("mykbeat.wav"); //створення
аудіо-плеєра із вказаним файлом
player.play(); //запуск відтворення аудіо-плеєра
}
Відтворенням аудіо можна керувати. Так, команда player.speed( ) дозволяє встановити швидкість відтворення. Наприклад, у процедурі void draw() група команд дозволить змінювати швидкість відтворення аудіо-ролика відповідно до переміщення миші:
void draw() { float ratio = (float) mouseX / (float) width; ratio *= 2; player.speed(ratio);
}
Аудіо-вміст, який відтворюється плеєром, можна аналізувати, визначаючи його характеристики. Для цього слід увімкнути режим аналізу:
void setup() { maxim = new Maxim(this); player = maxim.loadFile("mykbeat.wav"); player.play(); player.setAnalysing(true); } void draw() { float power = player.getAveragePower(); background(0); player.play(); |
fill (power*255,0,0); rect(0,0, power*width, height);
}
Ці команди зображатимуть прямокутник, ширина та колір якого визначаються звуковим супроводом, а точніше - його гучністю.
Для того, щоб явніше бачити різницю, варто додати множник fill (power*255*2,0,0);
За допомогою масиву spec можна представити звуковий файл як множину окремих значень гучностей: якщо є звук, то малюється прямокутник відповідного розміру та кольору.
float [] spec // оголошення даних
void setup() {
player.setAnalysing(true);
} void draw() { spec =player.getPowerSpectrum(); if (spec!=null) { |
for (int i=0; i<spec.length; i++) {
fill(0,255,255*spec[i]); rect(0,i,spec[i]*width,2);
}
}
}
Команди нижче перетворюють прямокутники на групу точок:
strokeWeight(4); stroke(255*spec[i]); point(xPos,i); xPos+=4;
На даний момент точки малюються по ширині екрану, щоб цей процес продовжувався, потрібно передбачити очищення екрану після його заповнення:
if (xPos>width){ xPos=0; background(0);
}
За замовчуванням програма працює в режимі Java . Але Processing підтримує і інші режими, зокрема, Android. У верхньому правому куті натисніть на список, що випадає і виберіть команду Add Mode ... .
У діалоговому вікні виберіть варіант Android Mode і натисніть кнопку Install .
На попередніх скріншотах показані вже встановлені компоненти, у вас буде трохи по-іншому.
Після завантаження необхідних файлів, ви зможете створювати повноцінні програми для Android (не забувайте перемикатися в даний режим).
Приступаємо до складного етапу - подружити комп'ютер з телефоном. Ми напишемо програму, яка буде передавати показання акселерометра телефону на комп'ютер, в свою чергу комп'ютер буде передавати статус натиснутою кнопки миші. Для вирішення цього завдання нам знадобляться бібліотеки: Ketai і oscP5 .
Бібліотека Ketai дозволяє працювати з датчиками, камерою, мережею і багато іншого.
Бібліотека oscP5 дозволяє передавати повідомлення між пристроями.
Встановлюються вони за пару клацань. Відкриваємо меню Sketch | Import Library | Add Library ... і знаходимо потрібні бібліотеки. Використовуйте фільтр для швидкого пошуку.
Вибираємо потрібну бібліотеку і натискаємо кнопку Install. Решта програма зробить сама.
Для обміну повідомленнями комп'ютер і телефон повинні використовувати загальну Wi-Fi мережу. Далі слід дізнатися IPадресу комп'ютера. У Windows це можна зробити через команду ipconfig.
Запам'ятаємо адресу і впишемо його в скетч для Androidрежиму.
import netP5.*; import oscP5.*; import ketai.net.*; import ketai.sensors.*;
OscP5 oscP5; KetaiSensor sensor;
NetAddress remoteLocation; float myAccelerometerX, myAccelerometerY, myAccelerometerZ; float proximity; String msg; int x, y, p; String myIPAddress; String remoteAddress = "192.168.1.42"; // адреса вашого комп’ютера void setup() { sensor = new KetaiSensor(this); //println(sensor.list()); // список всіх датчиків |
orientation(PORTRAIT); textAlign(CENTER, CENTER); textSize(40); msg = "hello"; initNetworkConnection(); sensor.start(); }
void draw() { background(78, 93, 75); text("Remote Mouse Info: \n" + "mouseX: " + x + "\n" + "mouseY: " + y + "\n" + "mousePressed: " + p + "\n\n" + "Local Accelerometer Data: \n" + "x: " + nfp(myAccelerometerX, 1, 3) + "\n" + "y: " + nfp(myAccelerometerY, 1, 3) + "\n" + "z: " + nfp(myAccelerometerZ, 1, 3) + "\n" + "Датчик расстояния: " + proximity + "\n" + "Message: " + msg + "\n\n" + "Local IP Address: \n" + myIPAddress + "\n\n" + "Remote IP Address: \n" + remoteAddress, width/2, height/2);
OscMessage myMessage = new OscMessage("accelerometerData"); |
|
myMessage.add(myAccelerometerX); myMessage.add(myAccelerometerY); myMessage.add(myAccelerometerZ); myMessage.add(msg); myMessage.add(proximity);
oscP5.send(myMessage, remoteLocation); } void oscEvent(OscMessage theOscMessage) { if (theOscMessage.checkTypetag("iii")) { x = theOscMessage.get(0).intValue(); y = theOscMessage.get(1).intValue(); p = theOscMessage.get(2).intValue(); } }
void onAccelerometerEvent(float x, float y, float z) { myAccelerometerX = x; myAccelerometerY = y; myAccelerometerZ = z; }
void onProximityEvent(float d) { |
|
proximity = d; } void initNetworkConnection() { oscP5 = new OscP5(this, 12000); remoteLocation = new NetAddress(remoteAddress, 12000); myIPAddress = KetaiNet.getIP(); } |
|
|
Так як наш телефон буде передавати дані через інтернет, то необхідний включити дозвіл на його використання. Йдемо в меню Android | Sketch Permissions і ставимо прапорець біля пункту Internet .
Запускаємо програму на телефоні (не забутьте включити WiFi). На телефоні ми побачимо дані від акслерометра, сенсора відстані і текст повідомлення і два ІР-адреси: свій і віддаленого комп'ютера. Запам'ятовуємо адреса телефону і вбиваємо його в скетч в режимі Java.
|
import oscP5.*; import netP5.*;
OscP5 oscP5; NetAddress remoteLocation; float accelerometerX, accelerometerY, accelerometerZ; float proximity; String msg; |
|
void setup() { size(480, 480); oscP5 = new OscP5(this, 12000); remoteLocation = new NetAddress("192.168.1.43", 12000); // ip-адреса телефона textAlign(CENTER, CENTER); textSize(24); } void draw() { background(78, 93, 75); text("Remote Accelerometer Info: " + "\n" + "x: "+ nfp(accelerometerX, 1, 3) + "\n" + "y: "+ nfp(accelerometerY, 1, 3) + "\n" + "z: "+ nfp(accelerometerZ, 1, 3) + "\n\n" + "Message: " + msg + "\n\n" + "Датчик расстояния: " + proximity + "\n\n" + "Local Info: \n" + "mousePressed: " + mousePressed, width/2, height/2); if (proximity == 0.0) { background(10, 10, 45); } |
|
|
OscMessage myMessage = new OscMessage("mouseStatus"); myMessage.add(mouseX); myMessage.add(mouseY); myMessage.add(int(mousePressed)); oscP5.send(myMessage, remoteLocation); } |
void oscEvent(OscMessage theOscMessage) { if (theOscMessage.checkTypetag("fffsf")) { accelerometerX = theOscMessage.get(0).floatValue(); accelerometerY = theOscMessage.get(1).floatValue(); accelerometerZ = theOscMessage.get(2).floatValue(); msg = theOscMessage.get(3).stringValue(); proximity = theOscMessage.get(4).floatValue(); } } |
Запускаємо скетч на комп'ютері. Телефон покладіть на стіл. Спостерігайте за тим, що відбувається.
Натискаємо на кнопку миші. Текст повинен змінитися на mousePressed: true .
Подивіться на телефон. Там напис синхронно зміниться на mousePressed: 1 .
Відпускайте і натискайте кнопку миші, щоб побачити, що обидва пристрої бачать один одного і передають інформацію про себе. Аналогічно ви можете обертати телефон в руках і бачити на своєму моніторі зміни показань датчика акселерометра.
Це ще не все! Покладіть телефон на стіл і прикрийте його долонею. Чи спрацює датчик наближення і вікно десктопного додатка раптово змінить свій колір.
Приберіть долоню, інформація знову проявиться.
Текст «hello» також був отриманий з телефону. Ви можете поміняти його в коді для телефону і перезапустити скетч, щоб побачити зміни.
1. Том Келли, Дэвид Келли «Креативная уверенность. Как высвободить и реализовать свои творческие силы». Перевод с англ. Т. Землянской: Азбука Бизнес, Азбука-Аттикус; Москва; 2015
2. Кейси Риз, Бен Фрай «Учимся программировать вместе с Processing». Copyright © 2010 Casey Reas and Ben Fry. All rights reserved. Перевод Александры Мишутиной.
3. Ян Вантомм «Processing 2: креативное программирование». First published: September 2012. Перевод Александры Мишутиной.
4. Орлов П. А. «Программирование для дизайнеров».
Учебное пособие под ред. проф. В. М. Иванова — М. : АВАТАР, 2015.
1. Processing / Онлайн довідник. http://wikihandbk.com
2. Reference. Processing was designed to be a flexible software sketchbook. https://www.processing.org/reference
3. Дистосвіта. Креативне програмування у Processing.
Додаток 1.
void setup() { size( 400, 400); background (255,255,255); fill(221, 160, 221); rect(0,0,400,200); fill(173, 255, 47); rect(0,200,400,200); stroke (0,0,0); strokeWeight(1); fill(255,255,255); rect(80,120,240,140); fill(255, 127, 80); rect(120,160,60,100); rect(310,160,20,120); fill(216, 191, 216); rect(220,160,60,60); fill(255, 0, 0); quad(80, 120, 320,120, 260, 60, 140, 60); fill(124, 252, 0); ellipse(320, 160, 100, 100);
}
Додаток 2.
int a=500; int b=500; void setup() { size( 800, 800); background (255,255,255); smooth(); } void draw() { if ((mousePressed && (mouseButton == LEFT)) ){ background (255,255,255); } int n=0; while (n<10) {n=round(random(20));}; float f=0 ; float df= 2*PI/n ; int r=round(random(30)); int x0=round(random(800)); int y0=round(random(800)); int red=round(random(255)); int green=round(random(255)); int blue=round(random(255)); stroke (red,green,blue); fill(0,0,0,0); |
|
|
|
for (int promin=0; promin<n; promin++) { int x= x0+round(r*cos(f)); int y= y0+round(r*sin(f)); ellipse(x,y, 2*r, 2*r); f += df; } if (mousePressed && (mouseButton == RIGHT)) { save("Picture.png"); } } |
|
Додаток 3.
void setup() {
size(800, 600); } void draw() { fill(255); if (mousePressed && (mouseButton == LEFT)) { fill( random( 255 ), random( 255 ), random( 255 )); } if (mousePressed && (mouseButton == RIGHT)) { fill( 0); } ellipse(mouseX, mouseY, 80, 80); } |
Додаток 4.
Клік лівою кнопкою мишки – побудова концентричних різнокольорових кіл, клік правою – запис побудованого зображення у файл.
int D,x,y,R,G,B; boolean kadr;
void setup(){ size(600,600); background(255,255,255); kadr=false;
} void draw(){ if (mousePressed && (mouseButton == LEFT)) { kadr=true; x=mouseX; y=mouseY; R=int(random(255)); G=int(random(255)); B=int(random(255)); D=1; } if (mousePressed && (mouseButton == RIGHT)) { save("Picture.png"); } if ((kadr==true) && (D<255)) { D++; } else { kadr=false; } noStroke(); fill(R,G,B); R=int(random(255)); G=int(random(255)); B=int(random(255)); stroke(R,G,B,255-D); |
noFill(); ellipse(x,y,D,D);
}
Додаток 5.
int x,y,D; float ro,fi; void setup(){ size(1600,1000); x=800;y=500;D=0; fi=0; |
noStroke();
} void draw(){ fill(random(255),random(255),random(255)); fi++;D=int(fi/10); ro=(D*radians(fi))/(3.5*PI); x=800+int(ro*cos(radians(fi))); y=500+int(ro*sin(radians(fi))); ellipse(x,y,D,D);
}
Додаток 6.
size(1000,1000); noStroke(); colorMode(RGB, 1000); for (int i = 0; i < 1000; i++) { for (int j = 0; j < 1000; j++) { stroke(i, j, 0); point(i, j);
}
}
Додаток 7.
int x,y; boolean vectorX,vectorY; void setup() { size(1000,800); background(255); strokeWeight(50); stroke(255,0,0); x=500; y=400; vectorX=true; } void draw() { //background(255); if (mouseButton==LEFT) {background(255);}; if (mouseButton==RIGHT) {save("diagonal.jpg");;}; if (vectorX) { x=x+6; } else {x=x-6;}; if (x>975) { vectorX=false; stroke(random(255),random(255),random(255));}; if (x<25) { vectorX=true; stroke(random(255),random(255),random(255));}; if (vectorY) { y=y+6; } else {y=y-6;}; if (y>775) { vectorY=false; stroke(random(255),random(255),random(255));}; if (y<25) { vectorY=true; stroke(random(255),random(255),random(255));}; point(x,y); } |
Додаток 8.
void setup(){ size(1000,800); background(255); } void draw(){ translate(random(1000),random(800)); stroke(random(255),random(255),random(255)); |
fill(random(255),random(255),random(255)); noFill(); int r=int(random(10,60)); for (int i=0;i<12;i++){ rotate(radians(30)); //line(0,0,r,0); stroke(random(255),random(255),random(255)); fill(random(255),random(255),random(255)); ellipse(r,0,2*r,2*r);
//delay(5) ;
}
}
Додаток 9.
Для роботи програми потрібно підключити до скетч кольорове зображення child.jpg розміром 700х460 пікселів.
Клік лівою кнопкою мишки – модифікація малюнка, клік правою – початковий вигляд малюнка.
PImage img; |
|
int kadr; void setup(){ img= loadImage("child.jpg"); size(700, 460); kadr=0; frameRate(50); } void draw(){ if (mousePressed && (mouseButton == LEFT)) { kadr++; } if (mousePressed && (mouseButton == RIGHT)) { kadr=0; } if (kadr==0){image(img,0,0);} if (kadr==1){Pics();} |
if (kadr==2){Negat();} if (kadr==3){Gray();} } void Pics(){ img=loadImage("child.jpg"); image (img,0,0); int resolution = 100; int xInc = width/resolution; //масштабування пікселя відповідно до розмірів початкового зображення int yInc = height/resolution; for (int y=0; y<img.height; y+=yInc) { //для кожного пікселя по рядках for (int x=0; x<img.width; x+=xInc) { //для кожного пікселя по стовпцях fill(img.get(x, y)); //колір зафарбування встановити кольором першого пікселя цієї області rect(x, y, xInc, yInc); //намалювати прямокутник розміру нового пікселя у координатах х,у } } } void Negat(){ img=loadImage("child.jpg"); |
image (img,0,0); for (int y = 0; y < img.height; y++) { for (int x = 0; x < img.width; x++) { color c = get(x, y); //змінна с типу color зберігає значення коду кольору пікселя set(x, y, color(255-red(c), 255-green(c), 255- blue(c))); //функції color(255-red(c) змінюють значення кодів RGB на протилежні } } } void Gray(){ img=loadImage("child.jpg"); image (img,0,0); loadPixels(); //завантажуємо пікселі у масив for (int i = 0; i < pixels.length; i++) { //перебираємо усі пікселі color c = pixels[i]; //змінна с містить значення поточного пікселя pixels[i] = color(red(c)*0.3+green(c)*0.59+blue(c)*0.11); //зміна кольору для пікселя } updatePixels(); //оновлення пікселів зображення відповідно до змін у масиві } |
Додаток 10.
PGraphics SinS; float x,y,t; void setup(){ size(600,400); x=0;t=0; for(x=0;x<=600;x++){ y=100*sin(radians(x)); fill(255,0,0,255); stroke(255,0,0,255); point(x,200+y); stroke(0,0,255,255); |
point(x,200);}
} void draw(){ if(t<=600){ t=t+1; y=100*sin(radians(t)); fill(255,255,0,255); stroke(255,255,0,255); ellipse(t,200+y,5,5); stroke(0,0,255,255); point(x,200);
};
}
Додаток 11.
float A,teta,omega,l,x,y,t; void setup(){ size(400,400); teta=0; A=50; t=0; l=200; omega=2; //omega=sqrt(9.8/l) frameRate(50); } void draw(){ background(128); if (t<10000){ t=t+1;} else {t=0;}; x=A*sin(radians(teta+omega*t)); y=sqrt(l*l-x*x); pend(); } void pend(){ line(200,100,200+x,100+y); ellipse(200+x,100+y,50,50); } |
Додаток 12.
Для роботи програми потрібно підключити до скетч два зображення zima.jpg та lito.jpg розміром 800х500 пікселів.
Клік лівою кнопкою мишки – фрагмент нижнього малюнка у виділеному прямокутнику, утримання правої кнопки – проявлення нижнього малюнка. Обертання колеса мишки змінює розміри прямокутника вибору.
PImage imgLito,imgZima; int x,y,l,sign,i; void setup(){ imgZima= loadImage("zima.jpg"); imgLito= loadImage("lito.jpg"); l=50; size(800, 500); frameRate(50); } void draw(){ background(imgZima); mouseWheel(); if (sign>0){l=l+2;}; if (sign<0){l=l-2;}; sign=0; x=mouseX-l/2;y=mouseY-l/2; noFill();stroke(255); rect(x, y, l, l); if (mousePressed && (mouseButton == LEFT)){ copy(imgLito,x, y, l, l, x, y, l, l); i=0;} if (mousePressed && (mouseButton == RIGHT)){ if (i<255) { i++; |
|
|
|
tint(255, i); image(imgLito,0,0,800,500); } else {image(imgLito,0,0,800,500);} } } void mouseWheel(MouseEvent event) { sign = event.getCount(); } |
|
Додаток 13.
Для роботи програми потрібно підключити до скетч аудіо файл ukr.wav, перетягнувши його в поле редактора програмного коду.
Також потрібно імпортувати бібліотеку processing.sound зі стандартних бібліотек Processing.
Програма аналізує та відображає спектр музичного твору і будує кругові діаграму в залежності від гучності.
import processing.sound.*; SoundFile file; Amplitude amp; AudioIn in; FFT fft; int bands = 512; float[] spectrum = new float[bands]; int R,G,B,Fon,kadr; void setup() { size(512, 512); background(255); // завантажуємо аудіофайл из папки «data» скетча и проиграємо його: file = new SoundFile(this, "ukr.wav"); file.play(); amp = new Amplitude(this); in = new AudioIn(this, 0); in.start(); amp.input(file); fft = new FFT(this, bands); in = new AudioIn(this, 0); fft.input(file); |
Fon=0;kadr=-1; } void draw() { if (Fon==0) {kadr=1;} if (Fon==510) {kadr=-1;} if (kadr==-1) {Fon--;} else {Fon++;} if ((Fon>=0) && (Fon<255)) {background(255- Fon,Fon,0);} if ((Fon>=255) && (Fon<510)) {background(0,510- Fon,Fon-255);} fft.analyze(spectrum); Color(); fill(R,G,B); stroke(0); Circ(); Fft(); } void Circ(){ ellipse(256,256,512*amp.analyze(),512*amp.analyze()); } void Color() { R=int(random(255)); G=int(random(255)); |
B=int(random(255));
} void Fft(){ for(int i = 0; i < bands; i++){ line(i, height, i, height - spectrum[i]*height*5 );
}
}