前々からしっかり勉強しようと思ってたので、WebGLスクール全6回に参加する事にしました。
→ WebGL スクール第2期の募集を開始します! 2015年5月開講!
個人的にWebGLやGLSL勉強してたけど、周りに優秀な人が多くて危機感あったのでちょうど良い機会でした!
1回目のスライド
内容
-
前半
・作例
・WebGLとは何か?
・実装の基本的な流れ -
後半
・シェーダーやGLSLのハンズオン
ハンズオン内容
以下のオンラインエディタを使ってハンズオンしました(主にGLSLエディタ)
・GLSLエディタ
・範囲選択でcommand + / でまとめてコメント、コメント解除できる
・エディタ上でcommand + sで実行
・エディタ上でescで実行停止
・GLSLの組込変数一覧 → 明解WebGL本の一番後ろの付録にも載ってた
GLSLの組み込み関数はここがわかりやすかった → GLSLについてのメモ
ちなみにGLSLには、javascriptのconsole.logみたいものはないっ!
##初歩のコード
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用に正規化するコード。
vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
gl_FragCoord = それぞれのピクセルの位置が入ってる組み込み関数
resolution = 解像度の事で512が入ってる(canvasの縦横 512 x 512)
(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)
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)
ちなみに以下のコードにすると斜めグラデーション
gl_FragColor = vec4(vec3(p.x*p.y), 1.0);
マイナスにすると位置が変わる
gl_FragColor = vec4(-vec3(p.x*p.y), 1.0);
1.0から引いて色を反転はよく使う
gl_FragColor = vec4(vec3(1.0 - p.x*p.y), 1.0);
##length使ったコード
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);
}
##absを使ったコード
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);
}
##powを使ったコード
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);
}
##小さい円を描くコード
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);
}
##modを使ったコード1
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);
}
##modを使ったコード2
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);
}
##グラデーションのある玉コード
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);
}
##グラデーションのある玉に赤を加算するコード
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);
}
##玉をぐるぐる回すコード
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);
}
##線を引くコード
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);
}
##円を引くコード
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);
}
#その他
開発環境は、NetBeansがオススメ!
→ ローカルWebサーバ起動するし、デバッグできる♪
BracketsでもローカルWebサーバ起動するので、そちらで開発してたけどちょっと乗り換えた。
NetBeansだとプロジェクト作る必要があるので、そこだけ少し面倒だがWebサーバーの起動早いしデバッグできるし、メリット多い。
ちなみにNeatBeanで既存HTML取り込みの仕方は以下の通りです。
(1)[ファイル]-[新規プロジェクト]を選択
(2)カテゴリ=HTML5、プロジェクト=既存のソースを使用するHTML5アプリケーションを選択する
(3)次へ
(4)サイト・ルートをindex.htmlがあるフォルダ選択する
(5)終了
(6)画面上部に実行ボタン押下すればローカルWebサーバ起動する
(7)(1)〜(6)を繰り返して、起動したいプロジェクトを追加する
以下のサイトのコードコピペでも行けたので、講義中に色々試してました。
→ GLSLで簡単2Dエフェクト
※ precision mediump float;は必要
あと、明解WebGL本は、読みやすいのでオススメです。
この本のライティング編あたりから「GLSLは超重要だ!」って思いました。
ソースコードはこちら → 明解 WebGL本ソースコード
また、前回のWebGLスクール内容やGLSLチュートリアルをやるのもオススメです。
第一回 WebGLスクール 「WebGLの概念」
[連載]やってみれば超簡単! WebGL と GLSL で始める、はじめてのシェーダコーディング(1)
いや〜、GLSLは短いコードで表現力が凄くてまったく意味がわからないw
理解できて余裕があれば次回も書いていきます