2Dのメタボール(Metaball)理解した
2Dのメタボール(metaball)について理解した。
メタボールっつーのは何かと言うとこれです。写経したやつだけど。
(PCで見てくれよな!)
See the Pen metaball canvas by bom_phage (@bom_phage) on CodePen.
メタボールというか、こういう滑らかにくっつく表現やりたいなーと思っていて、調べてたけどどうにもよくわからないでいた。特によく出てくるのはSVG filter使うやつ。liquid
みたいな言葉で検索するとよく出てくるけど、とにかくパフォーマンスが悪い。ほんでSVG filterに対する知識があんまりないので、???みたいな気持ちになってた。
ちょっと間忘れてたけど、思い出してふとやってみるかということになって写経したところ、ばっちり理解した。
原理
上述のcodepenのやつだと若干実装が違うんだけど、ポイントは
- 不透明度の円形グラデーションを複数用意する(中心は不透明度が高く、外側に行くにつれて透明)
- ある値(
閾値
)以下の不透明度の場合は不透明度を0にする(透明にする)
の2つ。これをやるとメタボールみたいに境界がぬるっとした感じの描画になる。
例えば、中心から外側にrgba(0, 0, 0, 1)
=> rgba(0, 0, 0, 0)
というグラデを作って、描画時に不透明度0.95以下の部分は rgba(0, 0, 0, 0)
にしちゃう感じ。
そうすると不透明度1 〜 0.95の部分だけの円ができる。
これが複数個集まると、重なる部分は不透明度が足し算されて、円と円の間の部分に不透明度0.95を超える部分が出てきて境界が滑らかなる。 => メタボール!という感じ:sun_with_face:
まぁそれはそうだがそれはどんな風に実装すんねんっていうのを下に書いとく。
実際触ると一目瞭然だと思うし、canvas
とcssのfilter
で実装したやつを用意している。
実装
canvas
canvas
の場合は、表示用と描画用の二種類のcanvas
が必要になる。描画用の方にradialGradient
でぼかした円を描画して、その内容を表示用のカンバスにコピーする。そのときに不透明度が閾値より低い部分は透明にすることで、メタボールが描画できる。
この実装ではTHRESHOLD
という定数が閾値(初期値210※1)になってるのでここを10とかにしてもらうとボケた円がでてくる。
※1 canvasの場合透明度の範囲も0〜255
See the Pen metaball canvas2 by bom_phage (@bom_phage) on CodePen.
◆前述の実装との違い
実装見てもらったら話は早いけど、描画用のcanvas
からgetImageData
で全ピクセルの情報を取得している。その時、ピクセルのデータは1pxずつrgba
という順番で配列に格納されている。
前述の実装の場合はコピー時にその全データに対して、閾値より低い場合に0
を与えている。これだとr
もg
もb
も閾値以上でないといけなくなってしまう。それだと色に限りがでてしまって困る。
そういうわけでa
の値のみ評価するようにしたのが後述の方。そっちのがforが回る回数も少なくて済むし、いろんな色がいけるぞ。
CSS filter
cssでもやってること一緒。円にblur
をかけて、描画領域のcontrast
を上げることで、不透明度の低い(コントラストが低い)部分を飛ばしている感じです。でもCSSだとcontrast
をあげる都合上、パキパキしたのしかできないし、色の自由度が著しく低いと思う(解決方法がわからん)。
しかもcssのfilter
めっちゃ重い!!
See the Pen metaball by bom_phage (@bom_phage) on CodePen.
はい
そういうわけで実装するならcanvas
でやりましょう!原理がわかれば無限に応用効くと思うし、いろいろできそうでワクワクするぞ!!
3Dも理解できるように頑張るぞ!
See the Pen metaball particles by bom_phage (@bom_phage) on CodePen.