この記事はWebGL Advent Calendar 2018の11日目の記事です。
はじめに
趣味でお絵かきツールを作っています
昨年からCanvasとWebGLを使ってベクター方式のお絵かきツールを作っています。前回のアドベントカレンダーでも少しだけ紹介しました。WebGLはポーズ人形の描画に使っています。
基本的には線画のためのツールですが、塗りつぶしや簡易なアニメーション機能も備えていて、そのうちそれを使って簡単なアニメーションが作れるようになったらいいなと思ってたりもします。
筆者はBlender使いの端くれなのでグリースペンシルも使っているのですが、自分の求める使い心地とは少し違う感じです。
Canvasは一定の太さの線しか描けない
線の描画はHTML5のCanvasで行っているのですが、Canvasの2D描画は最初から最後まで同じ太さでしか線を描画できないとう問題があります。
イラストを描くときには線に微妙な太さの変化をつけたいときがありますが、それができないということになります。
この問題は調べてもいまいち良い方法が見つからず、3D描画技術では細かくポリゴンに分割する方法がよくありますが、拡大しても滑らかな曲線にするには相当なポリゴン数になります。
なお、現状は線の太さを変えて何度も直線を描いています。これでも縮小すると結構それっぽく見えます。
ベクター方式でやりたいのには理由がある
正確には、ベクター方式(線の座標などを保存しておく方式)ではなくラスター方式(ピクセルデータを保存しておく方式)なら色々とやりようがありますし、ベクター方式でもそれなりにやりようがある気がするのですが処理が重かったりします。
ちなみに、なぜベクター方式にこだわるのかというと、筆者が不器用だからです。生まれつきか、練習不足か、あるいはペンタブレットの性能がいまいちなのか、PGの職業病で手が震えるからか、とにかくなかなか滑らかな線が引けないのです。そこで、後から線を編集したりスムージングしたりできるベクター方式のツールを作ろうと思いました。これもPG特有の病かもしれません。
WebGLで高速に太さと透明度に変化のある線を描く
半年くらい悩んだのですが、大雑把に次のような流れになります。
- 頂点の位置と半径のデータを作成
- 理想としては頂点の間をベジエ曲線で補間した各位置で補間された半径の円を描いた形にしたいが難しい
- そこでベジエ曲線で線の左側と右側を近似する。
- しかしポリゴンを単純に作ると線がはみ出る場合がある
- 左右の曲線がはみ出ないように制御点の位置も利用してポリゴンを作る
- セグメント(辺)ごとのローカル空間を考えて、ベジエ曲線の位置xに対応するyの値を三次だか四次だかの方程式を解いて求める(フラグメントシェーダ)
- 左側のベジエ曲線と右側のベジエ曲線の間の点であればピクセルを描画する
なお既知の問題として、ポリゴンにする関係から、厳しい角度になると破綻するという問題があります。
蛇足
シェーダ内でのベジエ曲線の計算はBlenderのベジエ曲線を再現する処理を作ったことがあり、それをTypeScriptからGLSLに移植しました。もともと方程式の解はネットからコピペしたコードで正直よくわかっていないのに、それをGLSLに移植したら一発で動いたのでびっくりしました。数学は偉大。数学は神秘。
ライブデモ
デモをGitHub pagesに用意しました。そういえば去年までのデモはたしか○オシティーズなのでそのうち見れなくなってしまうのか…
作ったはいいのですが線を一本描いただけでは高速なのか分からないため、自作のお絵かきツールで描いている途中の恥ずかしいデータ(他に良いデータが無かったんです。有名なキャラです)を無理やり描画してみました。ライブデモの「負荷テスト開始」ボタンから実行できます。
※データは2MBありますので、モバイル回線等で実行する際は注意して下さい。
本当に高速なのか?
単純に比較はできませんが、Canvasで描画するのと比べ高速な気がします。
iPhone 6Sではヌルヌル動きました。
ただ、頂点バッファを作成する処理は重いのでお絵かきツールで使うには工夫が必要そうです。
終わりに
今回の描画処理は拡大には強いですが縮小には弱いです。また、厳しい角度で線が曲がっていると破綻してしまいます。さらにアンチエイリアスを考えていないので、WebGLでは細かいポリゴンに分割する方がよいかもしれません(自動でされるため)。
などなど問題は多いのですが、ともかく半年くらい思い描いていたことを現実にできたので良かったです。
また、超がつく蛇足ですが、12月11日のアドベントカレンダーを担当して5年目になりました。来年も11日かもしれませんが、11日が良い方は筆者に遠慮なさらずに容赦なく先に登録していただければと思っております。これはフリではありません。
それでは皆様、WebGLとともに良い年の瀬をお過ごし下さい。