openFrameworksでマウス入力からある程度滑らかな線を引く

お絵描き機能の実現のためにタイトルのことをしたいときのソリューションをまとめておく。本気で滑らかにしたいならよりよいアルゴリズムがあるはずなので、他の場所で記事を探して欲しい。

基本

一番単純な実装は、マウスが押されている時の各フレームごとのマウス位置で点を打つ方法だ。しかし、これ少し早くマウスを動かすだけで点線になってしまう。そこで現在のマウス位置と直前のフレームでのマウス位置の間でofDrawLineで線を引く。こうすると必ず線はつながる。線を引くだけだとつなぎ目が見えてしまうことがあるが、そんなときは線の終端に線の太さと同じ円を描くと滑らかになる。

shaderを使うとき

上記のやり方でやっていくとshaderを使ったときに、ofDrawLineで描く線がofSetLineWidthの値に関わらず細くなる現象に遭遇する。shader側に渡すことで解決出来るらしいのだが、それもちょっとなと思って描き方を変えた。線の角度と長さを計算し、ofVertexを利用して四角形を描くのだ。メソッドにまとめたのが以下のコードになる。

void Test::drawLine(ofPoint startPos, ofPoint stopPos, float lineWidth){
    ofPoint vec = (stopPos - startPos).normalize() * lineWidth/2;
    vec.rotate(90, ofPoint(0, 0, 1));
    
    ofPoint first = startPos + vec;
    ofPoint second = stopPos + vec;
    ofPoint third = stopPos - vec;
    ofPoint fourth = startPos - vec;
    ofBeginShape();
    ofVertex(first);
    ofVertex(second);
    ofVertex(third);
    ofVertex(fourth);
    ofEndShape();
    
    ofDrawCircle(startPos, lineWidth/2);
    ofDrawCircle(stopPos, lineWidth/2);
}