WebGLについて

# はじめに
唐突にWebGLについて理解を深めたいと思ったので、記事を書いてみることにしました。
今後も時間が取れ次第、新記事or追記という形で更新したいと思っています。

# WebGLとは
[wiki](https://ja.wikipedia.org/wiki/WebGL)を引用
> WebGL（ウェブジーエル）は、ウェブブラウザで3次元コンピュータグラフィックスを表示させるための標準仕様。非営利団体のKhronos Groupで管理されている。WebGL 1.0は、ブラウザ上で利用できるOpenGL ES 2.0の派生規格であるが、細部に違いがある。WebGL 2.0は、ブラウザ上で利用できるOpenGL ES 3.0の派生規格であるが、細部に違いがある。WebGLはHTML5のcanvas要素に描画する。 

要はHTMLのcanvas属性を使用して、ブラウザ上で3Dモデルを表示しちゃうよ的なサムシング

# まずは生で
WebGLではThree.jsなど便利なライブラリが公開されていますが、自分の理解を多少なりとも深めるためにまずは生で描画をしていきます。
既に[先駆者様](https://www.shibuya24.info/entry/2015/07/28/200310)がいらっしゃるので、内容を参考にしつつより砕いていこうと思います。

## 1.canvasとWebGLコンテキストの取得
```script.js
var key = 'canvas';
var canvas = document.getElementById (key);
var gl = canvas.getContext('webgl', null);
var size = Math.min(window.innerWidth, window.innerHeight);
canvas.width = size;
canvas.height = size;
```

canvas、そしてWebGLコンテキストを取得した上で、サイズ等の設定を行います。

## 2.シェーダのコンパイル
###  シェーダis何
よくわからない単語が出てきました。ぐぐります。
[wiki](https://ja.wikipedia.org/wiki/%E3%82%B7%E3%82%A7%E3%83%BC%E3%83%80%E3%83%BC)を引用
> シェーダー（英: shader）とは、3次元コンピュータグラフィックスにおいて、シェーディング（陰影処理）を行うコンピュータプログラムのこと。「shade」とは「次第に変化させる」「陰影・グラデーションを付ける」という意味で、「shader」は頂点色やピクセル色などを次々に変化させるもの（より具体的に、狭義の意味で言えば関数）を意味する。 

はい、よくわかりません。wiki語は難しいです。

[こちらのサイト](http://e-words.jp/w/%E3%82%B7%E3%82%A7%E3%83%BC%E3%83%80.html)でなんとなく掴むことができました。
> シェーダとは、3次元コンピュータグラフィックス（3DCG）において、陰影付けや表面の質感や凹凸の設定、各画素の表示色の決定などを行うプログラムのこと。

3Dモデルを表現するためのプログラムというところでしょうか。
いったんそういうことにしておきます。

### シェーダの種類
読み進めている中でシェーダにはおおきくわけて2種類あることがわかりました。

- 頂点シェーダ(vertex shader)
    - モデルを構成する面の頂点の画面上での位置を決定する
- フラグメントシェーダ(fragment shader)
    - 面を構成する各画素の実際の表示色を決定する
    - ピクセルシェーダとも呼ばれる

## れっつコンパイル
```script.js
var vsElement = document.getElementById ('vs');
var vs = null;
if (vsElement.type == 'x-shader/x-vertex') {
	vs = gl.createShader(gl.VERTEX_SHADER);
}
// シェーダオブジェクトに頂点シェーダーを代入
gl.shaderSource(vs, vsElement.text);
// 頂点シェーダをコンパイル
gl.compileShader(vs);

var fsElement = document.getElementById('fs');
var fs = null;
if (fsElement.type == 'x-shader/x-fragment') {
	fs = gl.createShader(gl.FRAGMENT_SHADER);
}
// シェーダオブジェクトにフラグメントシェーダを代入
gl.shaderSource(fs, fsElement.text);
// フラグメントシェーダをコンパイル
gl.compileShader (fs);
```

まず頂点シェーダを作成するために、htmlにあるvsというスクリプトを呼び出しています。
これはGLSL(OpenGL Shading Language)と呼ばれているらしいです。

### GLSLis何
一応やっておきます。
[wiki](https://ja.wikipedia.org/wiki/GLSL)を引用
> GLSL (OpenGL Shading Language) はGLslangとしても知られ、C言語をベースとした高レベルシェーディング言語である。これはアセンブリ言語やハードウェアに依存した言語を使わないで、アプリケーションソフトウェア開発者がグラフィックスパイプラインを直接制御できるようにOpenGL ARB (Architecture Review Board)で策定された。 

描画に特化したプログラミング言語というところですかね。

```index.html
<script id="vs" type="x-shader/x-vertex">
attribute vec3 position;
void main ()
{
	// 1. JavaScript側から送られた頂点データをそのままgl_Positionに渡す
	gl_Position = vec4(position, 1.0);
}
</script>
```

[こちら](https://wgld.org/d/webgl/w011.html)が参考になりました。

- attribute
    - この修飾子を付けて宣言された変数が、頂点ごとに異なる情報をシェーダ側で受け取る変数となる
- vec3
    - 3点を持つベクトル

要はこれが頂点位置であり、X,Y,Zが入ってきます。

- gl_Position
    - 頂点シェーダを受け取るための組み込み変数

`gl_Position = vec4(position, 1.0);`
ここでは3次元として入ってきたローカル座標の頂点位置を vec4によって4次元に変換しています。

次にフラグメントシェーダですが、こちらも頂点シェーダと似たような形で準備をします。

```index.html
<script id="fs" type="x-shader/x-fragment">
precision mediump float;
void main ()
{
	// 2.処理する座標を白色で塗りつぶす
	gl_FragColor = vec4 (vec3 (1.0), 1.0);
}
</script>
```

- precision
    - 精度修飾子とよばれ、どの程度の精度でデータを扱うかを指定できる
- mediump
    - mediumpという精度でデータを扱う。他にも`lowp`、`highp`の計3種類がある。

`precision mediump float;`
floatにmediumpの精度を求めるということになります。
`gl_FragColor = vec4 (vec3 (1.0), 1.0);`
頂点シェーダと同じような形で設定を行い、こちらは色合いをRGB値で設定します。

## 3.WebGLProgramとシェーダをリンク

```script.js
// WebGLProgram
var program = gl.createProgram();
// WebGLProgramに頂点シェーダーを紐付ける
gl.attachShader(program, vs);
// WebGLProgramにフラグメントシェーダーを紐付ける
gl.attachShader(program, fs);
// WebGLProgramに紐付けられた、頂点シェーダとフラグメントシェーダをWebGLProgramにリンクさせる
gl.linkProgram (program);
// WebGLProgramのパラメータを取得する
if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
	// WebGLProgramを有効化する
	gl.useProgram(program);
}else {
	console.log (gl.getProgramInfoLog(program));
	return;
}
```
頂点情報と色情報をWebGLにリンクさせています。

## 4.三角ポリゴンの頂点バッファ生成
```script.js
// 空のバッファ生成
var positionBuffer = gl.createBuffer();
// 生成したバッファをバインドする
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
var position = [
	0, 0.5, 0,
	-0.5, -0.5, 0,
	0.5 ,-0.5, 0
];
// バインドされたバッファに三角ポリゴンのデータをセットする
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array (position), gl.STATIC_DRAW);
// バインド解除
gl.bindBuffer(gl.ARRAY_BUFFER, null);
```
ここで描画を行っています。
positionの値で図形を変更することができます。

## 5.描画
```script.js
render ();

function render ()
{
	// 背景描画
	gl.clearColor (0.8, 0.8, 0.8, 1.0);
	// バッファをクリアする
	gl.clear (gl.COLOR_BUFFER_BIT);

	// ビューポートを設定
	gl.viewport(0, 0, size, size);

	// 三角ポリゴン頂点バッファをバインド
	gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
	// 頂点シェーダのアドレスを保持
	var positionAddress = gl.getAttribLocation(program, "position");
	// 頂点属性を有効化する
	gl.enableVertexAttribArray(positionAddress);
	// 頂点属性に頂点データを設定する
	gl.vertexAttribPointer(positionAddress, 3, gl.FLOAT, false, 0, 0);

	//描画
	gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3);
}
```

- 背景
    - RGBA
- ビューポート
    - 表示位置の設定
- 描画
    - gl.TRIANGLE_STRIPを変更することで、表現方法が変わります。

ここまでを行い、htmlを開くと三角ポリゴンが一つ描画されているはずです。

<img width="75%" alt="Polygon.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275170/76dcad83-8428-81c3-9771-f82ad03aed56.png">


# おわりに
とりあえず書き連ねてみましたがまだ頭に入ったという感じは全く無いです。
これを元に簡易3Dモデルの描画をしてからわかったことを補足や追記をしていきます。
その後にライブラリを使ってみて感動する予定です。

## つづき
→[続・WebGLについて](https://qiita.com/alicial/items/ccff5d2459d888a5eabf)