【Three.js】GLTF読み込み・Raycaster

に公開

はじめに

Three.jsでGLTFの読み込みと、Raycasterを使ってランプのスイッチ切り替わりをやってみました。

▼完成(codepen)
GLTF use Raycaster

▼ランプモデリングはこちら参考に作成
【blender】超簡単モデリング!デスクライトをつくろう

やったこと

ポイントライトをランプの光るところに来るように位置を調整。
Blender側でのそれぞれのメッシュ名も実装を意識してつける必要があるなと思いました。
(今回のスイッチ部分 = 'btn')
初めはポイントライトは非表示にしています。

// ramp light
const pointLight = new THREE.PointLight(0xffffff, 20, 5);
pointLight.position.set(-1.2, 2, 0);
pointLight.visible = false;
scene.add(pointLight);

Blenderからデータをエクスポート(glb)→ Three.jsで読み込み。
そしてRaycasterでマウスの位置を取得して、
クリックイベントを設定したいスイッチ部分をここで探しています。

// raycaster
const raycaster = new THREE.Raycaster();
let btnMesh = null;
const mouse = new THREE.Vector2();

const loader = new THREE.GLTFLoader();
loader.load("https://raw.githubusercontent.com/yokota26/tutorial/main/public/models/light_three.glb", (gltf) => {
  scene.add(gltf.scene);
  // ランプのボタン取得
  gltf.scene.traverse((obj) => {
    if (obj.name === "btn" && obj instanceof THREE.Mesh) {
      btnMesh = obj;
    }
  });
});

ClickでON/OFF切り替えたいので、クリックイベントを設定します。
マウスの範囲を-1〜1に正規化。
スイッチをクリックしたらポイントライトがつくのと、
スイッチの位置も少し押した感じが出るようにyを変更しました。

// clickでランプのON/OFF切り替え
renderer.domElement.addEventListener("click", (e) => {
  if (!btnMesh) return;
  mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
  raycaster.setFromCamera(mouse, camera);

  const intersects = raycaster.intersectObject(btnMesh, true);
  if (intersects.length > 0) {
    pointLight.visible = !pointLight.visible;
  }

  if (pointLight.visible) {
    btnMesh.position.y = 0.3;
  } else if (!pointLight.visible) {
    btnMesh.position.y = 0.36;
  }
  console.log(btnMesh);
});

まとめ

今回はBlenderで作ったデータの読み込みと、Raycasterを調べながら作りました。
難しい〜もっと色々できるように勉強していきます。

Discussion