Edited at

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

More than 1 year has passed since last update.

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 = 各マテリアルで使用するシェーダー定義