見出し画像

[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側の座標をうまく合わせることでスクロールに応じた表現が色々できそうです。


いいなと思ったら応援しよう!