6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Three.jsAdvent Calendar 2019

Day 9

最小構成のWebXR AR

Last updated at Posted at 2019-12-09

WebXR AR Paint Advent Calendar3日目です(チガウ)。

前回のエントリWebXR AR Paintのソースコードについて雑に説明しました。ただ、改めて見ると、WebXRにとってはあまり本質ではない部分の説明が長くなってしまっていて混乱させるだけだったかもしれません。ということで、今回WebXR AR PaintのコードのTubePainter関連のコードをばっさり削って最小構成にしてみました。

画面をタップすると、その時点での端末の位置と向きにあわせて円錐が表示されます。

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>three.js ar</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <link type="text/css" rel="stylesheet" href="main.css">
  </head>
  <body>
    <script type="module">
      import * as THREE from './jsm/three.module.js';
      import { ARButton } from './jsm/ARButton.js';

      let camera, scene, renderer;
      let controller;

      init();
      animate();

      function init() {

        // 1. レンダラーのalphaオプションをtrueにする
        renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});

        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);

        // 2. レンダラーのXR機能を有効にする
        renderer.xr.enabled = true;

        document.body.appendChild(renderer.domElement);

        // 3. AR表示を有効にするためのボタンを画面に追加する
        document.body.appendChild(ARButton.createButton(renderer));

        scene = new THREE.Scene();
        let light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 1);
        light.position.set(0, 1, 0);
        scene.add(light);

        camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20);
        window.addEventListener('resize', () => {
          camera.aspect = window.innerWidth / window.innerHeight;
          camera.updateProjectionMatrix();
          renderer.setSize(window.innerWidth, window.innerHeight);
        }, false);

        // 4. XRセッションにアクセスするためコントローラーを取得する
        controller = renderer.xr.getController(0);
        controller.addEventListener('selectend', () => {
          controller.userData.isSelecting = true;
        });
      }

      function makeArrow(color) {
        const geometry = new THREE.ConeGeometry(0.03, 0.1, 32)
        const material = new THREE.MeshStandardMaterial({
          color: color,
          roughness: 0.9,
          metalness: 0.0,
          side: THREE.DoubleSide
        });
        const localMesh = new THREE.Mesh(geometry, material);
        localMesh.rotation.x = -Math.PI / 2
        const mesh = new THREE.Group()
        mesh.add(localMesh)
        return mesh
      }

      function handleController(controller) {
        if (!controller.userData.isSelecting) return;

        const mesh = makeArrow(Math.floor(Math.random() * 0xffffff))

        // 5. コントローラーのposition, rotationプロパティを使用して
        //    AR空間内での端末の姿勢を取得し、メッシュに適用する
        mesh.position.copy(controller.position)
        mesh.rotation.copy(controller.rotation)

        scene.add(mesh)

        controller.userData.isSelecting = false
      }

      function animate() {
        renderer.setAnimationLoop(render);
      }

      function render() {
        handleController(controller);
        renderer.render(scene, camera);
      }
    </script>
  </body>
</html>

要するに以下のような処理を追加すればARモードを実装できます。

  1. レンダラーのalphaオプションをtrueにする
  2. レンダラーのXR機能を有効にする
  3. AR表示を有効にするためのボタンを画面に追加する
  4. XRセッションにアクセスするためコントローラーを取得する
  5. コントローラーのposition, rotationプロパティを使用してAR空間内での端末の姿勢を取得し、メッシュに適用する

割と簡単にARアプリが実装できて楽しいので、ぜひ試してみてください。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?