[連載 GLSL 物語] チカラが欲しいか……（第一話）円を描く、但し、丸いドット点線で……

# はじめに
ディスタンスフィールド(ファンクション)で円を描くのはとても簡単です。
![circle.png](https://qiita-image-store.s3.amazonaws.com/0/135381/6a971001-2bb6-911d-8e4d-3a76c39c6b92.png)
https://goo.gl/zhk7Me

```glsl
 precision mediump float;
 uniform vec2  m;       // mouse
 uniform float t;       // time
 uniform vec2  r;       // resolution
 uniform sampler2D smp; // prev scene

 void main(void){
  vec2 p = (gl_FragCoord.xy * 2.0 - r) / min(r.x, r.y); // 正規化
 
  float l = step(0.,.8-length(p));
  gl_FragColor = vec4(vec3(l), 1.);
 }
```

![circle2.png](https://qiita-image-store.s3.amazonaws.com/0/135381/63d754a0-d36a-4385-52eb-a8e771e09cf4.png)
https://goo.gl/hdjgbw

```glsl
 precision mediump float;
 uniform vec2  m;       // mouse
 uniform float t;       // time
 uniform vec2  r;       // resolution
 uniform sampler2D smp; // prev scene
 
 void main(void){
  vec2 p = (gl_FragCoord.xy * 2.0 - r) / min(r.x, r.y); // 正規化
 
  float l = length(p);
  l = step(.75,l)*step(l,.8);
  gl_FragColor = vec4(vec3(l), 1.);
 }
```

じゃあ、線をドット(円)にしたいんだけど

![dot circle.png](https://qiita-image-store.s3.amazonaws.com/0/135381/eaa56766-220e-b70f-e369-cbec8b7c5cb7.png)
https://goo.gl/ra2QGP

これは、上の図形を描くに至るまでの物語である....。

# 極座標でのアプローチ
普通の破線は極座標を使えば簡単ですね。

![squarecircle.png](https://qiita-image-store.s3.amazonaws.com/0/135381/538ba4b8-0595-950e-7938-ccda53ee96ca.png)
https://goo.gl/4D4x7g

```glsl

precision mediump float;
uniform vec2  m;       // mouse
uniform float t;       // time
uniform vec2  r;       // resolution
uniform sampler2D smp; // prev scene

void main(void){
  vec2 p = (gl_FragCoord.xy * 2.0 - r) / min(r.x, r.y); // 正規化
  float l = step(abs(.65-dot(p,p)),step(sin(atan(p.y,p.x)*60.),0.)*.05);
  gl_FragColor = vec4(vec3(l), 1.);
}
```

この方法を使ってドットの破線を試みてみましょう。

![sincircle.png](https://qiita-image-store.s3.amazonaws.com/0/135381/34abc1df-2fe8-2e09-fb5b-18324430fad4.png)
https://goo.gl/1eZYcy

```glsl
precision mediump float;
uniform vec2  m;       // mouse
uniform float t;       // time
uniform vec2  r;       // resolution
uniform sampler2D smp; // prev scene

void main(void){
  vec2 p = (gl_FragCoord.xy * 2.0 - r) / min(r.x, r.y); // 正規化
  float l;
  l = step(abs(.7-dot(p,p)),sin(atan(p.y,p.x)*50.)*.05);
  gl_FragColor = vec4(vec3(l), 1.);
}
```

なんとなく、ぽいのが出来ましたが、円が歪んでますね。
これはこれで味があっていいのですが、求めているのはこれではありません。
まぁ、極座標を使っているので、円の中心から離れるほどに横軸は広くなるし、縦軸は円形に歪んでいるので当然の結果と言えます。

ということは、縦軸と、横軸の歪みを補正してあげれば求める形に出来そうですが、処理的に無駄そうなので別のアプローチを考えましょう！

# forを使ったアプローチ
![forcircle.png](https://qiita-image-store.s3.amazonaws.com/0/135381/81104bfa-2384-ab2e-d51a-7ddd189b051a.png)
https://goo.gl/tuoUG8

```glsl
precision mediump float;
uniform vec2  m;       // mouse
uniform float t;       // time
uniform vec2  r;       // resolution
uniform sampler2D smp; // prev scene

#define PI 3.1415926
#define PI2 PI * 2.0
#define N 48

void main(void){
  vec2 p = (gl_FragCoord.xy * 2.0 - r) / min(r.x, r.y); // 正規化
  float l = 0.;
  for(int i = 0; i < N; i++){
		float o = float(i) / float(N);
		float s = sin(o * PI2)*.8;
		float c = cos(o * PI2)*.8;
		l+= step(0.,.03-length(p+vec2(s,c)));
  }
  gl_FragColor = vec4(vec3(l), 1.);
}
```

for使えばできますよ。そりゃ簡単に
問題はglslのforはループ回数が固定なところ、例えば円の半径が変わるようなアニメーションをする場合に詰みます。

また、コードが長くなる。点の数が多くなると負荷が掛かるといった別の問題もあります。

* 参考 for文で円を描く https://qiita.com/doxas/items/00567758621bb506e584

# 新たなる力

そこで、新たなアプローチを考えます。
円のディスタンスフィールドの形状の上に円のディスタンスフィールドを乗せられないかと...。

そう、円のディスタンスフィールドの形状に円のディスタンスフィールド描けばいいじゃない！

しかし、ディスタンスフィールドは、別名距離関数と言われている通り、図形までの距離しか返してきません。つまりスカラーということで、ディスタンスフィールドを呼び出した時点で方向データ(ベクトル)が消失しています。ディスタンスフィールドから、さらに、その先でディスタンスフィールドを使うことは原理的に無理なのです。

だったら、ディスタンスフィールドを距離(スカラー)ではなくベクターで返したらいい。

第二話に続く...。

* [[連載 GLSL 物語] チカラが欲しいか……（第二話）新たなる力、その名はベクトルディスタンスフィールド！](https://qiita.com/7CIT/items/cfe28d258cddb009f67e)