自動勉強会 vol.0 ペイントツール作製技術 前半
課題(やるかどうかは自由)
ペイントツール作ったことないけど話に参加したい人用の入門セットとして、課題を2つ作ってあります。やってから参加すると話の内容が入ってきやすいかもです
ペイントツール課題の実装例回答 by

シンプルな線を描く
this.old = { x: ev.offsetX, y: ev.offsetY }
やるやる……

Vue2系
GUI初心者なのでナニモワカラナイ

マウス座標のとり方を毎回調べ直している

毛筆風ブラシ
単純にlineWidthを増減させてたのか、なるほど


マウス離してもdrawが続くのが描きづらい
これをなんとかしようとするといい感じに細くする部分の実装が工夫が要りそう
マウス離したらN秒間かけてだんだん細くなってゆく仕組みにするとどうなのかな

動かせば描かれて、動かなかったらそのままみたいな感じにすると、うまくはらい(?)が作れるかな
妄想が広がる
マウスイベントの時間を測り始めると実装が辛くなってくる...

毛筆というよりインクペンぽくなった

解けなかった

ペイントツール実装技術(1時間経過済)
線を引く・ブラシの実装
曲線補間 ( Spline /
B-Spline / Catmull-Rom / ... )

は3次B-Spline使いがち (打った点を制御点に)
2点から何点でもOK
手ブレ補正が効く
Bezierに変換できる
便利!

打った点をそのまま制御点にするのか〜
描いたパスの要所要所が尊重されるか、尊重されないか、というので違いがありますよね(何がなんだったか忘れた)

あ、制御点だ。制御点を通るかどうか
fabricjs-psbrushは三次スプライン曲線だったようです(と、昔の記事に書いてあった)

与えられた点列に近い、できるだけ少ない点で構成されたベジェ曲線を返す関数
Kakeruを作るときに、フォークして作りましたが、アルゴリズムはよく理解してないです

実装をほぼ変えずに、TypeScript化しただけ
通過点を通りつつ、いい感じの曲線になってくれる?
これもベジエに変換可能
3Dもいける!

ベジエに変換して描く方法
InstagramのStoryのペンが描き心地良いのだけどなぜか描き心地がいいのだろう

インク溜まり(端点)
ポインターの滞留時間で見て重みつけたりするのだろうか
気になる
速度でペン幅が変化している
そこに線形じゃない変換をかけるといい感じになるのかなぁ
Google図形描画、
SVG出力できるんだよね。あれ内部で何使ってるのか知らないけどベクターでやって
PNGやJPEG出力のときにラスターに変換してる
ラスターへの変換ってBlob経由してCanvasに転写してbase64にする感じでやったことはありますが、Googleさんはもっとスマートに??
パス単純化
間引くと角が丸くなっちゃう問題
人物の髪とか
市販ソフトのベクターツールでも角がぬるい感じになってしまう
間引いて
スムージング(quadratic curve にする)ことで線が滑らかになる効果もある
同時お絵描きツールを作ってみたときにポイントを間引ききつつ滑らかにするのにquadratic curve使いました

角が取れなくてすごい(角度の変化量が多いところは残る)
こういうgifすき


割とヒューリスティック

計算量も抑えつつできそう
インターセクション
懺悔します、ラスターでやってCanvasのcompositeに丸投げしました
ベジェ曲線同士の交差を検知する時は無数の直線に分割して直線同士の交差を探すようにしたり…
あ、まさにそれと同じことをしました!!

ベジェ曲線をN分割してポリラインにして、で交差判定をしました
SVGのブーリアン、Paper.jsのコアにあるぞって書かれてますね
課題1の勢いよく書いても線がカクカクしないバージョン
下図の赤い点が補助点として配列で得られる
pressure の値も補完?してくれるとうれしい…

わかる...

iOSだと、補完したデータがApple Pencilで取れたりするんですが、それと一緒だ(アプリの話)
そういうのもあって、最近iPadのネイティブアプリ作りたくなってます

お絵かきソフト以外で需要あるのかこれ……(便利)
ジェスチャーとか?

あ〜

Safari...
カスタムブラシ
テクスチャを使ったブラシ
水彩 (色混ぜ/水彩境界…)
色混ぜ→1点1点に分割して、その点で平均色を取ってブラシの色と混ぜ合わせる、はやったことある

シェーダーなんですね面白いー
プログラマブルにブラシを作ることができる
アニメ機能もついてる。UIがめちゃめちゃよくできていてすごい

普通のUI部分がとてもきれい
消しゴム実装されている!
ばくさんだ!!
ただ直線を引く
canvasに頼らない話
ブレゼンハムのアルゴリズムや、独自の実装について
ビットマップの点を全部舐めて、線分から一定距離にある点を全部塗ると、太い線が描ける

処理速度的にも大丈夫そう!

点と点の距離が短いので!

これは使えなかったって感じだったのかな?
imageSmoothingEnabled

目的が違う。画像を貼り付けるときにピクセル補完をするかというもの
アウトラインに線引いてから中身を埋めるとかできる?

多角形で輪郭を描いて、ライン単位で塗りつぶす、でやってます
それもありかも
いや、でも下に絵が描いてあると塗りつぶし大変そう
1ドットずつ fillRect してる()
無茶実装感

ポリゴン(3D)じゃん
太さの変わる曲線も同じ
N-gonを三角形面に分割する処理だ……

今度は逆方向の難しさ

この辺わりと3Dの知見が

パフォーマンス
React+SVGのパフォーマンスが悪かったので、Canvasで再実装した人です

canvasも、ペンで描いている間はできるだけ再描画しないとかの工夫をした
VDOM+SVGだけでも会が開けそう

描画バックエンドをCanvasにしておいて、UIを
VDOMでやりました
バウンディングボックスの四角は<div>のborderです
これの曲線がCanvasで描画してて、制御点とかのUIがVueですね
Kakeruもそれです!

Griffith Sketchも同じ

Figmaもそんな感じだったような

Figmaはなんか異常に頑張ってますよね....

右クリックして出てくるContext Menuとかは自作してそうな気がしている
SVGのRectではだめなんです?
foreignObjectのheightを越えられず描画が途切れる という経験
見えなくしたhtml側で描画しておいて高さを測ってsvg側に適用しましょ?(力技)
やっぱこれしかないのか…

imgタグで表示しているときにはforeignObject内部のリソースが読み込まれないことを利用した画像+動画
⇡ 新しいタブで開くと動画になる
外部リソースの読み込み制限回避のためにBase64にするのあるある

foreignObjectの面白さは一通り体験できた

レイヤーたくさん作ったらメモリが足りなくて大変だった時があった

レイヤータイリングして描いてない部分は確保しないようにしたいけど大変そう

Fabric.js はオブジェクトごとにbounding boxを計算して持っていて、描画キャッシュはbounding boxサイズで作られるので、レイヤー(fabric.Group)をいっぱい作っても、ラスタみたいに全画面サイズ×レイヤー数のメモリを奪われることはないんですよね

それでもストロークごとに fabric.Path みたいなオブジェクトを生成しているとメモリが足りなくなったりします

上で

が書いてる問題は、たしか retina ディスプレイとかでキャッシュの解像度を調整する部分があって、そのあたりのせいだったような…

canvasが多くなりすぎるのもダメなのか…?
とくにmobile safari なんかのCanvasのメモリ制限がしょっぱい
デカすぎんだろ…(テニヌ)
width=0,height=0設定しないと死なないのかなり罠だ…

canvas自体をv-ifで消してあとで再出現させたりすると、getContext('2D')からやり直しになってまう問題
Mobile Safariは200MBちょっとしかメモリがなかった
みんなとにかく色々なことと戦っていてすごい

組み込みシステムだとメモリ厳しくて undo 回数に制限をかけたことがある

cで書く(wasm)
やっぱり速いですか?

デスクトップアプリと遜色ない速度になっている
js>wasmでデータ渡すところがネックになる場合があるって聞いたことはありますね
Rust でも、wasm が絡むとデータ転送かなり難しい……

js>wasmは座標データだけ渡して、wasm>jsは更新矩形だけ渡す
1フレームで更新がかかる範囲は局所的なので転送コストがボトルネックになることはない
状態(今のツールとか)ってどこに持ってるんですか?
wasm側はコア+内部的なビットマップとしてのキャンバス
VuexやReduxのstoreってコト…!?
いかに独立した処理として切り出すかが難しそう

8bit paint webはA4 600dpiで持っている。えんぴつチャットはA3 600dpi
A4 600dpi !?

どいうこと??
4961 x 7016
ペイントツールというテーマが総合格闘技すぎる...!
