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

  • 59
    いいね
  • 2
    コメント

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

入出力

VertexShader

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

FragmentShader

  • 入力 gl_FrontFacing (bool) ポリゴンの表裏のブール値
  • 入力 gl_FragCoord (vec4) ウィンドウ座標=canvas上の座標 (x,y,z, 1/w)
  • 入力 gl_PointCoord (vec2) ポイントスプライト時の2次元座標
  • 出力 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 カメラの各種パラメータから3次元を2次元に射影し、クリップ座標系に変換する行列
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)
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

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

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

void main()
{
  // テクスチャの色情報をそのままピクセルに塗る
  gl_FragColor = texture2D(texture, vUv);
}
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 = 各マテリアルで使用するシェーダー定義