threejsでGLSLをいじるための基礎知識

threejsでShaderMaterialとかを使うと、自分で直接GLSLをいじれる。
そのためのメモ。

##入出力
###VertexShader
* 入力 なし
* 出力 gl_Position (vec4) _ ２次元平面上の頂点座標
* 出力 gl_PointSize (float) _ 点のサイズ

###FragmentShader
* 入力 gl_FrontFacing (bool) ポリゴンの表裏のブール値
* 入力 gl_FragCoord (vec4) ウィンドウ座標=canvas上の座標 (x,y,z, 1/w)
* 入力 gl_PointCoord (vec2) ポイントスプライト時の２次元座標
* 出力 gl_FragColor (vec4) ピクセルの描画色
* 出力 gl_FragData[] ([]) glDrawBuffersとかで使う配列データ

これら以外はuniform

##GLSL ES上で扱われる型

* int (整数)
* ivec2,ivec3,ivec4 (intのベクトル)
* bool (ブール)
* bvec2,bvec3,bvec4 (boolのベクトル)
* float
* vec2,vec3,vec4 (floatのベクトル)
* mat2,mat3,mat4 (行列)
* sampler2D (2次元テクスチャ)
* samplerCube (3次元テクスチャ)

##threejsによって既に定義されている変数

| 変数名 | 説明 |
|:-----------|:------------|
| modelMatrix |オブジェクト座標からワールド座標へ変換する|
| viewMatrix |ワールド座標から視点座標へ変換|
| modelViewMatrix |modelMatrixとviewMatrixの積算|
| projectionMatrix |カメラの各種パラメータから３次元を２次元に射影し、クリップ座標系に変換する行列 |
| cameraPosition |カメラの位置 |
| normalMatrix |頂点法線ベクトルを視点座標系に変換する行列|
| position |頂点座標|
| normal |頂点法線ベクトル|
| uv |テクスチャを貼るためのUV座標|
 
バーテックスシェーダーでは全部使える。
フラグメントシェーダーでは,viewMatrixとcameraPositionのみ使える。
フラグメントシェーダー側で使うときはバーテックスシェーダ内でvarying変数に一旦いれたりする。vUv=vu; みたいな感じで。

##threejsからuniform/attributeを渡すとき指定する文字列(type)
よくつかいそうなのは

* i (整数)
* f (float)
* v2 (THREE.Vector2)
* v3 (THREE.Vector3)
* v4 (THREE.Vector4)
* c (THREE.Color)
* m4 (THREE.Matrix4)
* t (THREE.Texture)


```js:uniform_type.js
var uniformsExample = {

"uInt" :  { type: "i", value: 1 },     // single integer
"uFloat" : { type: "f", value: 3.14 }, // single float

"uVec2" : { type: "v2", value: new THREE.Vector2( 0, 1 ) },       // single Vector2
"uVec3" : { type: "v3", value: new THREE.Vector3( 0, 1, 2 ) },    // single Vector3
"uVec4" : { type: "v4", value: new THREE.Vector4( 0, 1, 2, 3 ) }, // single Vector4

"uCol" : { type: "c", value: new THREE.Color( 0xffaa00 ) }, // single Color

"uMat4" : { type: "m4", value: new THREE.Matrix4() }, // single Matrix4


"uTex" :     { type: "t", value: THREE.ImageUtils.loadTexture( "texture.jpg" ) }, // regular texture
"uTexCube" : { type: "t", value: THREE.ImageUtils.loadTextureCube( [ "px.jpg", "nx.jpg", // cube texture
                                                                     "py.jpg", "ny.jpg", 
                                                                     "pz.jpg", "nz.jpg" ] ) },

"uIntArray"  : { type: "iv1", value: [ 1, 2, 3, 4, 5 ] },    // integer array (plain)
"uIntArray3" : { type: "iv", value: [ 1, 2, 3, 4, 5, 6 ] },   // integer array (ivec3)

"uFloatArray"  : { type: "fv1", value: [ 0.1, 0.2, 0.3, 0.4, 0.5 ] },    // float array (plain)
"uFloatArray3" : { type: "fv",  value: [ 0.1, 0.2, 0.3, 0.4, 0.5, 0.6 ] }, // float array (vec3)

"uVec2Array" : { type: "v2v", value: [ new THREE.Vector2( 0.1, 0.2 ), 
                                       new THREE.Vector2( 0.4, 0.5 ) ] }, // Vector2 array

"uVec3Array" : { type: "v3v", value: [ new THREE.Vector3( 0.1, 0.2, 0.3 ), 
                                       new THREE.Vector3( 0.4, 0.5, 0.6 ) ] }, // Vector3 array

"uVec4Array" : { type: "v4v", value: [ new THREE.Vector4( 0.1, 0.2, 0.3, 0.4 ), 
                                       new THREE.Vector4( 0.4, 0.5, 0.6, 0.7 ) ] }, // Vector4 array

"uMat4Array" : { type: "m4v", value: [ new THREE.Matrix4(), new THREE.Matrix4() ] }, // Matrix4 array

"uTexArray" : { type: "tv", value: [ new THREE.Texture(), new THREE.Texture() ] } // texture array (regular)
                                                                                              // texture units start from value

};
```

引用元: https://github.com/mrdoob/three.js/wiki/Uniforms-types





##座標変換と行列の関係性
オブジェクト座標系（ローカル座標系）
　↓
 **＊modelMatrix**
　↓
ワールド座標系
　↓
**＊viewMatrix**
　↓
視点座標系（カメラから見た座標）
　↓
**＊projectionMatrix**
　↓
クリップ座標系 ＝ xyzを-1〜+1で表す座標系
　↓
ウィンドウ座標系 ＝ canvas上の座標系

##基本的なfragmentShader/vertexShader

```glsl:vertexshader
varying vec2 vUv;// fragmentShaderに渡すためのvarying変数
void main()
{
  // 処理する頂点ごとのuv(テクスチャ)座標をそのままfragmentShaderに横流しする
  vUv = uv;
  // 変換：ローカル座標 → 配置 → カメラ座標
  vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);    
  // 変換：カメラ座標 → 画面座標
  gl_Position = projectionMatrix * mvPosition;
}

```

```glsl:fragmentShader
//uniform 変数としてテクスチャのデータを受け取る
uniform sampler2D texture;
// vertexShaderで処理されて渡されるテクスチャ座標
varying vec2 vUv;                                             

void main()
{
  // テクスチャの色情報をそのままピクセルに塗る
  gl_FragColor = texture2D(texture, vUv);
}
```

```js:js
var materialShaderSimple = new THREE.ShaderMaterial({            
  vertexShader: vartexShaderString
  fragmentShader: fragmentShaderString,
  uniforms: {
    texture: { type: 't', value: ImageUtils.loadTexture("**.png")}                                   }
});
```

※こちらを参考にしました。 http://izmiz.hateblo.jp/entry/2014/09/27/235743

##GLSL ES組み込み関数
覚えにくいものを抜粋

| 関数名 | 説明 |
|:-----------|:------------|
| sign(x)|符号判別、負:-1,ゼロ:0,正:1|
| fract(x)|小数の部分だけ返す|
| mod(x,y)|x/yのあまり|
| clamp(x,y,a)| クランプ処理min(max(x,y),a) |
| mix(x,y,a) | 線形補間 |
| smoothstep(edge0,edge1,x) | xの要素のうち、edge0以下のものは0.0、edge1以上のものは1.0にする。xがedge0とedge1の間にあるときには、3次エルミート補間を返す。 |
| step(a,x) | x<aのとき0, x≧aのとき1  |
| sqrt(x),inverssqrt(x) | inversは1/sqrt(x) | 
| normalize(x) | 正規化 | 
| faceforward(N,I,Nref) | 法線ベクトルNを条件により反転 | 
| reflect(I,N) | 法線ベクトルNの面に対して入射ベクトルIの反射ベクトルを返す | 
| refract(I,N,eta) | 屈折率etaの法線ベクトルNの面に対し、 | 
| length(x) | ベクトルの長さ＝絶対値 | 
| distance(x,y) | x,yの距離 | 
| dot(x,y) | 内積 | 
| cross(x,y) | 外積 | 
|  texture2D(uTexture, texCoords) | uTextureのtexCoords座標の色(vec4)を返す|

参考：glsl辞典
http://ec.nikkeibp.co.jp/nsp/dl/08513/HTML5GAMES_AppC.pdf

##threejs内でshaderが格納されている場所

https://github.com/mrdoob/three.js/tree/master/src/renderers/shaders
* THREE.ShaderChunk =	共通で使われるGLSLのコード片
* THREE.UniformsUtils =	uniformsの定義を操作するユーティリティ関数群
* THREE.UniformsLib =	共通で使われるuniforms定義
* THREE.ShaderLib = 各マテリアルで使用するシェーダー定義