Processing Advent Calender 2020 12日目です!
私が所属するクリエイティブコーディングサークル「ARTiS」は,不定期で開催した8回のワークショップごとに,テーマに合わせたバナーをProcessingだけで作っています.
ARTiSのWorkshop#1で出せなかったやつを供養#ARTiS_activity pic.twitter.com/BU3NiWegoR
— ohayota (@ohayoooota) May 5, 2020
今日は2回目のワークショップを開催しました!
— ARTiS (@ARTiS_CCC) May 3, 2020
「Noise」をテーマにして、オリジナル作品をつくってみました。
部員たちの作品を、ぜひこのアカウントのRTからご覧ください。
次回は「Object」をテーマに、5/6の開催を予定しています。#ARTiS_activity pic.twitter.com/w54jtmT9Oj
明日13:00-14:30の時間帯で、Workshop#3 “Object” を開催します!#ARTiS_activity pic.twitter.com/CHmnxSFofl
— ARTiS (@ARTiS_CCC) May 5, 2020
Workshop#4 “Image” を開催しました!
— ARTiS (@ARTiS_CCC) May 24, 2020
テンプレートプログラムを使いながら、画像の読み込みと加工、PGraphicsの使い方について学習しました。
次回Workshop#5 “Renderer” は、来月開催の予定です。#ARTiS_activity #ARTiS_workshop pic.twitter.com/Gu6HEjrZWz
本日13時、Workshop#5 “Renderer”を開催します!#ARTiS_activity pic.twitter.com/mvqcKzT7En
— ARTiS (@ARTiS_CCC) June 7, 2020
本日、Workshop#6 “Color”を開催しました!
— ARTiS (@ARTiS_CCC) June 14, 2020
colorModeやblendMode、配色について学びました。#ARTiS_activity pic.twitter.com/Db28YSFUuI
明日27(日)の13時より、Workshop#7 “Recursive” を開催します!
— ARTiS (@ARTiS_CCC) September 26, 2020
場所はProcessing Community JapanのDiscord、進行は @godpotbot です。#ARTiS_Activity #ARTiS_Workshop pic.twitter.com/CWCP5l6hLD
本日25(日)の12時半より、Workshop#8 “Attractor” を開催します!
— ARTiS (@ARTiS_CCC) October 25, 2020
場所はProcessing Community JapanのDiscord、進行は @ohayoooota です。#ARTiS_Activity #ARTiS_Workshop pic.twitter.com/opWmYMpLBC
開催するイベントのバナーを作るとき,どんなツールを使いますか?
グラフィック編集ツールで作る方が多いのではないでしょうか.
クリエイティブコーディングに関わるイベントであれば,Processing/p5.jsなどで描いたグラフィックをもとに,バナーを作ると思います.
作品を一度Processing/p5.jsで作ったものを他のソフトにインポートし,情報を付加し,エクスポートする...少し手数が増えますね.
それなら,コードを実行するだけで,バナーを完成できるようにしてしまいましょう.
本記事では,Workshop#2 "Noise"のバナーを例に,Processingで実現します(p5.js版に翻訳できなかった).
実装
以下2つを作成します.
- バナー背景に使いたい作品
- イベント名,開催日時,ロゴなどを描画するレイヤー(TypeLayer)
最終的には,1.の作品が文字の邪魔をしないように,filterでぼかしを入れます.
TypeLayerは,ProcessingのPGraphicsを利用して実装します.
1.の前面に2.のTypeLayerを描画して,最後に画像として出力し完成です.
バナー背景に使いたい作品を描画
スライドの表紙にも使うことを考えて,縦横比を縦:横=9:16にします.
例ではsize(1280, 720)
とします.
まずは,背景にするグラフィックを作成してみます.
7色の折れ線グラフみたいなものを,ノイズを使って適当に作ります.
↓こんなやつです
float offset = 0.0;
float distance = 0.01;
void setup() {
size(1280, 720);
background(0);
colorMode(HSB, 360, 100, 100, 100);
}
void draw() {
noiseSeed(0);
drawNoise(color(0, 100, 100));
noiseSeed(1);
drawNoise(color(30, 100, 100));
noiseSeed(2);
drawNoise(color(60, 100, 100));
noiseSeed(3);
drawNoise(color(90, 100, 100));
noiseSeed(4);
drawNoise(color(120, 100, 100));
noiseSeed(5);
drawNoise(color(210, 100, 100));
noiseSeed(6);
drawNoise(color(270, 100, 100));
offset += distance;
// 終了条件
if (width <= (offset+distance)*100) {
noLoop();
}
}
void drawNoise(color c) {
stroke(c, 50);
strokeWeight(5);
float x = offset*100;
float x_next = (offset+distance)*100;
float y = map(noise(offset), 0, 1, 0, height);
float y_next = map(noise(offset+distance), 0, 1, 0, height);
line(x, y, x_next, y_next);
}
イベント名,開催日時,ロゴなどを描画するレイヤー
作品の上に文字情報などを表示するため,TypeLayerクラスを作ってみます.
文字に使うフォントは"Avenir-Black"を選択しました.
サークルのバナーなので,サークルのロゴ(svg形式)をloadShape
で読み込んでいます.
(再現するときは,適宜置換・削除してください)
class TypeLayer {
PGraphics pg;
PShape logo;
TypeLayer() {
this.pg = createGraphics(width, height);
this.logo = pg.loadShape("ArtisLogo_v1.1.svg");
generate();
}
void generate() {
pg.beginDraw();
pg.background(0, 30);
pg.colorMode(HSB, 360, 100, 100, 100);
pg.textAlign(LEFT, CENTER);
pg.textFont(createFont("Avenir-Black", 80));
pg.fill(0, 0, 100);
pg.text("BannerExample", 100, height/2-45);
pg.textSize(40);
pg.text("2020.12.12(Sun)" + " " + "12:30-14:00", 100, height/2+45);
pg.shape(logo, width-logo.width/3-54, height-logo.height/3-20, logo.width/3, logo.height/3);
pg.endDraw();
}
void draw() {
image(pg, 0, 0);
}
}
TypeLayerクラスのインスタンスを生成することで,文字やロゴが描画されたレイヤーが完成します.
TypeLayerクラスインスタンスの生成はsetup()
内で行い,折れ線グラフみらいなグラフィックができた直後に,インスタンスのdraw()
を呼び出し描画します.
float offset = 0.0;
float distance = 0.01;
// ここから追加
TypeLayer typeLayer;
// ここまで追加
void setup() {
size(1280, 720);
background(0);
colorMode(HSB, 360, 100, 100, 100);
// ここから追加
typeLayer = new TypeLayer();
// ここまで追加
}
void draw() {
noiseSeed(0);
drawNoise(color(0, 100, 100));
noiseSeed(1);
drawNoise(color(30, 100, 100));
noiseSeed(2);
drawNoise(color(60, 100, 100));
noiseSeed(3);
drawNoise(color(90, 100, 100));
noiseSeed(4);
drawNoise(color(120, 100, 100));
noiseSeed(5);
drawNoise(color(210, 100, 100));
noiseSeed(6);
drawNoise(color(270, 100, 100));
offset += distance;
if (width <= (offset+distance)*100) {
// ここから追加
typeLayer.draw();
// ここまで追加
noLoop();
}
}
実行してみると,下図のように文字とロゴが表示されます.
見やすさのための調整
いまの状態だと背景の主張がうるさいので,少しだけぼかしを入れてみます.
そして,この状態をsaveFrame
で書き出してみます.
void draw() {
noiseSeed(0);
drawNoise(color(0, 100, 100));
noiseSeed(1);
drawNoise(color(30, 100, 100));
noiseSeed(2);
drawNoise(color(60, 100, 100));
noiseSeed(3);
drawNoise(color(90, 100, 100));
noiseSeed(4);
drawNoise(color(120, 100, 100));
noiseSeed(5);
drawNoise(color(210, 100, 100));
noiseSeed(6);
drawNoise(color(270, 100, 100));
offset += distance;
// 終了条件
if (width <= (offset+distance)*100) {
// ここから追加
filter(BLUR, 2);
// ここまで追加
typeLayer.draw();
// ここから削除
noLoop();
// ここまで削除
// ここから追加
saveFrame("Banner.png");
exit();
// ここまで追加
}
}
背景にぼかしをいれるとこうなります.見やすくなりましたね.
これで,コードだけでバナー作成を完結できました.
掲載したコードのまとめ
TypeLayer typeLayer;
float offset = 0.0;
float distance = 0.01;
void setup() {
size(1280, 720);
background(0);
colorMode(HSB, 360, 100, 100, 100);
typeLayer = new TypeLayer();
}
void draw() {
noiseSeed(0);
drawNoise(color(0, 100, 100));
noiseSeed(1);
drawNoise(color(30, 100, 100));
noiseSeed(2);
drawNoise(color(60, 100, 100));
noiseSeed(3);
drawNoise(color(90, 100, 100));
noiseSeed(4);
drawNoise(color(120, 100, 100));
noiseSeed(5);
drawNoise(color(210, 100, 100));
noiseSeed(6);
drawNoise(color(270, 100, 100));
offset += distance;
// 終了条件
if (width <= (offset+distance)*100) {
filter(BLUR, 2);
typeLayer.draw();
saveFrame("Banner.png");
exit();
}
}
void drawNoise(color c) {
stroke(c, 50);
strokeWeight(5);
float x = offset*100;
float x_next = (offset+distance)*100;
float y = map(noise(offset), 0, 1, 0, height);
float y_next = map(noise(offset+distance), 0, 1, 0, height);
line(x, y, x_next, y_next);
}
class TypeLayer {
PGraphics pg;
PShape logo;
TypeLayer() {
this.pg = createGraphics(width, height);
this.logo = pg.loadShape("ArtisLogo_v1.1.svg");
generate();
}
void generate() {
pg.beginDraw();
pg.background(0, 30);
pg.colorMode(HSB, 360, 100, 100, 100);
pg.textAlign(LEFT, CENTER);
pg.textFont(createFont("Avenir-Black", 80));
pg.fill(0, 0, 100);
pg.text("BannerExample", 100, height/2-45);
pg.textSize(40);
pg.text("2020.12.12(Sun)" + " " + "12:30-14:00", 100, height/2+45);
pg.shape(logo, width-logo.width/3-54, height-logo.height/3-20, logo.width/3, logo.height/3);
pg.endDraw();
}
void draw() {
image(pg, 0, 0);
}
}