こぴぺするだけ簡単 WebGL + GLSL テンプレート

## コピペするだけ

*かんたん！*

## ソース

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <!-- フラグメントシェーダのソースコード -->
    <script id="fs" type="xs/fs">
      // フラグメントシェーダには時間の経過がtimeに秒単位で、
      // スクリーン解像度がresolutionにピクセル単位で入ってくる
      precision mediump float;
      uniform float time;
      uniform vec2  resolution;

      // HSV色空間を使うための関数
      vec3 hsv(float h, float s, float v){
        vec4 t = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
        vec3 p = abs(fract(vec3(h) + t.xyz) * 6.0 - vec3(t.w));
        return v * mix(vec3(t.x), clamp(p - vec3(t.x), 0.0, 1.0), s);
      }

      // ジュリア集合を描くためのフラグメントシェーダ
      void main(void){
        vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / max(resolution.x, resolution.y);
        int j = 0;
        vec2 x = vec2(-0.345, 0.654);     // この辺変えると……
        vec2 y = vec2(time * 0.005, 0.0); // いろいろ変わるかも
        vec2 z = p;
        for(int i = 0; i < 360; i++){
          j++;
          if(length(z) > 2.0){break;}
          z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + x + y;
        }
        float h = abs(mod(time * 15.0 - float(j), 360.0) / 360.0);
        gl_FragColor = vec4(hsv(h, 1.0, 1.0), 1.0);
      }
    </script>
    <!-- 頂点シェーダのソースコード -->
    <script id="vs" type="xs/vs">
      // 頂点シェーダには一切手入れする必要なし
      attribute vec3 position;
      void main(void){
        gl_Position = vec4(position, 1.0);
      }
    </script>
    <script>
      // オンロードイベントがエントリポイント
      window.onload = function(){
        // 変数宣言
        var a, b, c, d, e, f, g, h, p, t, u, v, w, x, y, z;

        // document.getElementByIdをローカル変数に
        b = function(s){return document.getElementById(s)};

        // ウィンドウオブジェクト
        w = window;

        // ESCキーで描画を止めるためのイベントハンドラ
        w.addEventListener('keydown', k, true);

        // HTMLドキュメント内のcanvasへの参照
        c = b('c');

        // WebGLコンテキストの取得
        g = c.getContext('webgl');

        // プログラムオブジェクトの生成
        p = g.createProgram();

        // シェーダ生成関数
        h = function(i, j){
          // シェーダオブジェクト生成
          k = g.createShader(g.VERTEX_SHADER - i);

          // ソースの割り当て
          g.shaderSource(k, j);

          // シェーダのコンパイル
          g.compileShader(k);

          // シェーダのアタッチ
          g.attachShader(p, k);

          // ログをリターン
          return g.getShaderInfoLog(k);
        }

        // シェーダのコンパイルとリンク
        if(!h(0, b('vs').text) && !h(1, b('fs').text)){g.linkProgram(p);}

        // シェーダのリンクステータスをチェック
        e = g.getProgramParameter(p, g.LINK_STATUS);

        // プログラムオブジェクトの有効化
        g.useProgram(p);

        // uniformLocation格納用にオブジェクトを定義
        u = {};

        // uniform変数timeのロケーション取得
        u.time = g.getUniformLocation(p, 'time');

        // uniform変数resolutionのロケーション取得
        u.resolution = g.getUniformLocation(p, 'resolution');

        // VBO用のバッファオブジェクトを生成
        g.bindBuffer(g.ARRAY_BUFFER, g.createBuffer());

        // VBOに頂点データを登録
        g.bufferData(g.ARRAY_BUFFER, new Float32Array([-1,1,0,-1,-1,0,1,1,0,1,-1,0]), g.STATIC_DRAW);

        // attributeロケーション取得
        a = g.getAttribLocation(p, 'position');

        // attribute有効化
        g.enableVertexAttribArray(a);
        g.vertexAttribPointer(a, 3, g.FLOAT, false, 0, 0);

        // 初期化時の色を黒に指定
        g.clearColor(0, 0, 0, 1);

        // 動作開始時間を取得（時間の経過を調べるため）
        z = new Date().getTime();

        // 無名関数でメインルーチンを実行
        (function(){
          // シェーダのリンクに失敗していたら実行しない
          if(!e){return;}

          // ビューポートを動的に指定する
          c.width = x = w.innerWidth;
          c.height = y = w.innerHeight;
          g.viewport(0, 0, x, y);

          // 時間の経過を調べる
          d = (new Date().getTime() - z) * 0.001;

          // フレームバッファをクリア
          g.clear(g.COLOR_BUFFER_BIT);

          // uniform変数をプッシュ
          g.uniform1f(u.time, d);
          g.uniform2fv(u.resolution, [x, y]);

          // プリミティブのレンダリング
          g.drawArrays(g.TRIANGLE_STRIP, 0, 4);
          g.flush();

          // 再起
          requestAnimationFrame(arguments.callee);
        })();

        // keydownに登録する関数
        function k(h){e = (h.keyCode !== 27);}
      };
    </script>
    <style>
      /* ウィンドウ全体にcanvasをぴったり配置するためのStyle */
      * {
        margin:0;
        padding:0;
        overflow:hidden;
      }
      html,body{
        height:100%;
      }
    </style>
    <title>your demo title</title>
  </head>
  <body>
    <canvas id="c"></canvas>
  </body>
</html>
```

## ブラウザで表示

*たのしい！！*

![スクリーンショット 2015-03-22 10.02.55.png](https://qiita-image-store.s3.amazonaws.com/0/39638/6f54772c-bd19-3c82-c171-792413b6a012.png)