Three.jsでカスタムシェーダーを扱う際の自分用メモ。
下の記事とか非常に参考になる 。
https://qiita.com/mebiusbox2/items/8a4734ab5b0854528789
Three.jsのライトとかそのヘルパー凄い使いやすいんだけど、その情報を自分のシェーダーに組み込む方法が分からなかったんで、そこらへん含めて調べてみた。
結論を言うと、以下のようなコードを基本にするとかなり楽に色々実験できそう。
ファイル構成main.html
main.js
js/
└─three.js
OrbitControls.js
LoaderSupport.js
OBJLoader2.js
サンプル : http://nktk-tech.com/example/three-template1/main.html
ソースコード
main.html<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="js/three.js"></script>
<script src="js/LoaderSupport.js"></script>
<script src="js/OBJLoader2.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="main.js"></script>
<script id="vs" type="x-shader/x-vertex">
// PIの定義などがあり、ライト情報を使うのに必要
#include <common>
// punctualLightIntensityToIrradianceFactor関数がライトの定義の読み込みに必要
#include <bsdfs>
// ライトの構造体、uniform変数などが定義されている
#include <lights_pars_begin>
varying vec4 fragColor;
void main() {
vec4 tempFragColor = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < NUM_POINT_LIGHTS; i++) {
vec4 vertexToLight = normalize(vec4(pointLights[i].position, 1.0) - modelViewMatrix * vec4(position, 1.0));
tempFragColor += vec4(pointLights[i].color, 1.0) * max(dot(vertexToLight.xyz, normalMatrix * normal), 0.0);
}
fragColor = tempFragColor;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
</script>
<script id="fs" type="x-shader/x-fragment">
varying vec4 fragColor;
void main() {
gl_FragColor = fragColor;
}
</script>
</head>
<body>
<canvas id="myCanvas"></canvas>
</body>
</html>
main.jswindow.addEventListener('load', init);
function init() {
// サイズを指定
const width = 960;
const height = 540;
// レンダラーを作成
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('#myCanvas')
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height);
renderer.setClearColor(new THREE.Color( 0.5, 0.5, 0.5 ))
// シーンを作成
const scene = new THREE.Scene();
// カメラを作成
const camera = new THREE.PerspectiveCamera(45, width / height);
camera.position.set(0, 5, +10);
// マウスドラッグによるコントーロールを有効化
const controls = new THREE.OrbitControls( camera );
// 点光源追加
const light = new THREE.PointLight( 0xffffee );
light.position.set( 5, 3, 5 );
scene.add( light );
const sphereSize = 1;
const pointLightHelper = new THREE.PointLightHelper( light, sphereSize );
scene.add( pointLightHelper );
// モデルのロードが終わった際のコールバック
const callbackOnLoad = (event) => {
let rootNode = event.detail.loaderRootNode;
rootNode.children[0].material = new THREE.ShaderMaterial({
uniforms: THREE.UniformsLib['lights'],
vertexShader: document.getElementById('vs').textContent,
fragmentShader: document.getElementById('fs').textContent,
lights: true,
});
scene.add(rootNode);
renderer.render(scene, camera);
tick();
};
// .obj形式のモデルをロード
const objLoader = new THREE.OBJLoader2();
objLoader.setUseIndices(true);
objLoader.load( 'model/teapot.obj', callbackOnLoad, null, null, null, false );
// 毎フレーム時に実行されるループイベント
function tick() {
controls.update();
renderer.render(scene, camera); // レンダリング
requestAnimationFrame(tick);
}
}
続きを読む →