[UIデザイナーが学ぶ]Three.jsの画面スクロールとの連動の話
はじめに
この記事はthreejs journeyを利用しての学習メモです。
このthreejs journeyはthree.jsを学ぶのに非常に有用ですので、是非視聴してみてください。おすすめです!!
今回はWebglでの描画とブラウザのスクロールを連動するための方法について少し記載します。
学習の備忘録てきに書いているので、詳しくは上記リンクのthreejs journeyを御覧ください。
HTMLの準備
以下のような、高さ100vhのsectionを3つ持つhtmlを用意します。
なので、全体の高さはwindowの高さ3つ分になります。
Three.jsで背景を描画する
まずは、オブジェクトを3つ配置します。
htmlとは座標の考え方が違うので、注意が必要です。
const mesh1 = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshBasicMaterial({ color: "red" })
);
const mesh2 = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshBasicMaterial({ color: "blue" })
);
const mesh3 = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshBasicMaterial({ color: "green" })
);
const distance = 4;
mesh1.position.y = -distance * 0;
mesh2.position.y = -distance * 1;
mesh3.position.y = -distance * 2;
scene.add(mesh1, mesh2, mesh3);
今後カメラを移動させる際にコントロールしやすいように、オブジェクト同士の間隔を変数(distance)に入れておくと後々楽です。
カメラを移動する
まずは、スクロール値を取得します。
let scrollY = window.scrollY;
window.addEventListener("scroll", () => {
scrollY = window.scrollY;
});
ただし、このままの値を使うとcameraをコントロールするには大きすぎるので、window.innerHeightの値を利用して、Three.jsの座標系でも利用できるような値にします。
scrollY / sizes.height
レンダリング処理に追加します。
また、カメラのY軸は正の方向が上なので、負の方向に移動させます。
// アニメーション
const clock = new THREE.Clock();
const tick = () => {
const elapsedTime = clock.getElapsedTime();
// カメラを移動
camera.position.y = (-scrollY / sizes.height) ;
renderer.render(scene, camera);
window.requestAnimationFrame(tick);
};
tick();
カメラが移動しますが、オブジェクトが4間隔(distance)で配置されているので、htmlの各sectionと同期しながら移動するには、算出した値に4をかけて上げる必要があります。
camera.position.y = (-scrollY / sizes.height) * distance;
これで、htmlのsectionとThree.jsで描画したキューブの表示が同期します。
html側の座標と、WebGL側の座標をうまく合わせることでスクロールに応じた表現が色々できそうです。