円をつなぐ線 p5.js

数日前にTwitteerでopenFrameworks/C++ベースのシンプルで面白いプログラムを見つけました。junkiyoshiさんの「円をつなぐ線 openFrameworks」。ブログではソースコードも公開されているのでp5.jsで実装してみました。

円の頂点を繋げただけなのに、面白い動き!

通常のプログラミング

準備中

関数型プログラミングのように書いたもの

最近C#Linqや関数型プログラミングを勉強しているのでzip関数や参照透過性を考えながら書いたコードです。

 

p5.jsでライフゲーム

p5.jsでライフゲームを作成しました。

剰余による回り込み

二次元配列のboard[0][0]の場合は、近傍(neighbor)を調べるときに、board[-1][-1]のようになりエラーになってしまいます。このような場合は、(カラム数+現在のカラム-1%カラム数) のように書くと、カラム数が20だったらboard[19]となってくれます。一次元配列でもこの剰余のテクニックを使うと、配列をリングに見立てることができるので、非常に便利です。

ライフゲーム自体の実装は、着実に進めていけば簡単です。

 

p5.jsで一次元セルオートマトン

p5.jsで一次元セルオートマトンを作ってみました。ルール関数を作成し、0-255でルールを生成できるようにしました。ルール生成関数は、ビット演算とシフト演算んでもっと綺麗な実装にできそうです。

剰余による回り込みの実装

また、(配列の長さ+現在のインデックス)%配列の長さ というテクニックを使い、配列の0番目で、左端の値の場合は、配列の最後である右端の値を取得するようにしました。

 

 

 

p5.jsで加算ブレンド

p5.jsでは、blendMode関数を指定することで簡単に加算合成ができます。

簡単にvscodeでp5jsの入力補完をする方法

はじめてプログラミングをしてみた人でも設定できるp5jsの入力補完の方法です。マイクロソフトが無料で開発しているvscode(=Visual Studio Code)エディターを使うとp5jsの補完が簡単にできます。

tsファイルをダウンロード

以下のリンクから、p5.d.tsファイルとp5.global-mode.d.tsファイルをダウンロードして、プロジェクトのフォルダーに配置します。

https://github.com/LujunWeng/demos-p5js/tree/master/typings/p5js

tsファイルをダウンロードしたところ

コメント行を書く

sketch.jsのはじめの行に上記のコメントを書きます。あとは、createなどを書くと入力補完ができるようになります。

入力補完ができた!

vscodeの入力補完は優秀で、引数の値を入力すると、その細かい内容まで以下のように表示してくれます。

技術的な話

tsファイルはTypeScriptの型定義ファイルで通常TypeScriptで使われますが、TypeScriptはJavaScriptのスーパーセットなので、.jsファイルも混在可能です。そのためふぃあるのコメント行で型定義ファイルを指定すると補完が可能になります。このファイルの英語を日本語に直せば単純に変更できます。github上でTypeScriptの補完に関しても議論されているようです。現状、npm の@typesでこの型定義ファイルがダウンロードできないので、今後p5.js団体が管理してくれるとありがたいです。

まとめ

すべて手入力は面倒なので、簡単に補完する方法をまとめました。単純にファイルをダウンロードして、コメント行を追加するだけなので、プログラマーでない人でも簡単に導入できると思います。

 

p5.jsで2Dパーリンノイズを動かすにはコツがいります。

書籍Nature of Codeを買ったので最初の章をp5.jsで試してみました。2Dパーリンノイズを作ってみる課題があったのですが、書籍の書き方ではうまくいきませんでした。githubのサンプルコード(https://github.com/shiffman/The-Nature-of-Code-Examples-p5.js/tree/master/chp00_introduction)にも、サンプルはありませんが、Youtube動画でコーディングしていました。

See the Pen 2D perlin noise p5.js by dev001hajipro (@dev001hajipro) on CodePen.0

考え方

1.単純な二次元配列の要素の取得を考える。

横幅(width)を100px、縦幅(height)を100pxで考えると、2重のfor文で二次元配列の座標(X,Y)を求める事ができます。これはよくある実装方法なので難しくないです。

2.一行はRGBAが並んでいる事を考慮する

p5.jsのpixels配列は、1つの要素にRGBAがオブジェクトとして含まれるのではなく、R、G、B、A、がpixels配列の要素で連続で並んでいます。例えば、横幅5pixelで、縦幅2pixelの場合は、以下のような感じです。

このため、ピクセル単位で処理をしたい場合は、4単位で移動させるように、for文のステップ数を変更します。

3.画像は通常一次元配列

私たちはXY座標で操作するほうが簡単ですが、画像データは一次元配列でpixels配列も同様です。そのため、(1行の幅 * 行数) で現在行までの要素数を求めて、そこに現在のX座標を足します。

(1行の幅 * 行数) + 現在のX

p5jsが予約しているwidthグローバル変数はキャンバスの横幅、heightグローバル変数はキャンバスの縦幅を取得できます。これはちょうどcreateCanvasで指定した値です。また、今回の一行はRGBARGBARGBAのようになっているため4倍にする必要があります。

此処までで、各pixels要素であるRGBAにアクセスし、直接色を指定できるようになりました。以下はRGBA(255,0,0,255)を指定して、全てのピクセルを赤で染めるサンプルです。

4.Densityを考慮する

Retinaディスプレイや携帯電話の場合、より綺麗な画像を表示するためにPiexl per Inch(https://ja.wikipedia.org/wiki/Ppi)、所謂、画素密度が異なります。そのためpixelDensityで値を取得して、縦幅、横幅に掛けます。1行は、width*4*dになります。よって、(width*4*d)*yで、現在行数の要素数を求めて、それにxを加えることで、現在のピクセル位置が求まります。ゆっくり考えれば問題ありませんが、(width*4*d)*y*dみたいにしないように注意してください。

此処までで、高解像度ディスプレイの場合でも各RGBAを修正することができるようになりました。

5.横のノイズをリセットする

p5.jsでは、noise(x,y)を設定すると二次元のパーリンノイズを使うことができます。y=1の固定にして以下のコードを書きました。注意してほしいのは、noise(xoff)を1行単位でリセットすることです。つまり3行目のlet xoff = 0;のように書きます。

二重ループの前にxoffの変数定義をすると、パーリンノイズ関数は、xがずっと続いていると判断するため、意図したノイズになりません。

xoffが正しくない例

yoffも定義する

ここまでくればもう理解できたと思います。あとは、yoffを指定するだけです。

 

まとめ

p5.jsでのピクセル操作と2Dパーリンノイズを実装することができました。まずは、RGBA単位のピクセル操作をできるようにして、そのあとに高解像度を考慮して、最後に2Dパーリンノイズを実装しました。いちどにすべてをやろうとすると、どこが原因で表示できないのかが分からなくなるので、このような実装は、段階的にやったほうが良いようです。