p5.jsで生のwebglを使って板ポリ芸をする

# はじめに
　この記事では、p5.jsにも関わらず、その機能を使わないでwebglを実行します。背徳的で楽しいですね。
　今回は板ポリ芸です。板ポリ芸というのはシェーダー上の処理だけでピクセルの色を決めるものです。巷でシェーダー芸と言われているものです。今回もアトリビュートは使いません。あれは高級な話題なので...
　作るのはRGB三角形に次いでメジャーなwebglの初歩的な描画内容であるグラデーション長方形です。shadertoyを触ったことのある人にとってはおなじみの話題ですね。

## コード全文
　[vanilla webgl ITAPORI](https://openprocessing.org/sketch/2512157)
```js
// cf:シェーダーのコンパイル：https://wgld.org/d/webgl/w011.html

function setup() {
  createCanvas(400, 400, WEBGL);

  // 板ポリ芸をやってみる

  // 1.レンダラーの取得
  const gl = this._renderer.GL;

  // 2.shaderProgramの用意
  const pg = createShaderProgram(gl);

  if(pg === null){
    return;
  }

  // 3.ドローコール（今回はgl_VertexIDを使用）
  gl.clearColor(0.5, 0.5, 0.5, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);

  gl.useProgram(pg);
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

  gl.flush();
}

function createShaderProgram(gl){
  const vs =
`#version 300 es
const vec2 LEFT_DOWN = vec2(-1.0, -1.0);
const vec2 RIGHT_DOWN = vec2(1.0, -1.0);
const vec2 LEFT_UP = vec2(-1.0, 1.0);
const vec2 RIGHT_UP = vec2(1.0, 1.0);
out vec2 vUv;
void main(){
  int i = gl_VertexID;
  vec2 p;
  if(i==0){ p=LEFT_DOWN; }
  if(i==1){ p=RIGHT_DOWN; }
  if(i==2){ p=LEFT_UP; }
  if(i==3){ p=RIGHT_UP; }
  vUv = p;
  gl_Position = vec4(p, 0.0, 1.0);
}
`;
  const fs =
`#version 300 es
precision highp float;
in vec2 vUv;
out vec4 fragColor;
void main(){
  vec3 color = vec3(0.5 + 0.5*vUv, 1.0);
  fragColor = vec4(color, 1.0);
}
`;
  const vsShader = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vsShader, vs);
  gl.compileShader(vsShader);

  if(!gl.getShaderParameter(vsShader, gl.COMPILE_STATUS)){
    console.log("vertex shaderの作成に失敗しました");
    console.error(gl.getShaderInfoLog(vsShader));
    return null;
  }

  const fsShader = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fsShader, fs);
  gl.compileShader(fsShader);

  if(!gl.getShaderParameter(fsShader, gl.COMPILE_STATUS)){
    console.log("fragment shaderの作成に失敗しました");
    console.error(gl.getShaderInfoLog(fsShader));
    return null;
  }

  const program = gl.createProgram();

  gl.attachShader(program, vsShader);
  gl.attachShader(program, fsShader);
  gl.linkProgram(program);

  if(!gl.getProgramParameter(program, gl.LINK_STATUS)){
    console.log("programのlinkに失敗しました");
    console.error(gl.getProgramInfoLog(program));
    return null;
  }

  return program;
}
```
実行結果：

![rtewsdddddd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437349/7b42123c-d586-37eb-2393-6c2dbefb5f19.png)

## 三角形の位置
　今回はなんと2つの三角形を描画しています。位置を決めているのはいつものようにバーテックスシェーダです。
```glsl:vert
#version 300 es
const vec2 LEFT_DOWN = vec2(-1.0, -1.0);
const vec2 RIGHT_DOWN = vec2(1.0, -1.0);
const vec2 LEFT_UP = vec2(-1.0, 1.0);
const vec2 RIGHT_UP = vec2(1.0, 1.0);
out vec2 vUv;
void main(){
  int i = gl_VertexID;
  vec2 p;
  if(i==0){ p=LEFT_DOWN; }
  if(i==1){ p=RIGHT_DOWN; }
  if(i==2){ p=LEFT_UP; }
  if(i==3){ p=RIGHT_UP; }
  vUv = p;
  gl_Position = vec4(p, 0.0, 1.0);
}
```
LEFT_DOWNやRIGHT_UPは完全に文字通りの意味です。すなわち-1～1で左から右、下から上の座標系における四隅の座標です。アトリビュートというか処理するデータの数は今回4つで、0,1,2,3がそれぞれ然るべく対応する位置につきます。では三角形はどのように生成されるのでしょうか。

## ドローコールTRIANGLE_STRIP
　[Triangle strip](https://en.wikipedia.org/wiki/Triangle_strip)

![wefeg4eg4rrh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437349/6e9a59d3-f222-66a1-ab46-3014fbb9f8dc.png)

ドローコールは今回、TRIANGLE_STRIPを使っています。
```js
  gl.useProgram(pg);
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
```
これは図のように、0,1,2,3,4,5,...に対して、[0,1,2],[2,1,3],[2,3,4],[4,3,5],...のように三角形を作っていく処理です。それらに対して処理されます。ゆえに図を見ると分かりますが、二つの三角形が描画されて正方形になります。ドローコールには四角形以上の多角形を描画する命令は無いので、三角形の集合としてしか長方形を描画することはできません。こうして描画領域が決まります。

## varyingについて
　今回フラグメントシェーダに渡しているのは位置そのものです。vUvと名前がついてるこれです。これを使って描画します。すなわち座標系の値そのまんまです。これを0.5倍して0.5を足してRGを決め、Bは1として色を決めています。
```glsl:frag
#version 300 es
precision highp float;
in vec2 vUv;
out vec4 fragColor;
void main(){
  vec3 color = vec3(0.5 + 0.5*vUv, 1.0);
  fragColor = vec4(color, 1.0);
}
```
ゆえに左下は0,0,1で青となり、右上は1,1,1で白となるわけです。分かりやすいですね。

# おわりに
　ドローコールには様々なものがあるので調べてみましょう。
　[drawArrays()](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/drawArrays)
ここまでお読みいただいてありがとうございました。