Three.jsでGLSLを触るための基礎基礎メモ
GLSLの基礎
「WebGLを使って三角形を描画する為の基礎知識」でも少しかきましたが、GLSLは頂点シェーダーと、フラグメントシェーダーがあります。
頂点シェーダーではgl_Position
という組み込み変数に頂点データを必ず渡す必要があります。 フラグメントシェーダーには、gl_FragColor
という組み込み変数がありピクセルの色を指定します。
gl_Positionには、後述するカメラの視野範囲の空間であるクリッピング座標が入ります。
Three.jsで定義されている行列
Thress.jsでは、座標変換用の行列が用意されています。
名前 | 修飾子 | 型 | 説明 |
---|---|---|---|
modelMatrix | uniform | mat4 | オブジェクト座標からワールド座標へ変換する |
viewMatrix | uniform | mat4 | ワールド座標から視点座標へ変換 |
modelViewMatrix | uniform | mat4 | modelMatrixとviewMatrixの積算 |
projectionMatrix | uniform | mat4 | カメラの各種パラメータから3次元を2次元に射影し、クリップ座標系に変換する行列 |
normalMatrix | uniform | mat3 | 頂点法線ベクトルを視点座標系に変換する行列 |
Three.jsで定義されている変数
Thress.jsでは、座標系の変数が用意されています。
名前 | 修飾子 | 型 | 説明 |
---|---|---|---|
cameraPosition | uniform | vec3 | カメラの位置 |
position | attribute | vec3 | 頂点座標 |
normal | attribute | vec3 | 頂点法線ベクトル |
uv | attribute | vec2 | テクスチャを貼るためのUV座標 |
※フラグメントシェーダーはviewMatrix
、cameraPosition
のみ利用可能。
GLSLの組み込み変数
主に頂点シェーダーで使う変数
名前 | 型 | 説明 |
---|---|---|
gl_Position | vec4 | 頂点座標 |
gl_PointSize | float | ポイントスプライトのサイズ |
フラグメントシェーダで使う変数
名前 | 型 | 説明 |
---|---|---|
gl_FragColor | vec4 | ピクセルの描画色 |
gl_FragCoord | vec4 | ピクセルの座標 |
gl_PointCoord | vec2 | ポイントスプライト内の座標 |
gl_FrontFacing | bool | ピクセルの表裏。表ならtrue、裏ならfalse |
レンダリングの流れ
下記は3Dモデルが画面に表示されるまでの、レンダリングパイプラインの一部です。
ShaderMaterial
Three.jsでカスタムシェーダーを使うためにはShaderMaterial
を使用します。 ShaderMaterialを利用する場合は、uniform
とattribute
変数が自動で挿入されます。
ShaderMaterialを使うため、projectionMatrix、modelViewMatrix、positionの定義が不要。
<body> <div id="webgl"></div> <script id="vs" type="x-shader/x-vertex"> void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); } </script> <script id="fs" type="x-shader/x-fragment"> void main() { gl_FragColor =vec4(1.0, 1.0, 1.0, 1.0); } </script> </body>
var geometry = new THREE.PlaneGeometry(2, 2, 5, 5); var material = new THREE.ShaderMaterial({ vertexShader: document.getElementById('vs').textContent, fragmentShader: document.getElementById('fs').textContent }); var cube = new THREE.Mesh(geometry, material); scene.add(cube);
See the Pen KqZWRB by nogson (@satofaction) on CodePen.
RawShaderMaterial
RawShaderMaterial
はShaderMaterialと似ているのですが、uniform
とattribute
変数が自動で挿入されないので、自分で定義して上げる必要があります。 勝手に挿入されるのが嫌な場合はこちらを使います。
<body> <div id="webgl"></div> <script id="vs" type="x-shader/x-vertex"> attribute vec3 position; uniform mat4 projectionMatrix; uniform mat4 modelViewMatrix; void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); } </script> <script id="fs" type="x-shader/x-fragment"> void main() { gl_FragColor =vec4(1.0, 1.0, 1.0, 1.0); } </script> </body>
See the Pen wepJge by nogson (@satofaction) on CodePen.
ShaderMaterialでカスタムシェーダーを管理する際に使えるフィールド
名前 | 説明 |
---|---|
vertexShader | 頂点シェーダーのソースコード |
fragmentShader | フラグメントシェーダーのソースコード |
uniforms | 共通パラメータの定義 |
attributes | 各頂点データの定義 |
THREE.Geometryで頂点座標を定義する
頂点座標を指定してジオメトリを作成する場合は、THREE.Geometry
を利用します。 ジオメトリの頂点座標をvertices
に配列でいれます。 faces
には頂点の結ぶ順番を配列でいれます。
let geometry = new THREE.Geometry(); let vertices = [ new THREE.Vector3(0, 1, 0), new THREE.Vector3(-1, -1, 0), new THREE.Vector3(1, -1, 0), new THREE.Vector3(0, 4, 0), new THREE.Vector3(-1, 2, 0), new THREE.Vector3(1, 2, 0), ]; let faces = [ new THREE.Face3(0, 1, 2), new THREE.Face3(3, 4, 5) ]; geometry.vertices = vertices; geometry.faces = faces; var material = new THREE.ShaderMaterial({ vertexShader: document.getElementById('vs').textContent, fragmentShader: document.getElementById('fs').textContent }); var cube = new THREE.Mesh(geometry, material); scene.add(cube);
See the Pen XgZmgg by nogson (@satofaction) on CodePen.
ShaderMaterialで色を変更してみる
uniformsに色を指定し、GLSLで受け取る。 ただし、uniformで渡しているので全ポリゴンが同じ色になる。
var material = new THREE.ShaderMaterial({ vertexShader: document.getElementById('vs').textContent, fragmentShader: document.getElementById('fs').textContent, uniforms: { uColor: { type: "c", value: new THREE.Color(0xFF0068) } } });
<script id="fs" type="x-shader/x-fragment"> uniform vec3 uColor; void main() { gl_FragColor =vec4(uColor, 1.0); } </script>
多角形を書いてみる
1枚のポリゴンは基本的に三角形です。 そこで、三角形を組み合わせて多角形を描いてみます。
多角形の書き方も、いくつかパターンがありそうです。 例えば下記のような五角形でも3つの三角形で作る場合と、5つで作る場合があります。
今回の例だと、5つで作るほうが簡単そうなので、5つでやってみます。 (わかりやすいように、wireframeで表示しています)
See the Pen EXRYMq by nogson (@satofaction) on CodePen.
円周上の座標の計算式から、五角形の頂点座標を算出します。 あとは、中心点から円周上の座標を繋いでいきます。
let vertices = []; let faces = []; let split = 6; let theta = 360 / split; let radian = theta * Math.PI / 180; let size = 1; //中心の頂点を追加 vertices.push(new THREE.Vector3(0, 0, 0)); //頂点の座標を決める for (let i = 0; i < split; i++) { var x = Math.cos(radian * i) * size; var y = Math.sin(radian * i) * size; vertices.push(new THREE.Vector3(x, y, 0)); } //頂点のindexを決める for (let i = 0; i <= split; i++) { let index; if (i < split) { index = new THREE.Face3(0, i + 1, i + 2); } else { index = new THREE.Face3(0, i, 1); } faces.push(index); }
頂点の数だけ変更すれば、他の多角形にもそのまま利用できます。
まとめ
面ごとに色を指定してみたかったのですが、やり方がわかりませんでした。。。