WebGLスクール2期1回目メモ

前々からしっかり勉強しようと思ってたので、WebGLスクール全6回に参加する事にしました。
　→　[WebGL スクール第２期の募集を開始します！ 2015年5月開講！](http://webgl.souhonzan.org/entry/?v=0203)

個人的にWebGLやGLSL勉強してたけど、周りに優秀な人が多くて危機感あったのでちょうど良い機会でした！

# 1回目のスライド
・[WebGL の概念と基本を押さえよう](http://school.souhonzan.org/201505/document/001/)
![スクリーンショット 2015-05-27 15.47.06.png](https://qiita-image-store.s3.amazonaws.com/0/15028/af266df5-1afa-77c3-f1d7-29638db14715.png)

# 内容
- 前半
・作例
・WebGLとは何か？
・実装の基本的な流れ

- 後半
・シェーダーやGLSLのハンズオン

# ハンズオン内容
以下のオンラインエディタを使ってハンズオンしました(主にGLSLエディタ)

・[GLSLエディタ](http://school.souhonzan.org/ge/)
　・範囲選択でcommand + / でまとめてコメント、コメント解除できる
　・エディタ上でcommand + sで実行
　・エディタ上でescで実行停止

・[GLSL/HTML/jsエディタ](http://school.souhonzan.org/we/)

・[GLSLの組込変数一覧](https://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf)　→　明解WebGL本の一番後ろの付録にも載ってた

GLSLの組み込み関数はここがわかりやすかった　→　[GLSLについてのメモ](http://qiita.com/edo_m18/items/71f6064f3355be7e4f45)

**ちなみにGLSLには、javascriptのconsole.logみたいものはないっ！**

##初歩のコード

```glsl
precision mediump float;        // おまじない
uniform vec2  mouse;            // マウス座標の値
uniform vec2  prevMouse;        // 前のマウス座標の値
uniform float time;             // 時間の経過
uniform vec2  resolution;       // 解像度
uniform sampler2D backBuffer;   // 一つ前で描いた描画が取れる

void main(void){
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    gl_FragColor = vec4(vec3(p.x), 1.0);
}
```
##初歩のコード解説
以下のコードは、Canvasの座標をGLSL用に正規化するコード。

```glsl
vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
```
gl_FragCoord = それぞれのピクセルの位置が入ってる組み込み関数
resolution = 解像度の事で512が入ってる（canvasの縦横 512 x 512）

```glsl
(gl_FragCoord.xy * 2.0 - resolution)
```
2倍する事で最小：0 - 512 = -512、最大：1024 - 512 = 512になる。
つまり、-512〜512の座標系になる。
それを512で割る事で、-1.0〜1.0の間で座標指定ができる。
要するに縦横0〜512px　→　-1.0〜1.0にする。中心が（0,0）

```glsl
gl_FragColor = vec4(vec3(p.x), 1.0);
```
gl_FragColorは描画カラー部分の組み込み変数。
値が大きくなると白、値が小さくなると黒。
　白：vec3(1.0) = (1.0, 1.0, 1.0)
　黒：vec3(0.0) = (0.0, 0.0, 0.0)

ちなみに以下のコードにすると斜めグラデーション

```glsl
gl_FragColor = vec4(vec3(p.x*p.y), 1.0);
```

マイナスにすると位置が変わる

```glsl
gl_FragColor = vec4(-vec3(p.x*p.y), 1.0);
```

1.0から引いて色を反転はよく使う

```glsl
gl_FragColor = vec4(vec3(1.0 - p.x*p.y), 1.0);
```

##length使ったコード
```glsl
precision mediump float;        // おまじない
uniform vec2  mouse;            // マウス座標の値
uniform vec2  prevMouse;        // 前のマウス座標の値
uniform float time;             // 時間の経過
uniform vec2  resolution;       // 解像度
uniform sampler2D backBuffer;   // 一つ前で描いた描画が取れる

void main(void){
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    // lengthはpの長さを返す組み込み関数(pの長さ = -1.0〜1.0)
    float f = length(p);
    /*
    float f = length(p * 2.0); // このコードなら円が小さくなる
    float f = 1.0 - length(p); // 1.0から引いて黒と白を反転できる
    */
    gl_FragColor = vec4(vec3(f), 1.0);
}
```
![01.png](https://qiita-image-store.s3.amazonaws.com/0/15028/1896b3ff-757b-1412-9920-42d70c71b1bd.png)


##absを使ったコード
```glsl
precision mediump float;        // おまじない
uniform vec2  mouse;            // マウス座標の値
uniform vec2  prevMouse;        // 前のマウス座標の値
uniform float time;             // 時間の経過
uniform vec2  resolution;       // 解像度
uniform sampler2D backBuffer;   // 一つ前で描いた描画が取れる

void main(void){
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    // abs()はマイナスをプラスに変える組み込み関数
    vec2 q = abs(p);
    gl_FragColor = vec4(vec3(q.x), 1.0);
}
```
![02.png](https://qiita-image-store.s3.amazonaws.com/0/15028/33d68704-cdbd-56bb-f513-ea942fe7b926.png)


##powを使ったコード
```glsl
precision mediump float;        // おまじない
uniform vec2  mouse;            // マウス座標の値
uniform vec2  prevMouse;        // 前のマウス座標の値
uniform float time;             // 時間の経過
uniform vec2  resolution;       // 解像度
uniform sampler2D backBuffer;   // 一つ前で描いた描画が取れる

void main(void){
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    // pow(x,y)xのy乗を返す組み込み関数
    float f = pow(length(p), 10.0);
    // float f = length(p); にすると累乗の結果がわかりやすい
    gl_FragColor = vec4(vec3(f), 1.0);
}
```
![03.png](https://qiita-image-store.s3.amazonaws.com/0/15028/198cb569-1b20-a348-3e58-23490adc470c.png)


##小さい円を描くコード
```glsl
precision mediump float;        // おまじない
uniform vec2  mouse;            // マウス座標の値
uniform vec2  prevMouse;        // 前のマウス座標の値
uniform float time;             // 時間の経過
uniform vec2  resolution;       // 解像度
uniform sampler2D backBuffer;   // 一つ前で描いた描画が取れる

void main(void){
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    // 0.02を割ることで中心ほど値が小さくなる
    float f = 0.02 / length(p);
    // float f = 1.0 -0.02 / length(p);なら反転する
    gl_FragColor = vec4(vec3(f), 1.0);
}
```
![04.png](https://qiita-image-store.s3.amazonaws.com/0/15028/8d013a40-9b6f-97ee-2017-2369cec87f83.png)

##modを使ったコード1
```glsl
precision mediump float;        // おまじない
uniform vec2  mouse;            // マウス座標の値
uniform vec2  prevMouse;        // 前のマウス座標の値
uniform float time;             // 時間の経過
uniform vec2  resolution;       // 解像度
uniform sampler2D backBuffer;   // 一つ前で描いた描画が取れる

void main(void){
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    // mod()は割り算で描画してる内容を複製する時によく使う
    vec2 q = mod(p, 0.5) - 0.25;
    float f = 0.1 / length(q);
    gl_FragColor = vec4(vec3(f), 1.0);
}
```
![05.png](https://qiita-image-store.s3.amazonaws.com/0/15028/4b9df9e6-d73c-7934-199a-569cca561241.png)

##modを使ったコード2
```glsl
precision mediump float;        // おまじない
uniform vec2  mouse;            // マウス座標の値
uniform vec2  prevMouse;        // 前のマウス座標の値
uniform float time;             // 時間の経過
uniform vec2  resolution;       // 解像度
uniform sampler2D backBuffer;   // 一つ前で描いた描画が取れる

void main(void){
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    // 円部分
    vec2 q = mod(p, 1.0) - 0.5;
    /*
    vec2 q = mod(p, 0.5) - 0.25; // 細かく複製できる
    ちなみに以下でも意味は同じ
    vec2 q = mod(p, 0.5) - vec2(0.25);
    vec2 q = mod(p.xy, 0.5) - vec2(0.25);
    */
    // 円の明るさ
    float f = 0.1 / length(q);
    gl_FragColor = vec4(vec3(f), 1.0);
}
```
![06.png](https://qiita-image-store.s3.amazonaws.com/0/15028/e25b3d0b-f79b-9b53-2028-fa04ba03c837.png)

##グラデーションのある玉コード
```glsl
precision mediump float;        // おまじない
uniform vec2  mouse;            // マウス座標の値
uniform vec2  prevMouse;        // 前のマウス座標の値
uniform float time;             // 時間の経過
uniform vec2  resolution;       // 解像度
uniform sampler2D backBuffer;   // 一つ前で描いた描画が取れる

void main(void){
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    // rgbで色指定
    float r = 0.1 / length(p);
    float g = 0.2 / length(p);
    float b = 0.5 / length(p);
    gl_FragColor = vec4(r, g, b, 1.0);
}
```
![07.png](https://qiita-image-store.s3.amazonaws.com/0/15028/4850f560-f6de-486c-db54-0ab82729f5fd.png)

##グラデーションのある玉に赤を加算するコード
```glsl
precision mediump float;        // おまじない
uniform vec2  mouse;            // マウス座標の値
uniform vec2  prevMouse;        // 前のマウス座標の値
uniform float time;             // 時間の経過
uniform vec2  resolution;       // 解像度
uniform sampler2D backBuffer;   // 一つ前で描いた描画が取れる

void main(void){
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    float r = 0.1 / length(p + vec2(0.5));
    float g = 0.2 / length(p);
    float b = 0.5 / length(p);
    gl_FragColor = vec4(r, g, b, 1.0);
}
```
![08.png](https://qiita-image-store.s3.amazonaws.com/0/15028/112ffd2b-0e69-56e3-9075-7e50448a97e7.png)


##玉をぐるぐる回すコード
```glsl
precision mediump float;        // おまじない
uniform vec2  mouse;            // マウス座標の値
uniform vec2  prevMouse;        // 前のマウス座標の値
uniform float time;             // 時間の経過
uniform vec2  resolution;       // 解像度
uniform sampler2D backBuffer;   // 一つ前で描いた描画が取れる

void main(void){
    // timeにはjsから渡された時間が入ってる
    float s = sin(time);
    float c = cos(time);
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    float r = 0.1 / length(p + vec2(c, s));
    /*
    以下のコードにすると上下運動だけになるのでわかりやすい
    float r = 0.1 / length(p + vec2(0.0, s));

    sinの場合は中心からアニメーション開始
    cosの場合は、-1からアニメーション開始
    */
    float g = 0.2 / length(p);
    float b = 0.5 / length(p);
    gl_FragColor = vec4(r, g, b, 1.0);
}
```

##線を引くコード
```glsl
precision mediump float;        // おまじない
uniform vec2  mouse;            // マウス座標の値
uniform vec2  prevMouse;        // 前のマウス座標の値
uniform float time;             // 時間の経過
uniform vec2  resolution;       // 解像度
uniform sampler2D backBuffer;   // 一つ前で描いた描画が取れる

void main(void){
    float s = sin(time);
    float c = cos(time);
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    float f = 0.1 / p.y;
    /*
    これだと線の下半分が出てないので、absを足す
    float f = abs(0.1 / p.y);
    */
    gl_FragColor = vec4(vec3(f), 1.0);
}
```
![09.png](https://qiita-image-store.s3.amazonaws.com/0/15028/ed437d15-675b-60aa-8343-491115f9f1b4.png)

##円を引くコード
```glsl
precision mediump float;        // おまじない
uniform vec2  mouse;            // マウス座標の値
uniform vec2  prevMouse;        // 前のマウス座標の値
uniform float time;             // 時間の経過
uniform vec2  resolution;       // 解像度
uniform sampler2D backBuffer;   // 一つ前で描いた描画が取れる

void main(void){
    float s = sin(time);
    float c = cos(time);
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    float f = 0.02 / abs(length(p) - 0.5);
    // 「length(p) - 0.5」の-0.5は中心から離れるほど値が小さくなる
    gl_FragColor = vec4(vec3(f), 1.0);
}
```
![10.png](https://qiita-image-store.s3.amazonaws.com/0/15028/84c339f0-5d66-ddd9-850c-e5ed2663a261.png)

#その他
開発環境は、[NetBeans](https://ja.netbeans.org/)がオススメ！
　→　ローカルWebサーバ起動するし、デバッグできる♪
[Brackets](http://brackets.io/)でもローカルWebサーバ起動するので、そちらで開発してたけどちょっと乗り換えた。
NetBeansだとプロジェクト作る必要があるので、そこだけ少し面倒だがWebサーバーの起動早いしデバッグできるし、メリット多い。
ちなみにNeatBeanで既存HTML取り込みの仕方は以下の通りです。
（１）[ファイル]-[新規プロジェクト]を選択
（２）カテゴリ＝HTML5、プロジェクト＝既存のソースを使用するHTML5アプリケーションを選択する
（３）次へ
（４）サイト・ルートをindex.htmlがあるフォルダ選択する
（５）終了
（６）画面上部に実行ボタン押下すればローカルWebサーバ起動する
（７）（１）〜（６）を繰り返して、起動したいプロジェクトを追加する



以下のサイトのコードコピペでも行けたので、講義中に色々試してました。
　→　[GLSLで簡単2Dエフェクト](http://www.demoscene.jp/?p=1147)
**※　precision mediump float;は必要**

あと、[明解WebGL本](http://www.amazon.co.jp/%E6%98%8E%E8%A7%A3WebGL-iOS-Android%E3%82%82%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%9F3D-CG%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AEWeb%E6%A8%99%E6%BA%96-%E6%9D%89%E6%9C%AC%E9%9B%85%E5%BA%83/dp/4897979900)は、読みやすいのでオススメです。
この本のライティング編あたりから「GLSLは超重要だ！」って思いました。
ソースコードはこちら　→　[明解 WebGL本ソースコード](http://book.wgld.org/rf/?utm_source=dlvr.it&utm_medium=twitter
)

また、前回のWebGLスクール内容やGLSLチュートリアルをやるのもオススメです。

[第一回 WebGLスクール 「WebGLの概念」](http://qiita.com/konweb/items/a52ae0bc6aec2d2f3e6b)
[[連載]やってみれば超簡単！ WebGL と GLSL で始める、はじめてのシェーダコーディング（１）](http://qiita.com/doxas/items/b8221e92a2bfdc6fc211)


いや〜、GLSLは短いコードで表現力が凄くてまったく意味がわからないw
理解できて余裕があれば次回も書いていきます