読者です 読者をやめる 読者になる 読者になる

S.F. Page

Programming,Music,etc...

フラグメント・シェーダー(Shadertoy)で2D Line(線分)を描く

GLSL Shadertoy WebGL

フラグメント・シェーダー(Shadertoy)で線分を書いてみようと思った。

Shadertoyのフラグメント・シェーダーは描画するピクセルごとにmainImage(out vec4 fragColor, in vec2 fragCoord)が呼ばれる。画面のピクセル個数分このmainImage()が呼ばれるのである。 この関数で描画色を決め、fragColorに色をセットする。fragCoordは描画するピクセルの座標位置が入る。

線分の描画の考え方としては「ピクセルが線分の描画範囲に入っている場合は指定の色で色付ける。」となる。つまり画面全部の点についてこの処理を行えば線分が描画できることになる。

で、その点が線分に含まれるかどうかのアルゴリズムはいろいろありそうだが、私は以下のように考えた。

  1. 現在のピクセルの座標をx3,y3、描画したい線分の座標をx1,y1,x2,y2とする。
  2. x3,y3を通り、x1,y1,x2,y2を通る直線に垂直に交わる直線と、x1,y1,x2,y2を通る直線との交点をx4,y4とする。
  3. x3,y3x4,y4との距離をdとすると、dが線の太さt以下であればその点を描画する。

上の考え方に沿って実装方法を考えた。

  1. x1,y1,x2,y2を通る直線の方程式はy = \frac{y2 - y1}{x2 - x1}x - \frac{y2 - y1}{x2 - x1}x1 + y1 ... (1)
  2. x3,y3を通り、(3)と直交する直線の方程式はy=-\frac{x2-x1}{y2-y1}x + \frac{x2-x1}{y2-y1}x3 + y3 ... (2)
  3. (1),(3)の交点x4を求める。(2)式を(1)式に代入する。-\frac{x2-x1}{y2-y1}x + \frac{x2-x1}{y2-y1}x3 + y3 = \frac{y2 - y1}{x2 - x1}x - \frac{y2 - y1}{x2 - x1}x1 + y1 ... (3)
  4. (3)式を整理する。x(x4) = \frac{(x2 - x1)^{2}x3 + (y3-y1)(x2-x1)(y2-y1)+(y2-y1)^{2}x1}{(y2-y1)^{2}+(x2-x1)^{2}}
  5. x4 \lt min(x1,x2) かつ x4 \gt max(x1,x2)であれば描画しない。
  6. x4を式(1)に代入しy4を求める。
  7. length(vec2(x3,y3),vec2(x4,y4))を求め、dとする。abs(d) \le tであれば描画する。

x2-x1 = 0もしくは y2-y1 = 0の場合は特殊なケースとして場合分けをした。このあたりまで考えて実装した結果が以下である。

https://www.shadertoy.com/view/4ltSzH

実際Shadertoyのコードを読むと、もっと簡単に書いている方もいる。ベクトルの考え方を導入することによってね。

https://www.shadertoy.com/view/Xd2XWR

上の線分のコードを私用に改造すると以下となる。

うーむ。このコードはすごいな。。