見出し画像

おうちさんぽVR版をWebXRで試作する

こんにちは。木村(@atskimura)です。

以前スマホを振るとウォーキング動画を再生するという「おうちさんぽ」を作ろうとしていました。

ちょっと非公開の別のことをやっていたので間が開いてしまいましたが、その間にOculus Quest 2(今はMeta Questだけどこの名前の方がわかりやすいのでこのままいきます)が手に入ったので、おうちさんぽをVR版で作ったらより楽しいのではとおうちさんぽVR版を作ってみることにしました。

スマホを振るとウォーキング動画を再生

コントローラーを振ると360°ウォーキング動画を再生

という感じです。

WebXR

UnityでVRは以前作ったので、今回はWebXRを使ってみることにしました。たぶん当時よりWebでできることが増えてるに違いないし。

WebXRについては以下の記事が非常によくまとまっていて、これを読むだけでだいたいわかった気分になれます。

この記事によればWebVRをやりたいならA-Frameということなので、迷わずA-Frameを使います。

WebVR コンテンツを開発したいのであれば、まずこの A-Frame に行き着くはずです。

#WebXR ( WebVR/WebAR ) の現状確認 2021 Winter

A-Frame

A-Frameは公式サイトを見ればもうなんとなくはすぐわかるようになっています。いろんなサンプルがコードと一緒に見れるし、そのままVR版で動かすこともできます。

Hello WebVRサンプルを例に取れば、以下のようなコードを書くだけで、

<!DOCTYPE html>
<html>
  <head>
    <script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
  </head>
  <body>
    <a-scene>
      <a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
      <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
      <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>
  </body>
</html>

以下のような3DモデルをWebVRコンテンツとして描画できます。

コントローラーを振ると360°動画を再生する

VR表示したYouTubeの動画にVRコンテンツを被せることはできなそう

調べた範囲では無理そうでした。たぶんYouTube動画はiframeで埋め込むことになりそのVR表示はiframe内でXRセッションが開始される、iframeの外で開始したXRセッションとは別物になるので、無理なんじゃないかなあと推測されます。

諦めてどこかにある動画を再生することにする

ということで今回はちゃんと使えるものを作るのは諦めて、どこかにアップされた動画をコントローラを振ると再生/停止するようサンプルコードを作ることをゴールとします。まあちゃんと360°散歩動画を自前で用意すれば使えるものを作れますが、それは大変すぎますので。

クリックすると360°動画を再生するサンプルがあったのでこれを改造していきます。

Oculus Quest 2のコントローラの情報を取得する

A-FrameがOculus Quest 2のコントローラの情報を取得するコンポーネントを用意してくれているので、それを使います。

以下のように書くとQuest 2のコントローラの座標を取得できます。tickは各フレームごとに呼ばれるメソッドです。

      <a-entity
        oculus-touch-controls="hand: right"
        position-listner
      ></a-entity>
AFRAME.registerComponent("position-listner", {
  tick: function (time, timeDelta) {
    const pos = this.el.object3D.position;
    console.log(pos.x, pos.y, pos.z);
  },
});

コントローラを振ると360°動画再生完成

完成しましたが、見た目はただサンプル動画が再生/停止を繰り返すだけなので、特に動画などは貼りません。

ソースコード

動画の再生/停止の仕方は元のサンプルコードを参考にして完成しました。コードはGlitchにホスティングしています。

https://glitch.com/edit/#!/sudden-zinc-toy

以下にも主要なコードを貼っておきます。
index.html

<!DOCTYPE html>
<html>
  <head>
    <script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
    <script src="./js/video-controller.js"></script>
    <script src="./js/hide-on-play.js"></script>
  </head>
  <body>
    <a-scene background="color:black">
      <a-assets>
        <!--
        SOURCE
        Author: Bitmovin
        URL:    https://bitmovin.com/demos/vr-360
        -->
        <video
          id="video"
          preload="auto"
          src="https://bitmovin-a.akamaihd.net/content/playhouse-vr/progressive.mp4"
          playsinline
          loop="true"
          muted="true"
          crossorigin="anonymous"
        ></video>
      </a-assets>
      <a-videosphere
        id="videosphere"
        rotation="0 -90 0"
        src="#video"
        visible="true"
        play-on-click
      >
      </a-videosphere>
      <a-camera>
        <a-entity
          position="0 0 -1.5"
          text="align: center;
                width: 6;
                wrapCount: 100;
                color: white;
                value: Shake controller to play"
          hide-on-play="#video"
        >
        </a-entity>
      </a-camera>
      <a-entity
        oculus-touch-controls="hand: right"
        video-controller="#videosphere"
      ></a-entity>
    </a-scene>
  </body>
</html>

video-controller.js

/* global AFRAME */
/* global THREE */
AFRAME.registerComponent("video-controller", {
  schema: {
    type: "selector",
  },
  init: function () {
    this.velocity = new THREE.Vector3();
    this.prevPos = new THREE.Vector3();
  },
  tick: function (time, timeDelta) {
    const pos = this.el.object3D.position;
    this.velocity.copy(pos);
    this.velocity.sub(this.prevPos);
    this.velocity.divideScalar(timeDelta / 1000); // 0-2.5くらいに収まる

    const speed = this.velocity.length();
    
    if (speed > 0.5) {
      this.startVideo();
    } else {
      this.stopVideo();
    }
    
    this.prevPos.copy(pos);
  },
  startVideo: function() {
    if (this.isPlaying) {
      return;
    }
    const videoEl = this.getVideoEl();
    if (!videoEl) {
      return;
    }
    videoEl.play();
    this.isPlaying = true;
    
  },
  stopVideo: function() {
    if (!this.isPlaying) {
      return;
    }
    const videoEl = this.getVideoEl();
    if (!videoEl) {
      return;
    }
    videoEl.pause();
    this.isPlaying = false;
  },
  getVideoEl: function() {
    const videosphereEl = this.data;
    const videoEl = videosphereEl.getAttribute("material").src;
    return videoEl;
  },
});

公開URL

Oculus Quest 2で以下のURLにアクセスすると実際動かしてみることができます。

https://sudden-zinc-toy.glitch.me/

終わりに

YouTubeが使えないとわかった時点でちゃんと完成させる気はなくなり、Questのコントローラで再生/停止するサンプルを作って終わりとなりました。306°散歩動画をたくさん用意すれば使えるものもできそうですが、それは大変すぎるのでこんな結末となりました。せめて一本くらい散歩動画を用意したかったが、高画質360°動画を取るカメラもないし、難しいかったですね。

次回からは非VR版おうちさんぽに戻るか、他のことをやるか、ちょっと考えたいと思います。

しかし、A-Frameはめっちゃ気軽にVRコンテンツが作れて楽しいですね。


この記事が気に入ったらサポートをしてみませんか?