p5.jsを使って模写
ICS MEDIAの編集長さんの記事が目にとまりました。
これを読んで「うわ〜、すご〜い」って思いましたよ。
高校や大学でラジアンとかsinなど僕が学んでいた(そして、すっかり忘れている)数学をさらりと使っているし、僕の興味のあるフロントエンド分野のスペシャリストのようですから。
今やHTML5とJavaScriptでこんな面白そうなことができるんだ!僕も作ってみたい!
というわけで、ProcessingのJSライブラリ「p5.js」を使って模写しました。
成果は▼こちら。
※ソースコードは記事下においておきます
紹介した記事は段階的に処理を説明してくれていますので、ひとつひとつ同じことをp5.jsで実装していきました。p5.jsのお作法を知るためにリファレンスを見ながらコツコツと。
その途中経過の産物が▼こちら。マウスを押している間にぺジェ曲線のコントロールポイントが左右に動きます。(スマホでは動きませんでした)
しかし、紹介記事の「まとめ」にp5.js版のサンプルコードがあることを知ったのは最終段階に近づいたあたり(笑)
おかげでいい勉強になりましたけどね。たとえば、
- 時間の概念についてp5.jsではdraw()内に記述すれば良いのですが、JSだと「requestAnimationFrame(tick);」を使って時間の概念を作っていること。
- p5.jsは特に指定しない限り描いたものが残る(描き続ける)もの、JSではFlashやBlenderでいうタイムライン(パラパラ漫画的)の概念があるもの。
- Date.now()から刻一刻の変化量を求める手法がある。
などです。
Generative Design:論理性と偶然性のアート
プログラムしたものが動くわけだから、そのルールに収まったもの・決まったものしか描けません。でも、変数をいじってみたり、for文とfor文を掛け合わせてみたら思いがけない設定が生まれたりする。
そういうものから偶然に描かれるものがあるはず。
「何が生まれるのかが最後まで読めないこと」が僕には魅力的。
AdobeやBlenderを使って現実のもの・想像上のものを形にするのもいいけれど、プログラミングで創造することもまたいい。論理性と偶然性が織りなす何かがいいのです。
おわりに
昔から「動くものを作りたい」という気持ちはありましたが、これといって作ってきたわけでもなし。でも興味だけはずっとあった。
それがたまたま目にした記事で進み出すとは思わなかったです。
どうせなら動くものの方が心が躍ります。画面をタッチする、マウスカーソルを合わせる。インタラクションっていうのかな。
また、これきっかけにJSライブラリに興味が出てきました。今の時代は色々あるんですね〜。フレームワークもたくさんあってJSって面白いと感じてます。
本業の写真と融合させられないか動いていきましょう。
※ICS MEDIAさんの記事はどれもわかりやすくまとめられていて、参考&刺激になります。
うねうね動く曲線のソースコード
html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>p5.js demo | Takashi Q. Hanamura Photography</title> <style> body { margin: 0; height: 0; overflow: hidden; } canvas { width: 100vw; height: 100vh; background: black; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.min.js"></script> <script src="sketch180924.js"></script> </head> <body></body> </html>
※ICS MEDIAさんのサンプルを真似させてもらいました。CSSの設定方法は超参考になりました。
JavaScript(sketch180924.js)
/* https://ics.media/entry/18812 の動作をp5jsで再現する。 HTML Canvas要素とJavaScriptで実現している。 自分なりに作ってから上記URLのp5js版のコードを移植したもの。 */ let stageW = innerWidth; let stageH = innerHeight; const lineNum = 100; // ラインの数 const segmentNum = 100; // 曲線の分割数 const amplitude = stageH / 2; // 振幅 function setup() { createCanvas(stageW, stageH); colorMode(HSB); strokeWeight(1); } function draw() { background(0, 0, 0); noFill(); drawCurve(); } function drawCurve() { [...Array(lineNum).keys()].forEach(j => { const time = Date.now() / 6000; // 擬似アニメーション用の媒介変数 const coefficient = 50 + j; // 係数 // ラインのカラー設定 const h = round(j / lineNum * 360); // 色相 const s = 100; // 彩度 const l = round(j / lineNum * 100); // 明度 beginShape(); stroke(h, s, l); [...Array(segmentNum).keys()].forEach(i => { // X座標 const x = i / (segmentNum - 1) * stageW; // Y座標 const px = i / coefficient; // 横軸の入力値 const py = (j / 50 + time); // 時間の入力値 //const y = amplitude * noise(px, py) + stageH / 3; const y = (noise(px, py)) * stageH; vertex(x, y); }); endShape(); }); } // マウスを押している間は処理を止める function mousePressed() { noLoop(); } function mouseReleased() { loop(); }