babu_babu_babooのごみ箱

2017-05-02

クローンすべてをクリックしたときにリスナーが実行

| 11:46

クローンすべてをクリックしたときにリスナーが実行

https://okwave.jp/qa/q9323157.html

せっかく書いたのに、投稿しようと思ったらブロックされていた。もう見た人にあげる。好きなようにして!

3行で収まるんだよ!ES6をなめるな!

Mapを使ってみた。Array.every なんて久々に使ったぜ。

<!DOCTYPE html>
<title>クリックイベントは1つでいいだろう</title>
<style>
ul li.touched {background:#884}
p.hide {display:none}
</style>

<body>
<h1>例文です</h1>
<h3>すべての項目をクリックして
<ul></ul>
<p class="hide">すべての項目がクリックされました</p>

<script>
let mess = [
'質問の表題は、その不明瞭な事象を的確に表現すること',
'今後同じような悩みを抱えるであろう人のために、質問を撒き散らかさない。くだらない質問があちこちにあるとウンザリ',
'あちこちの掲示版に撒き散らかすのなら、その場所も記すこと',
'これからの人のために、自分なりの解決策を記しておくこと',
'撒き散らした場所にも解決策を記すか、その解決策に導けるように記して置くこと',
'1行程度で済ませるお礼ならしなくてもよい。但しポイントなどが付加されるならそれを行うこと',
'時間を割いて回答して頂いた人の回答の評価を故意に下げないこと',
'自分の過去の質問を読み返した時に、恥ずかしくなるような質問はしないこと。名前を変えれば良いなんて思わぬこと',
'同類の質問を何度も繰り返すのなら、ちゃんと過去のものは閉じること。というか、締め切らず喰い下がれ'
],_,m=new Map(),d=document;

mess.forEach(i=>m.set((_=d.querySelector('ul').appendChild(d.createElement('li')),_.textContent=i,_),0));
d.addEventListener('click',({target:_})=>m.has(_)?((m.get(_)?0:m.set(_,_.className='touched')),[...m.values()].every(_=>_)?d.querySelector('p.hide').className='d':0):0);

</script>

2017-04-29

WebGL 教科書の写経、その3

| 01:29

平行光源によるライティング

<!DOCTYPE html>
<meta charset="utf-8">
<title>WebGL</title>

<style>
body { background: black; }
</style>
<body>
  <canvas width="512" height="512"</canvas>
  

<!-- ※頂点シェーダ -->
<script id="vshader" type="x-shader/x-vertex">

  attribute vec3 position;
  attribute vec3 normal;
  attribute vec4 color;
  uniform   mat4 mvpMatrix;
  uniform   mat4 invMatrix;
  uniform   vec3 lightDirection;
  varying   vec4 vColor;

  void main (void) {
    vec3  invLight = normalize (invMatrix * vec4 (lightDirection, 0.0)).xyz;
    float diffuse  = clamp (dot (normal, invLight), 0.1, 1.0);
    vColor         = color * vec4 (vec3 (diffuse), 1.0);
    gl_Position    = mvpMatrix * vec4 (position, 1.0);
  }

</script>

<!-- ※フラグメントシェーダ -->
<script id="fshader" type="x-shader/x-fragment">
  precision mediump float;
  varying vec4 vColor;

  void main(void){
    gl_FragColor = vColor;
  }

</script>


<script>
{
  class Matrix4 {

    constructor (ary = [1,0,0,0,  0,1,0,0,  0,0,1,0,  0,0,0,1]) {
      let
        F = Math.fround,
        M = new Float32Array (16);
      
      for (let i = 0; i < 16; i++)
        M[i] = F (ary[i] || 0);

      this.M = M;
    }


    multiply (mat1) {
      let
        [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = this.M,
        [A, B, C, D, E, F, G, H, I, J, K, L, M, N ,O, P] = mat1.M;

      this.M = new Float32Array ([
        A * a + B * e + C * i + D * m,
        A * b + B * f + C * j + D * n,
        A * c + B * g + C * k + D * o,
        A * d + B * h + C * l + D * p,
        E * a + F * e + G * i + H * m,
        E * b + F * f + G * j + H * n,
        E * c + F * g + G * k + H * o,
        E * d + F * h + G * l + H * p,
        I * a + J * e + K * i + L * m,
        I * b + J * f + K * j + L * n,
        I * c + J * g + K * k + L * o,
        I * d + J * h + K * l + L * p,
        M * a + N * e + O * i + P * m,
        M * b + N * f + O * j + P * n,
        M * c + N * g + O * k + P * o,
        M * d + N * h + O * l + P * p
      ]);
      
      return this;
    }


    scale ([x,y,z]) {
      let [a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p] = this.M;
      this.M = new Float32Array ([
        a * x, b * x, c * x, d * x,
        e * y, f * y, g * y, h * y,
        i * z, j * z, k * z, l * z,
        m, n, o, p
      ]);
      
      return this;
    }


    translate ([x, y, z]) {
      let
        [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p] = this.M;
        
      this.M = new Float32Array ([
        a, b, c, d,
        e, f, g, h,
        i, j, k, l,
        a * x + e * y + i * z + m,
        b * x + f * y + j * z + n,
        c * x + g * y + k * z + o,
        d * x + h * y + l * z + p
      ]);

      return this;
    }


    rotate (angle, [a, b, c]) {
      let
        sq = Math.sqrt(a * a + b * b + c * c) || Number.MIN_VALUE;

//      if (! sq) throw new Error ('ベクトルが値が0です');
      if (sq != 1)//一応これが高速化?
        sq = 1 / sq; a *= sq; b *= sq; c *= sq; //単位ベクトルにしている

      let
        d = Math.sin (angle),
        e = Math.cos (angle),
        f = 1 - e,
        [g,h,i,j,k,l,m,n,o,p,q,r, B,C,D,E] = this.M,
        s = a * a * f + e,
        t = b * a * f + c * d,
        u = c * a * f - b * d,
        v = a * b * f - c * d,
        w = b * b * f + e,
        x = c * b * f + a * d,
        y = a * c * f + b * d,
        z = b * c * f - a * d,
        A = c * c * f + e;

      this.M = new Float32Array ([
        g * s + k * t + o * u,
        h * s + l * t + p * u,
        i * s + m * t + q * u,
        j * s + n * t + r * u,
        g * v + k * w + o * x,
        h * v + l * w + p * x,
        i * v + m * w + q * x,
        j * v + n * w + r * x,
        g * y + k * z + o * A,
        h * y + l * z + p * A,
        i * y + m * z + q * A,
        j * y + n * z + r * A,
        B, C, D,E
      ]);
      
      return this;
    }
    

    inverse () {
      let
        [a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p] = this.M,
        q = a * f - b * e,  r = a * g - c * e,
        s = a * h - d * e,  t = b * g - c * f,
        u = b * h - d * f,  v = c * h - d * g,
        w = i * n - j * m,  x = i * o - k * m,
        y = i * p - l * m,  z = j * o - k * n,
        A = j * p - l * n,  B = k * p - l * o,
        ivd = 1 / (q * B - r * A + s * z + t * y - u * x + v * w);

      this.M = new Float32Array ([
        ( f * B - g * A + h * z) * ivd,
        (-b * B + c * A - d * z) * ivd,
        ( n * v - o * u + p * t) * ivd,
        (-j * v + k * u - l * t) * ivd,
        (-e * B + g * y - h * x) * ivd,
        ( a * B - c * y + d * x) * ivd,
        (-m * v + o * s - p * r) * ivd,
        ( i * v - k * s + l * r) * ivd,
        ( e * A - f * y + h * w) * ivd,
        (-a * A + b * y - d * w) * ivd,
        ( m * u - n * s + p * q) * ivd,
        (-i * u + j * s - l * q) * ivd,
        (-e * z + f * x - g * w) * ivd,
        ( a * z - b * x + c * w) * ivd,
        (-m * t + n * r - o * q) * ivd,
        ( i * t - j * r + k * q) * ivd
      ]);
      
      return this;
    }
 
    
    
    copy () {
      return new Matrix4 (this.M);
    }
    

    static lookAt (eye, center, up) {
      let
        [eyeX, eyeY, eyeZ] = eye,
        [upX,  upY,  upZ]  = up,
        [centerX, centerY, centerZ] = center;

      if (eyeX == centerX && eyeY == centerY && eyeZ == centerZ)
        return (new this).identity ();

      let
        sqrt = Math.sqrt,
        z0 = eyeX - centerX,
        z1 = eyeY - centerY,
        z2 = eyeZ - centerZ,
        l = 1 / sqrt (z0 * z0 + z1 * z1 + z2 * z2);

      z0 *= l; z1 *= l; z2 *= l;

      let
        x0 = upY * z2 - upZ * z1,
        x1 = upZ * z0 - upX * z2,
        x2 = upX * z1 - upY * z0;

      l = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
      if (! l) {
        x0 = 0; x1 = 0; x2 = 0;
      } else {
        l = 1 / l;
        x0 *= l; x1 *= l; x2 *= l;
      }

      let
        y0 = z1 * x2 - z2 * x1,
        y1 = z2 * x0 - z0 * x2,
        y2 = z0 * x1 - z1 * x0;
      l = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
      if (! l) {
        y0 = 0; y1 = 0; y2 = 0;
      } else {
        l = 1 / l;
        y0 *= l; y1 *= l; y2 *= l;
      }

      return new this ([
        x0, y0, z0, 0,
        x1, y1, z1, 0,
        x2, y2, z2, 0,
        -(x0 * eyeX + x1 * eyeY + x2 * eyeZ),
        -(y0 * eyeX + y1 * eyeY + y2 * eyeZ),
        -(z0 * eyeX + z1 * eyeY + z2 * eyeZ),
        1
      ]);
    }


    static perspective (fovy, aspect, near, far) {
      let
        t = near * Math.tan (fovy * Math.PI / 360),
        r = t * aspect,
        a = r * 2, b = t * 2, c = far - near;

      return new this ([
        near * 2 / a, 0, 0, 0,
        0, near * 2 / b, 0, 0,
        0, 0, -(far + near) / c, -1,
        0, 0, -(far * near * 2) / c, 0
      ]);
    }

  }
  

  this.Matrix4 = Matrix4;
}



{// WebGL Shader Object 
  const
    ATT_STRIDE = {position: 3, normal: 3, color: 4};


  class Shader {
    constructor (canvas, vertex, fragment) {
      this.canvas   = canvas;
      this.gl       = canvas.getContext('webgl');
      this.v_shader = create_shader.call (this, vertex);
      this.f_shader = create_shader.call (this, fragment);
      this.prg      = create_program.call (this);
      this.vbo      = { };
      this.uniLocation = { mvp: null, inv: null, light: null };

      let gl = this.gl;
      gl.enable (gl.DEPTH_TEST);
      gl.depthFunc (gl.LEQUAL);
      gl.enable (gl.CULL_FACE);      

      this.clear ();
    }
    
    
    // canvas 初期化
    clear (r = 0, g = 0, b = 0, a = 1) {
      let gl = this.gl;
      gl.clearColor (r, g, b, a);
      gl.clearDepth (1.0);
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

      return this;
    }
    
    
    // Shader に VBO をセットする type = [ position, normal, color ]
    setVBO (data = [], type = 'position') {
      let
        { gl, prg } = this,
        attLocation = gl.getAttribLocation (prg, type),
        attStride = ATT_STRIDE[type],
        vbo = create_vbo.call (this, data);

      gl.bindBuffer (gl.ARRAY_BUFFER, vbo);
      gl.enableVertexAttribArray (attLocation);
      gl.vertexAttribPointer (attLocation, attStride, gl.FLOAT, false, 0, 0);
      this.vbo[type] = vbo;

      return this;
    }
    
    
    setIBO (data = []) {
      let
        gl = this.gl,
        ibo = create_ibo.call (this, data);

      gl.bindBuffer (gl.ELEMENT_ARRAY_BUFFER, ibo);
      this.ibo = ibo;
      
      return this;
    }


    setLocation () {
      let {gl, prg} = this;
      this.uniLocation = {
        mvp:   gl.getUniformLocation (prg, 'mvpMatrix'),
        inv:   gl.getUniformLocation (prg, 'invMatrix'),
        light: gl.getUniformLocation (prg, 'lightDirection')
      };
      
      return this;
    }
       
    
    draw (mvpMatrix, invMatrix, lightDirection, vertex_index, flush = true) {
      let
        {gl, prg, uniLocation} = this,
        {mvp, inv, light} = uniLocation;

      gl.uniformMatrix4fv (mvp, false, mvpMatrix);
      gl.uniformMatrix4fv (inv, false, invMatrix);
      gl.uniform3fv (light, lightDirection);

      gl.drawElements (gl.TRIANGLES, vertex_index.length, gl.UNSIGNED_SHORT, 0);
      
      if (flush)
        gl.flush ();
      
      return this;
    }
    
  }

//__________________  

  const
    SHADER_TYPE = {
      'x-shader/x-vertex': 'VERTEX_SHADER',
      'x-shader/x-fragment': 'FRAGMENT_SHADER'},


    create_shader =
      function (target = null) {
        if (target) {
          let
            gl = this.gl,
            {text, type} = target,
            shader = gl.createShader (gl[SHADER_TYPE[type]]);

          gl.shaderSource (shader, text);
          gl.compileShader (shader);
          if (! gl.getShaderParameter (shader, gl.COMPILE_STATUS))
            throw new Error (['シェーダーのコンパイルエラーがありました',
              gl.getShaderInfoLog (shader)].join ('\n'))

          return shader;
        }
        throw new Error ('要素がありません');
      },


    // プログラムオブジェクトを生成しシェーダをリンクする関数
    create_program =
      function () {
        let
          gl = this.gl,
          program = gl.createProgram ();

        gl.attachShader (program, this.v_shader);
        gl.attachShader (program, this.f_shader);
        gl.linkProgram (program);

        if (! gl.getProgramParameter(program, gl.LINK_STATUS))
          throw new Error (['プログラムのオブジェクトの生成に失敗しました',
            gl.getProgramInfoLog (program)].join ('\n'));

        gl.useProgram (program);
        return program;
      },


    create_vbo =
      function (data) {
        let
          gl = this.gl,
          vbo = gl.createBuffer (),
          buf = gl.ARRAY_BUFFER;

        gl.bindBuffer (buf, vbo);
        gl.bufferData (buf, new Float32Array (data), gl.STATIC_DRAW);
        gl.bindBuffer (buf, null);

        return vbo;
      },
    
    
    create_ibo =
      function (data) {
        let
          gl = this.gl,
          ibo = gl.createBuffer (),
          buf = gl.ELEMENT_ARRAY_BUFFER;

        gl.bindBuffer (buf, ibo);
        gl.bufferData (buf, new Int16Array (data), gl.STATIC_DRAW);
        gl.bindBuffer (buf, null);

        return ibo;
      };
      

  //_______
  
  this.Shader = Shader;
}

//_________
  function torus(row, column, irad, orad){
    var pos = new Array(), nor = new Array(),
      col = new Array(), idx = new Array();
    for(var i = 0; i <= row; i++){
      var r = Math.PI * 2 / row * i;
      var rr = Math.cos(r);
      var ry = Math.sin(r);
      for(var ii = 0; ii <= column; ii++){
        var tr = Math.PI * 2 / column * ii;
        var tx = (rr * irad + orad) * Math.cos(tr);
        var ty = ry * irad;
        var tz = (rr * irad + orad) * Math.sin(tr);
        var rx = rr * Math.cos(tr);
        var rz = rr * Math.sin(tr);
        pos.push(tx, ty, tz);
        nor.push(rx, ry, rz);
        var tc = hsva(360 / column * ii, 1, 1, 1);
        col.push(tc[0], tc[1], tc[2], tc[3]);
      }
    }
    for(i = 0; i < row; i++){
      for(ii = 0; ii < column; ii++){
        r = (column + 1) * i + ii;
        idx.push(r, r + column + 1, r + 1);
        idx.push(r + column + 1, r + column + 2, r + 1);
      }
    }
    return [pos, nor, col, idx];
  }  
  // HSVカラー取得用関数
  function hsva(h, s, v, a){
    if(s > 1 || v > 1 || a > 1){return;}
    var th = h % 360;
    var i = Math.floor(th / 60);
    var f = th / 60 - i;
    var m = v * (1 - s);
    var n = v * (1 - s * f);
    var k = v * (1 - s * (1 - f));
    var color = new Array();
    if(!s > 0 && !s < 0){
      color.push(v, v, v, a); 
    } else {
      var r = new Array(v, n, m, m, k, v);
      var g = new Array(k, v, v, n, m, m);
      var b = new Array(m, m, k, v, v, n);
      color.push(r[i], g[i], b[i], a);
    }
    return color;
  }



{//実行スクリプト
  let
    doc = document,
    canvas = doc.querySelector ('canvas'),
    shader = new Shader (
      canvas,
      doc.querySelector ('script[type="x-shader/x-vertex"]'),
      doc.querySelector ('script[type="x-shader/x-fragment"]'),
    ),

    // 各種行列の生成と初期化
    matrix = Matrix4.perspective (45, canvas.width / canvas.height, 0.1, 100)
             .multiply (Matrix4.lookAt ([0, 0, 10.0], [0, 0, 0], [0, 1, 0]))
             .multiply (new Matrix4),
    // 光のベクトル
    lightDirection = [-0.5, 0.5, 0.5],

    // モデル(頂点)データ
    [vertex_position, vector_normal, vertex_color, vertex_index]
      = torus (72, 72, 1.0, 2.0);


  shader.setLocation ();
  shader.setVBO (vertex_position, 'position');
  shader.setVBO (vector_normal, 'normal');
  shader.setVBO (vertex_color, 'color');
  shader.setIBO (vertex_index);

  //_____
  
  let cnt = 0, pi = Math.PI, deg = pi / 180;

  const loop = function (timeStamp) {
    
    shader.clear ();

    let
      rad = (cnt++ %360) * deg,
      m = (new Matrix4).rotate (rad, [0, 1, 1]),
      mMatrix = matrix.copy ().multiply (m),      
      invMatrix = m.copy ().inverse ();
    
    shader.draw (mMatrix.M, invMatrix.M, lightDirection, vertex_index);

    requestAnimationFrame (loop);
  }
  
  loop ();
}

</script>

2017-04-28

WebGL 教科書の写経、その2

| 09:13

複数モデルのレンダリング

https://wgld.org/d/webgl/w016.html

教科書にあるマトリクスのライブラリなのだが、使い方がオブジェクト指向ではなく、たんなるマトリクス関数の集合体だけの使い方のように思えてきた。

そのライブラリは少しずつ自分用のライブラリに移植している。

<!DOCTYPE html>
<meta charset="utf-8">
<title>WebGL</title>

<style>
</style>

<body>
  <canvas width="1024" height="512"</canvas>
  

<!-- ※頂点シェーダ -->
<script id="vshader" type="x-shader/x-vertex">
attribute vec3 position;
attribute vec4 color;
uniform   mat4 mvpMatrix;
varying   vec4 vColor;

void main (void){
    vColor = color;
    gl_Position = mvpMatrix * vec4(position, 1.0);
}

</script>

<!-- ※フラグメントシェーダ -->
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;

varying vec4 vColor;

void main(void){
    gl_FragColor = vColor;
}


</script>


<script>
{
  class Matrix4 {

    constructor (ary = [1,0,0,0,  0,1,0,0,  0,0,1,0,  0,0,0,1]) {
      let
        F = Math.fround,
        M = new Float32Array (16);
      
      for (let i = 0; i < 16; i++)
        M[i] = F (ary[i] || 0);

      this.M = M;
    }


    multiply (mat1) {
      let
        [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = this.M,
        [A, B, C, D, E, F, G, H, I, J, K, L, M, N ,O, P] = mat1.M;

      this.M = new Float32Array ([
        A * a + B * e + C * i + D * m,
        A * b + B * f + C * j + D * n,
        A * c + B * g + C * k + D * o,
        A * d + B * h + C * l + D * p,
        E * a + F * e + G * i + H * m,
        E * b + F * f + G * j + H * n,
        E * c + F * g + G * k + H * o,
        E * d + F * h + G * l + H * p,
        I * a + J * e + K * i + L * m,
        I * b + J * f + K * j + L * n,
        I * c + J * g + K * k + L * o,
        I * d + J * h + K * l + L * p,
        M * a + N * e + O * i + P * m,
        M * b + N * f + O * j + P * n,
        M * c + N * g + O * k + P * o,
        M * d + N * h + O * l + P * p
      ]);
      
      return this;
    }


    scale ([x,y,z]) {
      let m = this.M;
      this.M = new Float32Array ([
        m[0] * x,  m[1] * x,  m[2] * x,  m[3] * x,
        m[4] * y,  m[5] * y,  m[6] * y,  m[7] * y,
        m[8] * z,  m[9] * z,  m[10]* z,  m[11]* z,
        m[12],     m[13],     m[14],     m[15]
      ]);
      
      return this;
    }


    translate ([x, y, z]) {
      let
        [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p] = this.M;
        
      this.M = new Float32Array ([
        a, b, c, d,
        e, f, g, h,
        i, j, k, l,
        a * x + e * y + i * z + m,
        b * x + f * y + j * z + n,
        c * x + g * y + k * z + o,
        d * x + h * y + l * z + p
      ]);

      return this;
    }


    rotate (mat, angle, [a, b, c]) {
      let
        sq = Math.sqrt(a * a + b * b + c * c);

      if (! sq)
        return null;
      if (sq != 1) {
        sq = 1 / sq; a *= sq; b *= sq; c *= sq; //?angle
      }

      let
        d = Math.sin (angle),
        e = Math.cos (angle),
        f = 1 - e,
        g = mat[0],  h = mat[1], i = mat[2],  j = mat[3],
        k = mat[4],  l = mat[5], m = mat[6],  n = mat[7],
        o = mat[8],  p = mat[9], q = mat[10], r = mat[11],
        s = a * a * f + e,
        t = b * a * f + c * d,
        u = c * a * f - b * d,
        v = a * b * f - c * d,
        w = b * b * f + e,
        x = c * b * f + a * d,
        y = a * c * f + b * d,
        z = b * c * f - a * d,
        A = c * c * f + e;

      if (angle) {
        if(mat != dest) {
          dest[12] = mat[12]; dest[13] = mat[13];
          dest[14] = mat[14]; dest[15] = mat[15];
        }
      } else {
        dest = mat;
      }
      return new Matrix4([
        g * s + k * t + o * u,
        h * s + l * t + p * u,
        i * s + m * t + q * u,
        j * s + n * t + r * u,
        g * v + k * w + o * x,
        h * v + l * w + p * x,
        i * v + m * w + q * x,
        j * v + n * w + r * x,
        g * y + k * z + o * A,
        h * y + l * z + p * A,
        i * y + m * z + q * A,
        j * y + n * z + r * A
      ]);
    }
    
    
    copy () {
      return new Matrix4 (this.M);
    }


    static lookAt (eye, center, up) {
      let
        [eyeX, eyeY, eyeZ] = eye,
        [upX,  upY,  upZ]  = up,
        [centerX, centerY, centerZ] = center;

      if (eyeX == centerX && eyeY == centerY && eyeZ == centerZ)
        return (new this).identity ();

      let
        sqrt = Math.sqrt,
        z0 = eyeX - centerX,
        z1 = eyeY - centerY,
        z2 = eyeZ - centerZ,
        l = 1 / sqrt (z0 * z0 + z1 * z1 + z2 * z2);

      z0 *= l; z1 *= l; z2 *= l;

      let
        x0 = upY * z2 - upZ * z1,
        x1 = upZ * z0 - upX * z2,
        x2 = upX * z1 - upY * z0;

      l = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
      if (! l) {
        x0 = 0; x1 = 0; x2 = 0;
      } else {
        l = 1 / l;
        x0 *= l; x1 *= l; x2 *= l;
      }

      let
        y0 = z1 * x2 - z2 * x1,
        y1 = z2 * x0 - z0 * x2,
        y2 = z0 * x1 - z1 * x0;
      l = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
      if (! l) {
        y0 = 0; y1 = 0; y2 = 0;
      } else {
        l = 1 / l;
        y0 *= l; y1 *= l; y2 *= l;
      }

      return new this ([
        x0, y0, z0, 0,
        x1, y1, z1, 0,
        x2, y2, z2, 0,
        -(x0 * eyeX + x1 * eyeY + x2 * eyeZ),
        -(y0 * eyeX + y1 * eyeY + y2 * eyeZ),
        -(z0 * eyeX + z1 * eyeY + z2 * eyeZ),
        1
      ]);
    }


    static perspective (fovy, aspect, near, far) {
      let
        t = near * Math.tan (fovy * Math.PI / 360),
        r = t * aspect,
        a = r * 2, b = t * 2, c = far - near;

      return new this ([
        near * 2 / a, 0, 0, 0,
        0, near * 2 / b, 0, 0,
        0, 0, -(far + near) / c, -1,
        0, 0, -(far * near * 2) / c, 0
      ]);
    }

  }
  

  this.Matrix4 = Matrix4;
}

function matIV(){
	this.create = function(){
		return new Float32Array(16);
	};


	this.transpose = function(mat, dest){
		dest[0]  = mat[0];  dest[1]  = mat[4];
		dest[2]  = mat[8];  dest[3]  = mat[12];
		dest[4]  = mat[1];  dest[5]  = mat[5];
		dest[6]  = mat[9];  dest[7]  = mat[13];
		dest[8]  = mat[2];  dest[9]  = mat[6];
		dest[10] = mat[10]; dest[11] = mat[14];
		dest[12] = mat[3];  dest[13] = mat[7];
		dest[14] = mat[11]; dest[15] = mat[15];
		return dest;
	};

	this.inverse = function(mat, dest){
		var a = mat[0],  b = mat[1],  c = mat[2],  d = mat[3],
			e = mat[4],  f = mat[5],  g = mat[6],  h = mat[7],
			i = mat[8],  j = mat[9],  k = mat[10], l = mat[11],
			m = mat[12], n = mat[13], o = mat[14], p = mat[15],
			q = a * f - b * e, r = a * g - c * e,
			s = a * h - d * e, t = b * g - c * f,
			u = b * h - d * f, v = c * h - d * g,
			w = i * n - j * m, x = i * o - k * m,
			y = i * p - l * m, z = j * o - k * n,
			A = j * p - l * n, B = k * p - l * o,
			ivd = 1 / (q * B - r * A + s * z + t * y - u * x + v * w);
		dest[0]  = ( f * B - g * A + h * z) * ivd;
		dest[1]  = (-b * B + c * A - d * z) * ivd;
		dest[2]  = ( n * v - o * u + p * t) * ivd;
		dest[3]  = (-j * v + k * u - l * t) * ivd;
		dest[4]  = (-e * B + g * y - h * x) * ivd;
		dest[5]  = ( a * B - c * y + d * x) * ivd;
		dest[6]  = (-m * v + o * s - p * r) * ivd;
		dest[7]  = ( i * v - k * s + l * r) * ivd;
		dest[8]  = ( e * A - f * y + h * w) * ivd;
		dest[9]  = (-a * A + b * y - d * w) * ivd;
		dest[10] = ( m * u - n * s + p * q) * ivd;
		dest[11] = (-i * u + j * s - l * q) * ivd;
		dest[12] = (-e * z + f * x - g * w) * ivd;
		dest[13] = ( a * z - b * x + c * w) * ivd;
		dest[14] = (-m * t + n * r - o * q) * ivd;
		dest[15] = ( i * t - j * r + k * q) * ivd;
		return dest;
	};
}


{
  class Shader {
    constructor (canvas, vertex, fragment) {
      this.canvas = canvas;
      this.gl = canvas.getContext('webgl');
      this.v_shader = create_shader.call (this, vertex);
      this.f_shader = create_shader.call (this, fragment);
      this.prg = create_program.call (this);
      this.vbo = {};

      
      this.clear ();
    }
    
    
    clear (r = 0, g = 0, b = 0, a = 1) {
      let gl = this.gl;
      gl.clearColor (r, g, b, a);
      gl.clearDepth (1.0);
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

      return this;
    }
    
    
    setVBO (data = [], type = 'position') {
      let
        gl = this.gl,
        attLocation = gl.getAttribLocation (this.prg, type),
        attStride = {position: 3, color: 4}[type],
        vbo = create_vbo.call (this, data);
     
      gl.bindBuffer (gl.ARRAY_BUFFER, vbo);
      gl.enableVertexAttribArray (attLocation);
      gl.vertexAttribPointer (attLocation, attStride, gl.FLOAT, false, 0, 0);
      this.vbo[type] = vbo;

      return this;
    }
    
    
    draw (mvpMatrix, flash = true) {
      let
        {gl, prg} = this,
        uniLocation = gl.getUniformLocation (prg, 'mvpMatrix');
      gl.uniformMatrix4fv (uniLocation, false, mvpMatrix);
      gl.drawArrays (gl.TRIANGLES, 0, 3);
      
      if (flash)
        gl.flush ();
      
      return this;
    }
    
    
  }
  

  const
    SHADER_TYPE = {
      'x-shader/x-vertex': 'VERTEX_SHADER',
      'x-shader/x-fragment': 'FRAGMENT_SHADER'},

    create_shader =
      function (target = null) {
        if (target) {
          let
            gl = this.gl,
            {text, type} = target,
            shader = gl.createShader (gl[SHADER_TYPE[type]]);

          gl.shaderSource (shader, text);
          gl.compileShader (shader);
          if (! gl.getShaderParameter (shader, gl.COMPILE_STATUS))
            throw new Error (['シェーダーのコンパイルエラーがありました',
              gl.getShaderInfoLog (shader)].join ('\n'))

          return shader;
        }
        throw new Error ('要素がありません');
      },


      // プログラムオブジェクトを生成しシェーダをリンクする関数
    create_program =
      function () {
        let
          gl = this.gl,
          program = gl.createProgram();

        gl.attachShader (program, this.v_shader);
        gl.attachShader (program, this.f_shader);
        gl.linkProgram (program);

        if (! gl.getProgramParameter(program, gl.LINK_STATUS))
          throw new Error (['プログラムのオブジェクトの生成に失敗しました',
            gl.getProgramInfoLog (program)].join ('\n'));

        gl.useProgram (program);
        return program;
      },


	  create_vbo =
	    function (data) {
	      let
	        gl = this.gl,
	        vbo = gl.createBuffer ();

        gl.bindBuffer (gl.ARRAY_BUFFER, vbo);
        gl.bufferData (gl.ARRAY_BUFFER, new Float32Array (data), gl.STATIC_DRAW);
        gl.bindBuffer (gl.ARRAY_BUFFER, null);

        return vbo;
      };
      

  //_______
  
  this.Shader = Shader;
}


{//実行スクリプト
	let
	  doc = document,
	  canvas = doc.querySelector ('canvas'),
	  shader = new Shader (
	    canvas,
	    doc.querySelector ('script[type="x-shader/x-vertex"]'),
	    doc.querySelector ('script[type="x-shader/x-fragment"]'),
	  ),
    // モデル(頂点)データ
    vertex_position = [
      0.0, 1.0, 0.0,
      1.0, 0.0, 0.0,
      -1.0, 0.0, 0.0
    ],
    vertex_color = [
      1.0, 0.0, 0.0, 1.0,
      0.0, 1.0, 0.0, 1.0,
      0.0, 0.0, 1.0, 1.0
    ],

    // 各種行列の生成と初期化
    matrix = Matrix4.perspective (90, canvas.width / canvas.height, 0.1, 100)
             .multiply (Matrix4.lookAt ([0.0, 1.0, 3.0], [0, 0, 0], [0, 1, 0]))
             .multiply (new Matrix4);
    

  shader.setVBO (vertex_position, 'position');
  shader.setVBO (vertex_color, 'color');

  shader.draw (matrix.copy ().translate ([1.5,0,0]).M, false);
  shader.draw (matrix.translate ([-1.5,0,0]).M);
}

</script>

再帰処理と移動・回転・拡大縮小

https://wgld.org/d/webgl/w017.html

マトリクスのライブラリの移植終了。

これまでの勉強がかなり役立っている。何をしているのかスルスルわかる。

移植は脳内変換スムーズに移行中、タイマーイベントから、アニメーションに変更。

<!DOCTYPE html>
<meta charset="utf-8">
<title>WebGL</title>

<style>
</style>

<body>
  <canvas width="1024" height="512"</canvas>
  

<!-- ※頂点シェーダ -->
<script id="vshader" type="x-shader/x-vertex">
attribute vec3 position;
attribute vec4 color;
uniform   mat4 mvpMatrix;
varying   vec4 vColor;

void main (void){
    vColor = color;
    gl_Position = mvpMatrix * vec4(position, 1.0);
}

</script>

<!-- ※フラグメントシェーダ -->
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;

varying vec4 vColor;

void main(void){
    gl_FragColor = vColor;
}


</script>


<script>
{
  class Matrix4 {

    constructor (ary = [1,0,0,0,  0,1,0,0,  0,0,1,0,  0,0,0,1]) {
      let
        F = Math.fround,
        M = new Float32Array (16);
      
      for (let i = 0; i < 16; i++)
        M[i] = F (ary[i] || 0);

      this.M = M;
    }


    multiply (mat1) {
      let
        [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = this.M,
        [A, B, C, D, E, F, G, H, I, J, K, L, M, N ,O, P] = mat1.M;

      this.M = new Float32Array ([
        A * a + B * e + C * i + D * m,
        A * b + B * f + C * j + D * n,
        A * c + B * g + C * k + D * o,
        A * d + B * h + C * l + D * p,
        E * a + F * e + G * i + H * m,
        E * b + F * f + G * j + H * n,
        E * c + F * g + G * k + H * o,
        E * d + F * h + G * l + H * p,
        I * a + J * e + K * i + L * m,
        I * b + J * f + K * j + L * n,
        I * c + J * g + K * k + L * o,
        I * d + J * h + K * l + L * p,
        M * a + N * e + O * i + P * m,
        M * b + N * f + O * j + P * n,
        M * c + N * g + O * k + P * o,
        M * d + N * h + O * l + P * p
      ]);
      
      return this;
    }


    scale ([x,y,z]) {
      let [a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p] = this.M;
      this.M = new Float32Array ([
        a * x, b * x, c * x, d * x,
        e * y, f * y, g * y, h * y,
        i * z, j * z, k * z, l * z,
        m, n, o, p
      ]);
      
      return this;
    }


    translate ([x, y, z]) {
      let
        [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p] = this.M;
        
      this.M = new Float32Array ([
        a, b, c, d,
        e, f, g, h,
        i, j, k, l,
        a * x + e * y + i * z + m,
        b * x + f * y + j * z + n,
        c * x + g * y + k * z + o,
        d * x + h * y + l * z + p
      ]);

      return this;
    }


    rotate (angle, [a, b, c]) {//a,b,cは多分ベクトルだろう。後で四元数で回せるから
      let
        sq = Math.sqrt(a * a + b * b + c * c);

      if (! sq)
        throw new Error ('ベクトルが値が0です');
      if (sq != 1)//一応これが高速化?
        sq = 1 / sq; a *= sq; b *= sq; c *= sq; //単位ベクトルにしている

      let
        d = Math.sin (angle),
        e = Math.cos (angle),
        f = 1 - e,
        [g,h,i,j,k,l,m,n,o,p,q,r, B,C,D,E] = this.M,
        s = a * a * f + e,
        t = b * a * f + c * d,
        u = c * a * f - b * d,
        v = a * b * f - c * d,
        w = b * b * f + e,
        x = c * b * f + a * d,
        y = a * c * f + b * d,
        z = b * c * f - a * d,
        A = c * c * f + e;

      this.M = new Float32Array ([
        g * s + k * t + o * u,
        h * s + l * t + p * u,
        i * s + m * t + q * u,
        j * s + n * t + r * u,
        g * v + k * w + o * x,
        h * v + l * w + p * x,
        i * v + m * w + q * x,
        j * v + n * w + r * x,
        g * y + k * z + o * A,
        h * y + l * z + p * A,
        i * y + m * z + q * A,
        j * y + n * z + r * A,
        B, C, D,E
      ]);
      
      return this;
    }
    

	  inverse (mat, dest) {
	    let
	      [a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p] = this.M,
        q = a * f - b * e,  r = a * g - c * e,
        s = a * h - d * e,  t = b * g - c * f,
        u = b * h - d * f,  v = c * h - d * g,
        w = i * n - j * m,  x = i * o - k * m,
        y = i * p - l * m,  z = j * o - k * n,
        A = j * p - l * n,  B = k * p - l * o,
        ivd = 1 / (q * B - r * A + s * z + t * y - u * x + v * w);

      this.M = new Float32Array ([
        ( f * B - g * A + h * z) * ivd,
        (-b * B + c * A - d * z) * ivd,
        ( n * v - o * u + p * t) * ivd,
        (-j * v + k * u - l * t) * ivd,
        (-e * B + g * y - h * x) * ivd,
        ( a * B - c * y + d * x) * ivd,
        (-m * v + o * s - p * r) * ivd,
        ( i * v - k * s + l * r) * ivd,
        ( e * A - f * y + h * w) * ivd,
        (-a * A + b * y - d * w) * ivd,
        ( m * u - n * s + p * q) * ivd,
        (-i * u + j * s - l * q) * ivd,
        (-e * z + f * x - g * w) * ivd,
        ( a * z - b * x + c * w) * ivd,
        (-m * t + n * r - o * q) * ivd,
        ( i * t - j * r + k * q) * ivd
      ]);
      
      return this;
	  };
    
    
    
    copy () {
      return new Matrix4 (this.M);
    }
    
    transpose () {
      return new Matrix4 (this.M);    
    }


    static lookAt (eye, center, up) {
      let
        [eyeX, eyeY, eyeZ] = eye,
        [upX,  upY,  upZ]  = up,
        [centerX, centerY, centerZ] = center;

      if (eyeX == centerX && eyeY == centerY && eyeZ == centerZ)
        return (new this).identity ();

      let
        sqrt = Math.sqrt,
        z0 = eyeX - centerX,
        z1 = eyeY - centerY,
        z2 = eyeZ - centerZ,
        l = 1 / sqrt (z0 * z0 + z1 * z1 + z2 * z2);

      z0 *= l; z1 *= l; z2 *= l;

      let
        x0 = upY * z2 - upZ * z1,
        x1 = upZ * z0 - upX * z2,
        x2 = upX * z1 - upY * z0;

      l = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
      if (! l) {
        x0 = 0; x1 = 0; x2 = 0;
      } else {
        l = 1 / l;
        x0 *= l; x1 *= l; x2 *= l;
      }

      let
        y0 = z1 * x2 - z2 * x1,
        y1 = z2 * x0 - z0 * x2,
        y2 = z0 * x1 - z1 * x0;
      l = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
      if (! l) {
        y0 = 0; y1 = 0; y2 = 0;
      } else {
        l = 1 / l;
        y0 *= l; y1 *= l; y2 *= l;
      }

      return new this ([
        x0, y0, z0, 0,
        x1, y1, z1, 0,
        x2, y2, z2, 0,
        -(x0 * eyeX + x1 * eyeY + x2 * eyeZ),
        -(y0 * eyeX + y1 * eyeY + y2 * eyeZ),
        -(z0 * eyeX + z1 * eyeY + z2 * eyeZ),
        1
      ]);
    }


    static perspective (fovy, aspect, near, far) {
      let
        t = near * Math.tan (fovy * Math.PI / 360),
        r = t * aspect,
        a = r * 2, b = t * 2, c = far - near;

      return new this ([
        near * 2 / a, 0, 0, 0,
        0, near * 2 / b, 0, 0,
        0, 0, -(far + near) / c, -1,
        0, 0, -(far * near * 2) / c, 0
      ]);
    }

  }
  

  this.Matrix4 = Matrix4;
}


{
  class Shader {
    constructor (canvas, vertex, fragment) {
      this.canvas = canvas;
      this.gl = canvas.getContext('webgl');
      this.v_shader = create_shader.call (this, vertex);
      this.f_shader = create_shader.call (this, fragment);
      this.prg = create_program.call (this);
      this.vbo = {};

      
      this.clear ();
    }
    
    
    clear (r = 0, g = 0, b = 0, a = 1) {
      let gl = this.gl;
      gl.clearColor (r, g, b, a);
      gl.clearDepth (1.0);
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

      return this;
    }
    
    
    setVBO (data = [], type = 'position') {
      let
        gl = this.gl,
        attLocation = gl.getAttribLocation (this.prg, type),
        attStride = {position: 3, color: 4}[type],
        vbo = create_vbo.call (this, data);
     
      gl.bindBuffer (gl.ARRAY_BUFFER, vbo);
      gl.enableVertexAttribArray (attLocation);
      gl.vertexAttribPointer (attLocation, attStride, gl.FLOAT, false, 0, 0);
      this.vbo[type] = vbo;

      return this;
    }
    
    
    draw (mvpMatrix, flash = true) {
      let
        {gl, prg} = this,
        uniLocation = gl.getUniformLocation (prg, 'mvpMatrix');
      gl.uniformMatrix4fv (uniLocation, false, mvpMatrix);
      gl.drawArrays (gl.TRIANGLES, 0, 3);
      
      if (flash)
        gl.flush ();
      
      return this;
    }
    
    
  }
  

  const
    SHADER_TYPE = {
      'x-shader/x-vertex': 'VERTEX_SHADER',
      'x-shader/x-fragment': 'FRAGMENT_SHADER'},

    create_shader =
      function (target = null) {
        if (target) {
          let
            gl = this.gl,
            {text, type} = target,
            shader = gl.createShader (gl[SHADER_TYPE[type]]);

          gl.shaderSource (shader, text);
          gl.compileShader (shader);
          if (! gl.getShaderParameter (shader, gl.COMPILE_STATUS))
            throw new Error (['シェーダーのコンパイルエラーがありました',
              gl.getShaderInfoLog (shader)].join ('\n'))

          return shader;
        }
        throw new Error ('要素がありません');
      },


      // プログラムオブジェクトを生成しシェーダをリンクする関数
    create_program =
      function () {
        let
          gl = this.gl,
          program = gl.createProgram();

        gl.attachShader (program, this.v_shader);
        gl.attachShader (program, this.f_shader);
        gl.linkProgram (program);

        if (! gl.getProgramParameter(program, gl.LINK_STATUS))
          throw new Error (['プログラムのオブジェクトの生成に失敗しました',
            gl.getProgramInfoLog (program)].join ('\n'));

        gl.useProgram (program);
        return program;
      },


	  create_vbo =
	    function (data) {
	      let
	        gl = this.gl,
	        vbo = gl.createBuffer ();

        gl.bindBuffer (gl.ARRAY_BUFFER, vbo);
        gl.bufferData (gl.ARRAY_BUFFER, new Float32Array (data), gl.STATIC_DRAW);
        gl.bindBuffer (gl.ARRAY_BUFFER, null);

        return vbo;
      };
      

  //_______
  
  this.Shader = Shader;
}


{//実行スクリプト
	let
	  doc = document,
	  canvas = doc.querySelector ('canvas'),
	  shader = new Shader (
	    canvas,
	    doc.querySelector ('script[type="x-shader/x-vertex"]'),
	    doc.querySelector ('script[type="x-shader/x-fragment"]'),
	  ),
    // モデル(頂点)データ
    vertex_position = [
      0.0, 1.0, 0.0,
      1.0, 0.0, 0.0,
      -1.0, 0.0, 0.0
    ],
    vertex_color = [
      1.0, 0.0, 0.0, 1.0,
      0.0, 1.0, 0.0, 1.0,
      0.0, 0.0, 1.0, 1.0
    ],

    // 各種行列の生成と初期化
    matrix = Matrix4.perspective (90, canvas.width / canvas.height, 0.1, 100)
             .multiply (Matrix4.lookAt ([0.0, 1.0, 3.0], [0, 0, 0], [0, 1, 0]))
             .multiply (new Matrix4);
    


  shader.setVBO (vertex_position, 'position');
  shader.setVBO (vertex_color, 'color');


  //_____
  
  let
    start = + new Date,
    deg = Math.PI / 180,
    {sin, cos} = Math;
    
  const loop = function (timeStamp) {
    let
      count = (timeStamp - start) / 30,
      rad = (count % 360) * deg;
    
    
    shader.clear ();
    
    // model-1 円の軌道を描き移動
    let
      x = cos (rad),
      y = sin (rad),
      m1 = (new Matrix4).translate ([x, y + 1, 0]),
      m1_Matrix = matrix.copy ().multiply (m1);
    
    // model-2 Y軸を中心に回転
    let
      m2 = (new Matrix4).translate ([1,-1,0]).rotate (rad, [0,1,0]),
      m2_Matrix = matrix.copy ().multiply (m2);
    
    // model-3 拡大縮小
    let
      s = sin (rad) + 1,
      m3 = (new Matrix4).translate ([-1,-1,0]).scale ([s,s,0]),
      m3_Matrix = matrix.copy ().multiply (m3);


    shader.draw (m1_Matrix.M);
    shader.draw (m2_Matrix.M);
    shader.draw (m3_Matrix.M);
  
    requestAnimationFrame (loop);
  }
  
  loop ();
}

</script>


インデックスバッファによる描画

https://wgld.org/d/webgl/w018.html

まだまだ余裕。

<!DOCTYPE html>
<meta charset="utf-8">
<title>WebGL</title>

<style>
</style>

<body>
  <canvas width="1024" height="512"</canvas>
  

<!-- ※頂点シェーダ -->
<script id="vshader" type="x-shader/x-vertex">
attribute vec3 position;
attribute vec4 color;
uniform   mat4 mvpMatrix;
varying   vec4 vColor;

void main (void){
    vColor = color;
    gl_Position = mvpMatrix * vec4(position, 1.0);
}

</script>

<!-- ※フラグメントシェーダ -->
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;

varying vec4 vColor;

void main(void){
    gl_FragColor = vColor;
}


</script>


<script>
{
  class Matrix4 {

    constructor (ary = [1,0,0,0,  0,1,0,0,  0,0,1,0,  0,0,0,1]) {
      let
        F = Math.fround,
        M = new Float32Array (16);
      
      for (let i = 0; i < 16; i++)
        M[i] = F (ary[i] || 0);

      this.M = M;
    }


    multiply (mat1) {
      let
        [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = this.M,
        [A, B, C, D, E, F, G, H, I, J, K, L, M, N ,O, P] = mat1.M;

      this.M = new Float32Array ([
        A * a + B * e + C * i + D * m,
        A * b + B * f + C * j + D * n,
        A * c + B * g + C * k + D * o,
        A * d + B * h + C * l + D * p,
        E * a + F * e + G * i + H * m,
        E * b + F * f + G * j + H * n,
        E * c + F * g + G * k + H * o,
        E * d + F * h + G * l + H * p,
        I * a + J * e + K * i + L * m,
        I * b + J * f + K * j + L * n,
        I * c + J * g + K * k + L * o,
        I * d + J * h + K * l + L * p,
        M * a + N * e + O * i + P * m,
        M * b + N * f + O * j + P * n,
        M * c + N * g + O * k + P * o,
        M * d + N * h + O * l + P * p
      ]);
      
      return this;
    }


    scale ([x,y,z]) {
      let [a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p] = this.M;
      this.M = new Float32Array ([
        a * x, b * x, c * x, d * x,
        e * y, f * y, g * y, h * y,
        i * z, j * z, k * z, l * z,
        m, n, o, p
      ]);
      
      return this;
    }


    translate ([x, y, z]) {
      let
        [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p] = this.M;
        
      this.M = new Float32Array ([
        a, b, c, d,
        e, f, g, h,
        i, j, k, l,
        a * x + e * y + i * z + m,
        b * x + f * y + j * z + n,
        c * x + g * y + k * z + o,
        d * x + h * y + l * z + p
      ]);

      return this;
    }


    rotate (angle, [a, b, c]) {//a,b,cは多分ベクトルだろう。後で四元数で回せるから
      let
        sq = Math.sqrt(a * a + b * b + c * c);

      if (! sq)
        throw new Error ('ベクトルが値が0です');
      if (sq != 1)//一応これが高速化?
        sq = 1 / sq; a *= sq; b *= sq; c *= sq; //単位ベクトルにしている

      let
        d = Math.sin (angle),
        e = Math.cos (angle),
        f = 1 - e,
        [g,h,i,j,k,l,m,n,o,p,q,r, B,C,D,E] = this.M,
        s = a * a * f + e,
        t = b * a * f + c * d,
        u = c * a * f - b * d,
        v = a * b * f - c * d,
        w = b * b * f + e,
        x = c * b * f + a * d,
        y = a * c * f + b * d,
        z = b * c * f - a * d,
        A = c * c * f + e;

      this.M = new Float32Array ([
        g * s + k * t + o * u,
        h * s + l * t + p * u,
        i * s + m * t + q * u,
        j * s + n * t + r * u,
        g * v + k * w + o * x,
        h * v + l * w + p * x,
        i * v + m * w + q * x,
        j * v + n * w + r * x,
        g * y + k * z + o * A,
        h * y + l * z + p * A,
        i * y + m * z + q * A,
        j * y + n * z + r * A,
        B, C, D,E
      ]);
      
      return this;
    }
    

	  inverse (mat, dest) {
	    let
	      [a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p] = this.M,
        q = a * f - b * e,  r = a * g - c * e,
        s = a * h - d * e,  t = b * g - c * f,
        u = b * h - d * f,  v = c * h - d * g,
        w = i * n - j * m,  x = i * o - k * m,
        y = i * p - l * m,  z = j * o - k * n,
        A = j * p - l * n,  B = k * p - l * o,
        ivd = 1 / (q * B - r * A + s * z + t * y - u * x + v * w);

      this.M = new Float32Array ([
        ( f * B - g * A + h * z) * ivd,
        (-b * B + c * A - d * z) * ivd,
        ( n * v - o * u + p * t) * ivd,
        (-j * v + k * u - l * t) * ivd,
        (-e * B + g * y - h * x) * ivd,
        ( a * B - c * y + d * x) * ivd,
        (-m * v + o * s - p * r) * ivd,
        ( i * v - k * s + l * r) * ivd,
        ( e * A - f * y + h * w) * ivd,
        (-a * A + b * y - d * w) * ivd,
        ( m * u - n * s + p * q) * ivd,
        (-i * u + j * s - l * q) * ivd,
        (-e * z + f * x - g * w) * ivd,
        ( a * z - b * x + c * w) * ivd,
        (-m * t + n * r - o * q) * ivd,
        ( i * t - j * r + k * q) * ivd
      ]);
      
      return this;
	  };
    
    
    
    copy () {
      return new Matrix4 (this.M);
    }
    
    transpose () {
      return new Matrix4 (this.M);    
    }


    static lookAt (eye, center, up) {
      let
        [eyeX, eyeY, eyeZ] = eye,
        [upX,  upY,  upZ]  = up,
        [centerX, centerY, centerZ] = center;

      if (eyeX == centerX && eyeY == centerY && eyeZ == centerZ)
        return (new this).identity ();

      let
        sqrt = Math.sqrt,
        z0 = eyeX - centerX,
        z1 = eyeY - centerY,
        z2 = eyeZ - centerZ,
        l = 1 / sqrt (z0 * z0 + z1 * z1 + z2 * z2);

      z0 *= l; z1 *= l; z2 *= l;

      let
        x0 = upY * z2 - upZ * z1,
        x1 = upZ * z0 - upX * z2,
        x2 = upX * z1 - upY * z0;

      l = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
      if (! l) {
        x0 = 0; x1 = 0; x2 = 0;
      } else {
        l = 1 / l;
        x0 *= l; x1 *= l; x2 *= l;
      }

      let
        y0 = z1 * x2 - z2 * x1,
        y1 = z2 * x0 - z0 * x2,
        y2 = z0 * x1 - z1 * x0;
      l = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
      if (! l) {
        y0 = 0; y1 = 0; y2 = 0;
      } else {
        l = 1 / l;
        y0 *= l; y1 *= l; y2 *= l;
      }

      return new this ([
        x0, y0, z0, 0,
        x1, y1, z1, 0,
        x2, y2, z2, 0,
        -(x0 * eyeX + x1 * eyeY + x2 * eyeZ),
        -(y0 * eyeX + y1 * eyeY + y2 * eyeZ),
        -(z0 * eyeX + z1 * eyeY + z2 * eyeZ),
        1
      ]);
    }


    static perspective (fovy, aspect, near, far) {
      let
        t = near * Math.tan (fovy * Math.PI / 360),
        r = t * aspect,
        a = r * 2, b = t * 2, c = far - near;

      return new this ([
        near * 2 / a, 0, 0, 0,
        0, near * 2 / b, 0, 0,
        0, 0, -(far + near) / c, -1,
        0, 0, -(far * near * 2) / c, 0
      ]);
    }

  }
  

  this.Matrix4 = Matrix4;
}


{
  class Shader {
    constructor (canvas, vertex, fragment) {
      this.canvas = canvas;
      this.gl = canvas.getContext('webgl');
      this.v_shader = create_shader.call (this, vertex);
      this.f_shader = create_shader.call (this, fragment);
      this.prg = create_program.call (this);
      this.vbo = {};

      
      this.clear ();
    }
    
    
    clear (r = 0, g = 0, b = 0, a = 1) {
      let gl = this.gl;
      gl.clearColor (r, g, b, a);
      gl.clearDepth (1.0);
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

      return this;
    }
    
    
    setVBO (data = [], type = 'position') {
      let
        gl = this.gl,
        attLocation = gl.getAttribLocation (this.prg, type),
        attStride = {position: 3, color: 4}[type],
        vbo = create_vbo.call (this, data);
     
      gl.bindBuffer (gl.ARRAY_BUFFER, vbo);
      gl.enableVertexAttribArray (attLocation);
      gl.vertexAttribPointer (attLocation, attStride, gl.FLOAT, false, 0, 0);
      this.vbo[type] = vbo;

      return this;
    }
    
    
    setIBO (data = []) {
      let
        gl = this.gl,
        ibo = create_ibo.call (this, data);

      gl.bindBuffer (gl.ELEMENT_ARRAY_BUFFER, ibo);
      this.ibo = ibo;
      
      return this;

    }
    
    
    draw (mvpMatrix, vertex_index, flash = true) {
      let
        {gl, prg} = this,
        uniLocation = gl.getUniformLocation (prg, 'mvpMatrix');
      gl.uniformMatrix4fv (uniLocation, false, mvpMatrix);
//      gl.drawArrays (gl.TRIANGLES, 0, 3);
      gl.drawElements (gl.TRIANGLES, vertex_index.length, gl.UNSIGNED_SHORT, 0);
      
      if (flash)
        gl.flush ();
      
      return this;
    }
    
    
  }
  

  const
    SHADER_TYPE = {
      'x-shader/x-vertex': 'VERTEX_SHADER',
      'x-shader/x-fragment': 'FRAGMENT_SHADER'},

    create_shader =
      function (target = null) {
        if (target) {
          let
            gl = this.gl,
            {text, type} = target,
            shader = gl.createShader (gl[SHADER_TYPE[type]]);

          gl.shaderSource (shader, text);
          gl.compileShader (shader);
          if (! gl.getShaderParameter (shader, gl.COMPILE_STATUS))
            throw new Error (['シェーダーのコンパイルエラーがありました',
              gl.getShaderInfoLog (shader)].join ('\n'))

          return shader;
        }
        throw new Error ('要素がありません');
      },


      // プログラムオブジェクトを生成しシェーダをリンクする関数
    create_program =
      function () {
        let
          gl = this.gl,
          program = gl.createProgram();

        gl.attachShader (program, this.v_shader);
        gl.attachShader (program, this.f_shader);
        gl.linkProgram (program);

        if (! gl.getProgramParameter(program, gl.LINK_STATUS))
          throw new Error (['プログラムのオブジェクトの生成に失敗しました',
            gl.getProgramInfoLog (program)].join ('\n'));

        gl.useProgram (program);
        return program;
      },


	  create_vbo =
	    function (data) {
	      let
	        gl = this.gl,
	        vbo = gl.createBuffer ();

        gl.bindBuffer (gl.ARRAY_BUFFER, vbo);
        gl.bufferData (gl.ARRAY_BUFFER, new Float32Array (data), gl.STATIC_DRAW);
        gl.bindBuffer (gl.ARRAY_BUFFER, null);

        return vbo;
      },
    
    
    create_ibo =
      function (data) {
        let
          gl = this.gl,
          ibo = gl.createBuffer ();

        gl.bindBuffer (gl.ELEMENT_ARRAY_BUFFER, ibo);
        gl.bufferData (gl.ELEMENT_ARRAY_BUFFER, new Int16Array (data), gl.STATIC_DRAW);
        gl.bindBuffer (gl.ELEMENT_ARRAY_BUFFER, null);

        return ibo;
      };
      

  //_______
  
  this.Shader = Shader;
}


{//実行スクリプト
	let
	  doc = document,
	  canvas = doc.querySelector ('canvas'),
	  shader = new Shader (
	    canvas,
	    doc.querySelector ('script[type="x-shader/x-vertex"]'),
	    doc.querySelector ('script[type="x-shader/x-fragment"]'),
	  ),
    // モデル(頂点)データ
    vertex_position = [
      0.0, 1.0, 0.0,
      1.0, 0.0, 0.0,
      -1.0, 0.0, 0.0,
      0.0, -1.0, 0.0
    ],
    vertex_color = [
      1.0, 0.0, 0.0, 1.0,
      0.0, 1.0, 0.0, 1.0,
      0.0, 0.0, 1.0, 1.0,
      1.0, 1.0, 1.0, 1.0
    ],
    vertex_index = [
      0, 1, 2,
      1, 2, 3
    ],

    // 各種行列の生成と初期化
    matrix = Matrix4.perspective (45, canvas.width / canvas.height, 0.1, 100)
             .multiply (Matrix4.lookAt ([0, 0, 5.0], [0, 0, 0], [0, 1, 0]))
             .multiply (new Matrix4);
    

  shader.setVBO (vertex_position, 'position');
  shader.setVBO (vertex_color, 'color');
  shader.setIBO (vertex_index);

  //_____
  
  let
    start = + new Date,
    deg = Math.PI / 180,
    {sin, cos} = Math;
    
  const loop = function (timeStamp) {
    let
      count = (timeStamp - start) / 30,
      rad = (count % 360) * deg;
    
    
    shader.clear ();

    let
      m = (new Matrix4).rotate (rad, [0,1,0]),
      mMatrix = matrix.copy ().multiply (m);
    
    shader.draw (mMatrix.M, vertex_index);
  
    requestAnimationFrame (loop);
  }
  
  loop ();
}

</script>

2017-04-26

new URL 知らなかった…いつの間に。

| 01:03

浦島太郎かっ!>俺

ちなみにそれを1行で配列にしたいのだけれど。^^;

WebGL の事始め

| 16:51

https://wgld.org/d/webgl/w014.html

まずは、移植から。いきなりオブジェクト指向で脳内変換

なんで素直に写経するのを嫌うのだ?! > 俺

マトリクスのライブラリーも、後ほど見直すこと。

<!DOCTYPE html>
<meta charset="utf-8">
<title>WebGL</title>

<style>
</style>

<body>
  <canvas width="1024" height="512"</canvas>
  

<!-- ※頂点シェーダ -->
<script id="vshader" type="x-shader/x-vertex">
attribute vec3 position;
uniform   mat4 mvpMatrix;

void main (void){
  gl_Position = mvpMatrix * vec4(position, 1.0);
}
</script>

<!-- ※フラグメントシェーダ -->
<script id="fshader" type="x-shader/x-fragment">
void main(void){
	gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
</script>


<script>
{
  class Matrix4 {

    constructor (ary = [1,0,0,0,  0,1,0,0,  0,0,1,0,  0,0,0,1]) {
      let
        F = Math.fround,
        M = new Float32Array (16);
      
      for (let i = 0; i < 16; i++)
        M[i] = F (ary[i] || 0);

      this.M = M;
    }


    multiply (mat1) {
      let
        [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = this.M,
        [A, B, C, D, E, F, G, H, I, J, K, L, M, N ,O, P] = mat1.M;

      this.M = new Float32Array ([
        A * a + B * e + C * i + D * m,
        A * b + B * f + C * j + D * n,
        A * c + B * g + C * k + D * o,
        A * d + B * h + C * l + D * p,
        E * a + F * e + G * i + H * m,
        E * b + F * f + G * j + H * n,
        E * c + F * g + G * k + H * o,
        E * d + F * h + G * l + H * p,
        I * a + J * e + K * i + L * m,
        I * b + J * f + K * j + L * n,
        I * c + J * g + K * k + L * o,
        I * d + J * h + K * l + L * p,
        M * a + N * e + O * i + P * m,
        M * b + N * f + O * j + P * n,
        M * c + N * g + O * k + P * o,
        M * d + N * h + O * l + P * p
      ]);
      
      return this;
    }


    scale ([x,y,z]) {
      let m = this.M;
      this.M = new Float32Array ([
        m[0] * x,  m[1] * x,  m[2] * x,  m[3] * x,
        m[4] * y,  m[5] * y,  m[6] * y,  m[7] * y,
        m[8] * z,  m[9] * z,  m[10]* z,  m[11]* z,
        m[12],     m[13],     m[14],     m[15]
      ]);
      
      return this;
    }


    translate ([a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p], [x, y, z]) {
      this.M = new Float32Array ([
        a, b, c, d,
        e, f, g, h,
        i, j, k, l,
        a * x + e * y + i * z + m,
        b * x + f * y + j * z + n,
        c * x + g * y + k * z + o,
        d * x + h * y + l * z + p
      ]);

      return this;
    }


    static lookAt (eye, center, up) {
      let
        [eyeX, eyeY, eyeZ] = eye,
        [upX,  upY,  upZ]  = up,
        [centerX, centerY, centerZ] = center;

      if (eyeX == centerX && eyeY == centerY && eyeZ == centerZ)
        return (new this).identity ();

      let
        sqrt = Math.sqrt,
        z0 = eyeX - centerX,
        z1 = eyeY - centerY,
        z2 = eyeZ - centerZ,
        l = 1 / sqrt (z0 * z0 + z1 * z1 + z2 * z2);

      z0 *= l; z1 *= l; z2 *= l;

      let
        x0 = upY * z2 - upZ * z1,
        x1 = upZ * z0 - upX * z2,
        x2 = upX * z1 - upY * z0;

      l = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
      if (! l) {
        x0 = 0; x1 = 0; x2 = 0;
      } else {
        l = 1 / l;
        x0 *= l; x1 *= l; x2 *= l;
      }

      let
        y0 = z1 * x2 - z2 * x1,
        y1 = z2 * x0 - z0 * x2,
        y2 = z0 * x1 - z1 * x0;
      l = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
      if (! l) {
        y0 = 0; y1 = 0; y2 = 0;
      } else {
        l = 1 / l;
        y0 *= l; y1 *= l; y2 *= l;
      }

      return new this ([
        x0, y0, z0, 0,
        x1, y1, z1, 0,
        x2, y2, z2, 0,
        -(x0 * eyeX + x1 * eyeY + x2 * eyeZ),
        -(y0 * eyeX + y1 * eyeY + y2 * eyeZ),
        -(z0 * eyeX + z1 * eyeY + z2 * eyeZ),
        1
      ]);
    }


    static perspective (fovy, aspect, near, far) {
      let
        t = near * Math.tan (fovy * Math.PI / 360),
        r = t * aspect,
        a = r * 2, b = t * 2, c = far - near;

      return new this ([
        near * 2 / a, 0, 0, 0,
        0, near * 2 / b, 0, 0,
        0, 0, -(far + near) / c, -1,
        0, 0, -(far * near * 2) / c, 0
      ]);
    }

  }
  

  this.Matrix4 = Matrix4;
}

function matIV(){
	this.create = function(){
		return new Float32Array(16);
	};

	this.translate = function(mat, vec, dest){
		dest[0] = mat[0]; dest[1] = mat[1]; dest[2]  = mat[2];  dest[3]  = mat[3];
		dest[4] = mat[4]; dest[5] = mat[5]; dest[6]  = mat[6];  dest[7]  = mat[7];
		dest[8] = mat[8]; dest[9] = mat[9]; dest[10] = mat[10]; dest[11] = mat[11];
		dest[12] = mat[0] * vec[0] + mat[4] * vec[1] + mat[8]  * vec[2] + mat[12];
		dest[13] = mat[1] * vec[0] + mat[5] * vec[1] + mat[9]  * vec[2] + mat[13];
		dest[14] = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2] + mat[14];
		dest[15] = mat[3] * vec[0] + mat[7] * vec[1] + mat[11] * vec[2] + mat[15];
		return dest;
	};
	this.rotate = function(mat, angle, axis, dest){
		var sq = Math.sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
		if(!sq){return null;}
		var a = axis[0], b = axis[1], c = axis[2];
		if(sq != 1){sq = 1 / sq; a *= sq; b *= sq; c *= sq;}
		var d = Math.sin(angle), e = Math.cos(angle), f = 1 - e,
			g = mat[0],  h = mat[1], i = mat[2],  j = mat[3],
			k = mat[4],  l = mat[5], m = mat[6],  n = mat[7],
			o = mat[8],  p = mat[9], q = mat[10], r = mat[11],
			s = a * a * f + e,
			t = b * a * f + c * d,
			u = c * a * f - b * d,
			v = a * b * f - c * d,
			w = b * b * f + e,
			x = c * b * f + a * d,
			y = a * c * f + b * d,
			z = b * c * f - a * d,
			A = c * c * f + e;
		if(angle){
			if(mat != dest){
				dest[12] = mat[12]; dest[13] = mat[13];
				dest[14] = mat[14]; dest[15] = mat[15];
			}
		} else {
			dest = mat;
		}
		dest[0] = g * s + k * t + o * u;
		dest[1] = h * s + l * t + p * u;
		dest[2] = i * s + m * t + q * u;
		dest[3] = j * s + n * t + r * u;
		dest[4] = g * v + k * w + o * x;
		dest[5] = h * v + l * w + p * x;
		dest[6] = i * v + m * w + q * x;
		dest[7] = j * v + n * w + r * x;
		dest[8] = g * y + k * z + o * A;
		dest[9] = h * y + l * z + p * A;
		dest[10] = i * y + m * z + q * A;
		dest[11] = j * y + n * z + r * A;
		return dest;
	};
	this.perspective = function(fovy, aspect, near, far, dest){
		var t = near * Math.tan(fovy * Math.PI / 360);
		var r = t * aspect;
		var a = r * 2, b = t * 2, c = far - near;
		dest[0] = near * 2 / a;
		dest[1] = 0;
		dest[2] = 0;
		dest[3] = 0;
		dest[4] = 0;
		dest[5] = near * 2 / b;
		dest[6] = 0;
		dest[7] = 0;
		dest[8] = 0;
		dest[9] = 0;
		dest[10] = -(far + near) / c;
		dest[11] = -1;
		dest[12] = 0;
		dest[13] = 0;
		dest[14] = -(far * near * 2) / c;
		dest[15] = 0;
		return dest;
	};
	this.transpose = function(mat, dest){
		dest[0]  = mat[0];  dest[1]  = mat[4];
		dest[2]  = mat[8];  dest[3]  = mat[12];
		dest[4]  = mat[1];  dest[5]  = mat[5];
		dest[6]  = mat[9];  dest[7]  = mat[13];
		dest[8]  = mat[2];  dest[9]  = mat[6];
		dest[10] = mat[10]; dest[11] = mat[14];
		dest[12] = mat[3];  dest[13] = mat[7];
		dest[14] = mat[11]; dest[15] = mat[15];
		return dest;
	};
	this.inverse = function(mat, dest){
		var a = mat[0],  b = mat[1],  c = mat[2],  d = mat[3],
			e = mat[4],  f = mat[5],  g = mat[6],  h = mat[7],
			i = mat[8],  j = mat[9],  k = mat[10], l = mat[11],
			m = mat[12], n = mat[13], o = mat[14], p = mat[15],
			q = a * f - b * e, r = a * g - c * e,
			s = a * h - d * e, t = b * g - c * f,
			u = b * h - d * f, v = c * h - d * g,
			w = i * n - j * m, x = i * o - k * m,
			y = i * p - l * m, z = j * o - k * n,
			A = j * p - l * n, B = k * p - l * o,
			ivd = 1 / (q * B - r * A + s * z + t * y - u * x + v * w);
		dest[0]  = ( f * B - g * A + h * z) * ivd;
		dest[1]  = (-b * B + c * A - d * z) * ivd;
		dest[2]  = ( n * v - o * u + p * t) * ivd;
		dest[3]  = (-j * v + k * u - l * t) * ivd;
		dest[4]  = (-e * B + g * y - h * x) * ivd;
		dest[5]  = ( a * B - c * y + d * x) * ivd;
		dest[6]  = (-m * v + o * s - p * r) * ivd;
		dest[7]  = ( i * v - k * s + l * r) * ivd;
		dest[8]  = ( e * A - f * y + h * w) * ivd;
		dest[9]  = (-a * A + b * y - d * w) * ivd;
		dest[10] = ( m * u - n * s + p * q) * ivd;
		dest[11] = (-i * u + j * s - l * q) * ivd;
		dest[12] = (-e * z + f * x - g * w) * ivd;
		dest[13] = ( a * z - b * x + c * w) * ivd;
		dest[14] = (-m * t + n * r - o * q) * ivd;
		dest[15] = ( i * t - j * r + k * q) * ivd;
		return dest;
	};
}


{
  class Shader {
    constructor (canvas, vertex, fragment) {
      this.canvas = canvas;
      this.gl = canvas.getContext('webgl');
      this.v_shader = create_shader.call (this, vertex);
      this.f_shader = create_shader.call (this, fragment);
      this.prg = create_program.call (this);
      this.vbo = null;

      
      this.clear ();
    }
    
    
    clear (r = 0, g = 0, b = 0, a = 1) {
      let gl = this.gl;
      gl.clearColor (r, g, b, a);
      gl.clearDepth (1.0);
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

      return this;
    }
    
    
    setVBO (vertex_position = []) {
      let
        gl = this.gl,
        attLocation = gl.getAttribLocation (this.prg, 'position'),
        attStride = 3,
        vbo = create_vbo.call (this, vertex_position);
     
      gl.bindBuffer (gl.ARRAY_BUFFER, vbo);
      gl.enableVertexAttribArray (attLocation);
      gl.vertexAttribPointer (attLocation, attStride, gl.FLOAT, false, 0, 0);
      this.vbo = vbo;

      return this;
    }
    
    
    draw (mvpMatrix) {
      let
        {gl, prg} = this,
        uniLocation = gl.getUniformLocation (prg, 'mvpMatrix');
      gl.uniformMatrix4fv (uniLocation, false, mvpMatrix);
      gl.drawArrays (gl.TRIANGLES, 0, 3);
      gl.flush ();
      
      return this;
    }

  }
  

  const
    SHADER_TYPE = {
      'x-shader/x-vertex': 'VERTEX_SHADER',
      'x-shader/x-fragment': 'FRAGMENT_SHADER'},

    create_shader =
      function (target = null) {
        if (target) {
          let
            gl = this.gl,
            {text, type} = target,
            shader = gl.createShader (gl[SHADER_TYPE[type]]);

          gl.shaderSource (shader, text);
          gl.compileShader (shader);
          if (! gl.getShaderParameter (shader, gl.COMPILE_STATUS))
            throw new Error (['シェーダーのコンパイルエラーがありました',
              gl.getShaderInfoLog (shader)].join ('\n'))

          return shader;
        }
        throw new Error ('要素がありません');
      },


      // プログラムオブジェクトを生成しシェーダをリンクする関数
    create_program =
      function () {
        let
          gl = this.gl,
          program = gl.createProgram();

        gl.attachShader (program, this.v_shader);
        gl.attachShader (program, this.f_shader);
        gl.linkProgram (program);

        if (! gl.getProgramParameter(program, gl.LINK_STATUS))
          throw new Error (['プログラムのオブジェクトの生成に失敗しました',
            gl.getProgramInfoLog (program)].join ('\n'));

        gl.useProgram (program);
        return program;
      },


	  create_vbo =
	    function (data) {
	      let
	        gl = this.gl,
	        vbo = gl.createBuffer ();

        gl.bindBuffer (gl.ARRAY_BUFFER, vbo);
        gl.bufferData (gl.ARRAY_BUFFER, new Float32Array (data), gl.STATIC_DRAW);
        gl.bindBuffer (gl.ARRAY_BUFFER, null);

        return vbo;
      };
      

  //_______
  
  this.Shader = Shader;
}


{//実行スクリプト
	let
	  doc = document,
	  canvas = doc.querySelector ('canvas'),
	  shader = new Shader (
	    canvas,
	    doc.querySelector ('script[type="x-shader/x-vertex"]'),
	    doc.querySelector ('script[type="x-shader/x-fragment"]'),
	  ),
    // モデル(頂点)データ
    vertex_position = [
      0.0, 1.0, 0.0,
      1.0, 0.0, 0.0,
      -1.0, 0.0, 0.0
    ],

    // 各種行列の生成と初期化
    matrix = Matrix4.perspective (90, canvas.width / canvas.height, 0.1, 100)
             .multiply (Matrix4.lookAt ([0.0, 1.0, 3.0], [0, 0, 0], [0, 1, 0]))
             .multiply (new Matrix4);

  shader.setVBO (vertex_position);
	shader.draw (matrix.M);

}



	
	

</script>

think49think49 2017/04/29 11:29 > new URL 知らなかった…いつの間に。
ついでに、HTMLHyperlinkElementUtils も覚えておくと便利です(ぶっちゃけ、location と同じ Interface)。
HTMLHyperlinkElementUtils#searchParams は残念ながらないですが、自前でURLをパースするよりは楽です。
https://momdo.github.io/html/semantics.html#api-for-a-and-area-elements

> ちなみにそれを1行で配列にしたいのだけれど。^^;
こういう事かなー。
[...new URL('http://example.com/?a=1&b=2').searchParams]; // "[["a","1"],["b","2"]]

URL#searchParams は iterable なので、SpreadElement を使えば、配列化するのは容易です。
巷では Spread Operator (スプレッド演算子)と説明されることが多いようですが、厳密には演算子ではありません…。
(MDN までスプレッド演算子と表記されているのはどうかと思いますが、MDNは結構俗語を使いますね。)
http://www.ecma-international.org/ecma-262/7.0/#sec-array-initializer
http://js-next.hatenablog.com/entry/2015/06/24/100705
https://triple-underscore.github.io/URL-ja.html#url-class

babu_babu_baboobabu_babu_baboo 2017/04/29 21:22 think49 さん

ありがとうございます。なんだかJavaScriptが高級言語化しているようで、低レベルな命令の組み合わせで作り上げてたのが数年前ですよ。
進歩が早い。ついていけそうにないです。

ES6 は、かなり秘技(ショートコーディングも含む)が考えられそうで興味はあるのですが、今はコンピュータ・グラフィックスにドハマり中でして…。

2017-04-22

こんな質問者への対応は、アフリカ難民募金と同じでその難民の自立を妨げるのと同じ!

| 10:49

もう何十年も募金と支援してるのに終わらないのはなぜなのか気づけよ!

まぁ回答者側がアレだからな。

俺以外の回答者にでも言ってくれ。


    1. 質問の表題は、その不明瞭な事象を的確に表現すること
    2. 今後同じような悩みを抱えるであろう人のために、質問を撒き散らかさない。くだらない質問があちこちにあるとウンザリするから。
    3. あちこちの掲示版に撒き散らかすのなら、その場所も記すこと。
    4. これからの人のために、自分なりの解決策を記しておくこと。
    5. 撒き散らした場所にも解決策を記すか、その解決策に導けるように記して置くこと。
    6. 1行程度で済ませるお礼ならしなくてもよい。但しポイントなどが付加されるならそれを行うこと。
    7. 自分の過去の質問を読み返した時に、恥ずかしくなるような質問はしないこと。名前を変えれば良いなんて思わない事。
    8. 同類の質問を何度も繰り返すのなら、ちゃんと過去のものは閉じること。というか、締め切らず喰い下がれ。

この程度の事を考えられない、もしくは「そんな規約はどこにもないよ」という奴は、そもそもどこの世界に出ても大成しない。

その昔、「良き質問には良き回答が出る」ってのを見てから、これも格言のように思っている。







この手の特徴

    1. 人のアドバイスを深く検証する事なく、無視または罵倒する
    2. 罵倒する対象には、自分の出来る範囲陰湿評価を下げようとする
    3. すぐに名前をかえて忘れた頃にやってくる
    4. 思考固執しているので、コード進歩がなくすぐに判別できる
    5. 自作自演で自分を擁護する仲間が居るように装う
    6. 仲間用のidを常に複数所有して居る
    7. そして興奮して書き込むとidを間違えて自作自演がばれる

もしかして境界性人格障害に近いか、、、



過去に残念だったこと。

    1. 回答に対してお礼と、さらなる質問をしておいて締め切られた事。どうやってその回答をしろってゆうんだよ!?
    2. 異様なまでに持ち上げられた事。さっぱり嬉しくも無かった。
    3. 23OLです。」に釣られて速攻で回答した事。


「いいね」ボタンがあるように「愚問に近いね」とか「愚問だね」とか作って頂きたい。検索に引っかからないで欲しい。

もう過去の質問への回答も参考にならない時代なのか。

babu_babu_baboobabu_babu_baboo 2017/04/22 16:51 違うところで噛み付いてきたーーー!
でもな。今までに提示したコード見ると、幼稚なんだよね。
「老害」の反対語が「餓鬼」ってなっているのだけれど、
何を食べても燃えてしまって食べられない飢えた鬼。
周りが見えてない。

babu_babu_baboobabu_babu_baboo 2017/04/22 17:30 あっ、スレッドごと削除された。自作自演がばれたしね

think49think49 2017/04/23 17:45 あの人は同じサイト内でも名前を変えて質問を連投しているイメージですね。
「トレンドは何ですか?Ajaxをやっておけば大丈夫ですか?」とあちこちのサイトで質問して「これをやっておけばよいというものはありません」と様々な場所で回答されるのですが、しつこく食い下がってマルチポストを続けてます。
このしつこさだけは大したものだと思いますが、それを基礎知識を得るための学習に割り当ててくれれば…。
「聞いた方が早い」の意識が抜けない人なので勉強の仕方を教えても聞きませんし、厳しいアドバイスをすると、babu_babu_babooさんがされたのと同じ様に暴言を吐いて切り捨てます。
こういう人は切り捨てられるQ&Aサイトは有ってもいいと思います。

> 「いいね」ボタンがあるように「愚問に近いね」とか「愚問だね」とか作って頂きたい。検索に引っかからないで欲しい
teratailやstackoverflowにはその機能があります。
OKWaveは前からずっと同じ体制なので改善には期待できないと思います。

babu_babu_baboobabu_babu_baboo 2017/04/24 10:27 think49 さん、

う〜〜〜ん、困ったものですね。
というかどうでもよいのですが、人格形成の上で、彼には何があったのでしょう?
そちらが非常に気になります。

相変わらず知恵袋では、質問者が質問とその回答を含めてバッサリ削除できるようですが、その時に罵倒するお礼のハンドルネームが別人のものでした。それを自分で気づいてバッサリ削除したものだと推測しています。


以下うるおぼえ。

その化身のプロフィールを見ました。たしか女性で30〜35歳となっていました。
もしその人が自分の化身ならば、年齢は同じぐらいと考えます。

「フリーランスで仕事をするには」的な質問なのでフリーランスではない。

プロのプログラマーの面接してくれた人が、会話の中で「知らないことは我々でもあるし教えていただきながら自分たちも仕事をしている。だから君もそうやって仕事をすればいいんだよ」みたいなことをいわれたとその部分は敬語で書いていた。
普通そこは「自分の尊敬する上司が」ならば理解できるが、面接した人が!?なのでやっぱり今は仕事をしていない。


過去にこういった行動が似ている人を、覚えています。
すごく似てるんだよな〜。


--
と、ここまで書いて一切が無駄と悟る。

時間があれば、WebGL2.0 に興味あり。いつになることやら。
再来月は手術だ。