こくぶん研究室

スマホ VR を作ろう

はじめに

VR が日常に

VR はもう日常に
VR はもう日常に

長らく研究段階だったバーチャルリアリティ(Virtual Reality; VR)が、2016年頃から一気に私たちの日常にやってきました。従来は数百万円~数千万円もしていた VR 機器が 10万円前後で手に入るようにになったり、PlayStation VR のように 5万円程度で楽しめるようになりました。

VR は自分で作る時代へ

とはいっても、5~10万円という金額はすぐに手が出るものではありません。でも、安心してください。VR はスマホでも楽しめます。いえ、楽しむだけでなく、自分でコンテンツを作ることができます。

鍵は CG と立体視とセンサ
鍵は CG と立体視とセンサ

VR の鍵は、CG と立体視とセンサ(主にジャイロ)です。CG の世界を立体的に見ながら、頭を左右や上下に振ったら CG の世界が動けばいいのです。当然スマホでは CG を扱えます。立体視は右の図のように、画面を左右に分けて、左目用の映像と右目用の映像を映します(サイドバイサイド方式の立体視といいます)。多くのスマホにはジャイロセンサが付いているので、頭の動きも測定できます。このあたりの処理を簡単にプログラミングできる方法も普及してきました。

安価なゴーグルとスマホで VR
安価なゴーグルとスマホで VR

あとは実際に立体的に見るためのゴーグルですが、これも、千円前後のものがたくさん売られています。これらのゴーグルの中にスマホを入れると、スマホ画面の左目用の映像を左目だけで、右目用の映像を右目だけで見ることができて、立体視できます。

さぁ 遊んでみましょう

さっそくスマホ VR を作って遊びましょう。「CG と立体視とセンサ」と書くと難しそうですが、とても簡単に作れます。今回は「プログラミング」さえほとんど要りません。

▲TOP

今回の内容

目標

VR 空間にオリジナルの CG モデルを置いて、立体的に見るだけでなく、そのモデルと簡単なインタラクションができる VR コンテンツを作ります。

今回の目標
今回の目標

さらにおまけとして、スマホのカメラの映像を VR 空間に置くことで、現実世界(リアル)と仮想世界(バーチャル)がミックスした AR (Augmented Reality) や MR (Mixed Reality) にチャレンジします。

今回のおまけ
今回のおまけ

使うもの

ステップ

  1. A-Frame で超簡単 VR
  2. アニメーションとインタラクション
  3. CG モデルを登場させる
  4. おまけ:スマホカメラと合成して AR & MR

▲TOP

1. A-Frame で超簡単 VR

超簡単に VR が作れる A-Frame

VR を作る方法はたくさんあって、しかも現在は日進月歩で「定番」がありません。このページでは、超簡単に高品質の VR コンテンツが作れる A-Frame(エー・フレーム)というライブラリを使って VR を作ります。

A-Frame は Firefox ブラウザを作っている Mozilla 財団が作っています(2015年12月に登場)。とにかく簡単なことが特徴で、HTML を書くだけで VR コンテンツを作ることができます。このページでは「おまけ」として扱いますが、JavaScript もあわせて使うと高度な VR コンテンツが作れます。HTML と JavaScript(Web アプリ)ですから、スマホのブラウザで楽しむことができます(Web VR といいます)。

なにはともあれ、作ってみましょう。まずは VR 空間の中に単純な CG を置いて、360度見渡せる簡単な VR を作ります。

今から作るもの
今から作るもの

プログラミング

Visual Studio Code(または好みのエディタ)を立ち上げて、以下のコードを入力しましょう。こちらで作ったテンプレートをもとに書き始めると効率的です。ファイルは、C:\xampp\htdocs フォルダの中に「vr1」というフォルダを作って、その中に「index.html」として保存してください。それぞれのコードが何をしているのか考えながら入力していきましょう。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>A-Frame で超簡単 VR</title>
<!-- A-Frame を使うための外部スクリプトの読み込み -->
<script src="https://aframe.io/releases/0.5.0/aframe.min.js"></script>
</head>

<body>
<!-- A-Frame の VR は必ず a-scene タグで囲み、その中に様々なオブジェクト(entity)を置く -->
<a-scene>
    <!-- a-sphere:球、a-box:直方体、a-cylinder:円柱、a-plane:平面、a-sky:背景 -->
    <!-- position="x y z" [m]  rotation="x y z" [deg]  scale="w h d" [m] -->
    <a-sphere position="0 1.25 -5"
        radius="1.25"
        color="rgb(255, 0, 0)">
    </a-sphere>
    <a-box position="-1 0.5 -3"
        rotation="0 45 0"
        scale="1 1 1"
        color="rgb(0, 255, 0)">
    </a-box>
    <a-cylinder position="1 0.75 -3"
        radius="0.5"
        height="1.5"
        color="rgb(0, 0, 255)">
    </a-cylinder>
    <a-plane position="0 0 -4"
        rotation="-90 0 0"
        width="4"
        height="4"
        color="rgb(255, 255, 0)">
    </a-plane>
    <a-sky color="rgb(222, 222, 222)">
    </a-sky>
</a-scene>
</body>
</html>

動作確認

XAMPP Control Panel で Apache を Start させてください(不明な場合はこちらを参考にしてください)。

プログラムを書いているパソコンと、動作確認するスマホが、同じ LAN につながっていることを確認します(不明な場合はこちらを参考にしてください)。

Windows の「コマンド プロンプト」で ipconfig して、パソコンの IP アドレスを調べてください(不明な場合はこちらを参考にしてください)。

スマホのブラウザ(Safari や Chrome)を開き、アドレス欄に以下のように入力します。以下の「10.11.52.81」の部分は上で調べた IP アドレスです。

スマホは横向きにしましょう。以下のように表示されます。

アクセスすると
アクセスすると

この状態でも 360度見渡すことができます。スマホを持ってぐるっと見渡してみましょう。

でも、まだ立体的に見ることはできませんね。画面の右下に表示されているメガネのような(VR ゴーグルの)アイコンをタップしましょう。すると以下のように左目用と右目用の映像が表示されます。

VR ゴーグルのアイコンをタップすると
VR ゴーグルのアイコンをタップすると

この状態になったら、用意した VR ゴーグルにスマホをセットして、ゴーグルを覗き込んでみましょう。

VR ゴーグルにスマホをセット
VR ゴーグルにスマホをセット

解説

8行目が A-Frame を使う設定です。<script> タグの中で、A-Frame のサイトで公開されている a-frame.min.js という JavaScript のプログラムを読み込んでいます。こうすることで、これ以降で A-Frame の機能を使えるようになります。なお、<script> タグは普通は <body> タグの中で使うのですが、A-Frame のドキュメント(仕様書・解説書)では <head> タグの中で指定するように推奨されています。

<!-- A-Frame を使うための外部スクリプトの読み込み -->
<script src="https://aframe.io/releases/0.5.0/aframe.min.js"></script>

今回は JavaScript は全く使っていません。その代わり、13行目以降に <a-scene> や <a-sphere> などの見慣れないタグが登場しています。これが A-Frame のタグです。A-Frame はこのように独自のタグを使って VR コンテンツを作っていきます。

まず、<a-scene> ~ </a-scene> タグが最も重要です。これを指定することで VR 空間(シーン)を作っています。この <a-scene> ~ </a-scene> タグの内側に CG、カメラ、照明などの様々な部品(entity(エンティティ)と呼ばれる)を置いていきます。

<!-- A-Frame の VR は必ず a-scene タグで囲み、その中に様々なオブジェクト(entity)を置く -->
<a-scene>

例えば <a-sphere> は球状の CG、<a-box> は箱状の CG、<a-cylinder> は筒状の CG、<a-plane> は板状の CG を置くタグです。このような単純な形の図形のことを「primitive(プリミティブ)」といいます。プリミティブを積み木のように組み合わせて様々なものを作ることができます(使えるプリミティブの一覧はこちら)。

それぞれのプリミティブのタグの中では、位置や大きさなどの属性を指定します。

    <a-box position="-1 0.5 -3"
        rotation="0 45 0"
        scale="1 1 1"
        color="rgb(0, 255, 0)">
    </a-box>

例えば position 属性はプリミティブの位置です。" " の中は座標で "X Y Z" です。JavaScript などとは違い、カンマではなくスペースで値を区切るのは要注意です。数値の単位はメートル [m] です。座標の方向は以下の図のように、画面に向かって右方向に X がプラス、上方向に Y がプラス、手前方向に Z がプラスです(右手系座標といいます)。

A-Frame の座標系
A-Frame の座標系

rotation 属性はプリミティブを回転させる指定で、" " の中は "X Y Z" 軸まわりの角度(単位は度 [°])です。例えば上の例では "0 45 0" ですから、Y 軸(つまり縦方向の軸)まわりに 45度、a-box プリミティブを回転させています。

scale 属性は大きさです。width, height, depth という属性でも指定できますが、scale="width height depth" とすることで一気に大きさを指定しています。単位はメートル [m] です。

<a-sky> は空(そら)を作るタグです。空を作らないと真っ暗な空間に浮いている感じになります。ここでは color 属性だけ指定して灰色の空間にしています。

    <a-sky color="rgb(222, 222, 222)">
    </a-sky>

参考

完成品をこちらに置いてありますからスマホで開いてみてください。

▲TOP

2. アニメーションとインタラクション

止まった無地のプリミティブを見ているだけではあまり面白くありませんね。また、ただ見ているだけでは VR っぽくないですね。ここでは、プリミティブに画像(テクスチャ)を貼り付けて、プリミティブを動かすアニメーションをつけます。また、少しだけインタラクティブにしてみます。

今から作るもの
今から作るもの

プログラミング

Visual Studio Code(または好みのエディタ)を立ち上げて、さきほどの vr1 の index.html をもとに以下のコードを入力しましょう。<title> タグ ~ </a-scene> タグ の部分のみを掲載します(このままコピペするだけでは動きません)。ファイルは、C:\xampp\htdocs フォルダの中に「vr2」というフォルダを作って、その中に「index.html」として保存してください。それぞれのコードが何をしているのか考えながら入力していきましょう。

<title>アニメーションとインタラクション</title>
<!-- A-Frame を使うための外部スクリプトの読み込み -->
<script src="https://aframe.io/releases/0.5.0/aframe.min.js"></script>
</head>

<body>
<!-- A-Frame の VR は必ず a-scene タグで囲み、その中に様々なオブジェクト(entities)を置く -->
<a-scene>
    <!-- メディアを入れておく a-assets タグ -->
    <a-assets>
        <img id="boxTexture" src="huchan.jpg">      <!-- 箱のテクスチャ -->
        <img id="groundTexture" src="floor.jpg">    <!-- 地面のテクスチャ -->
        <img id="skyTexture" src="sechelt.jpg">     <!-- 背景のテクスチャ -->
    </a-assets>

    <!-- a-box:直方体 -->
    <!-- src="#テクスチャ"  position="x y z" [m]  rotation="x y z" [deg]  scale="w h d" [m] -->
    <a-box src="#boxTexture"
        position="0 2 -5"
        rotation="0 45 45"
        scale="2 2 2"
        color="rgb(222, 222, 222)">
        <!-- アニメーションするための a-animation タグ(a-box の子要素として指定すると a-box に適用される) -->
        <!-- attribute="動かす属性"  to="動かす先"  dur="持続時間"  begin="アニメ開始イベント" -->
        <a-animation attribute="position"
            to="0 3 -5"
            dur="2000"
            direction="alternate"
            repeat="indefinite">
        </a-animation>
        <a-animation attribute="scale"
            to="2.3 2.3 2.3"
            dur="300"
            begin="mouseenter">
        </a-animation>
        <a-animation attribute="scale"
            to="2 2 2"
            dur="300"
            begin="mouseleave">
        </a-animation>
        <a-animation attribute="rotation"
            to="360 405 45"
            dur="2000"
            begin="click">
        </a-animation>
    </a-box>

    <!-- 地面と背景 src="#テクスチャ" -->
    <a-plane src="#groundTexture"
        rotation="-90 0 0"
        width="15"
        height="15">
    </a-plane>
    <a-sky src="#skyTexture"
        color="rgb(127, 127, 127)">
    </a-sky>

    <!-- カメラを操作する a-camera タグ -->
    <a-camera>
        <a-cursor></a-cursor>   <!-- インタラクションするための a-cursor(視線カーソル)タグ -->
    </a-camera>
</a-scene>

動作確認

このアプリを試すには、プリミティブに貼り付けるテクスチャの画像ファイルを用意する必要があります。以下の 3個の画像をダウンロードしてください(パソコンのブラウザで画像を右クリックして「名前をつけて画像を保存」などの方法で)。ダウンロードした 3個の画像を「vr2」フォルダの中に入れてください(index.html と同じ階層に)。

スマホのブラウザ(Safari や Chrome)を開き、アドレス欄に以下のように入力します。以下の「10.11.52.81」の部分はさきほど調べた IP アドレスです。

スマホで以下のように表示されます。さきほどと同じように VR ゴーグルのアイコンをタップして VR モードにして、スマホを VR ゴーグルに入れて覗き込みましょう。

アクセスすると
アクセスすると

空(背景)、床、箱のプリミティブに画像が貼り付けられました。また、箱のプリミティブがふわりふわりと動いていますね。視界の真ん中に小さな○(カーソル)が出ていますね? 頭を動かしてカーソルを箱のプリミティブに当てると箱のプリミティブが少し大きく膨らみます。さらにずっとカーソルを当てていると、箱のプリミティブがくるくるっと回転します。

解説

まずはプリミティブに貼り付ける画像(テクスチャ)の設定です。

<a-scene>
    <!-- メディアを入れておく a-assets タグ -->
    <a-assets>
        <img id="boxTexture" src="huchan.jpg">      <!-- 箱のテクスチャ -->
        <img id="groundTexture" src="floor.jpg">    <!-- 地面のテクスチャ -->
        <img id="skyTexture" src="sechelt.jpg">     <!-- 背景のテクスチャ -->
    </a-assets>
 
    <!-- a-box:直方体 -->
    <!-- src="#テクスチャ"  position="x y z" [m]  rotation="x y z" [deg]  scale="w h d" [m] -->
    <a-box src="#boxTexture"
        position="0 2 -5"
        rotation="0 45 45"
        scale="2 2 2"
        color="rgb(222, 222, 222)">
        ...

<a-assets> は画像・動画・音声・CG などのファイル(素材)を入れておくタグです。「アセット」といいます。ここでは <img>タグを使って 3個の画像ファイルを読み込んでいます。後からそれぞれの画像を指定するために id 属性に画像の名前を設定しています。

プリミティブにこれらの画像を貼るには、<a-box> などのプリミティブのタグで src 属性を指定します。この src 属性に画像の名前(img タグの id で指定した名前)を指定します。

次にアニメーションの設定です。

    <a-box src="#boxTexture"
        position="0 2 -5"
        rotation="0 45 45"
        scale="2 2 2"
        color="rgb(222, 222, 222)">
        <!-- アニメーションするための a-animation タグ(a-box の子要素として指定すると a-box に適用される) -->
        <!-- attribute="動かす属性"  to="動かす先"  dur="持続時間"  begin="アニメ開始イベント" -->
        <a-animation attribute="position"
            to="0 3 -5"
            dur="2000"
            direction="alternate"
            repeat="indefinite">
        </a-animation>
        ...

<a-box> ~ </a-box> の間に <a-animation> タグを書いています。アニメーションさせたい部品(エンティティ)のタグの間に <a-animation> タグを入れる(子要素にする)ことでその部品にアニメーションを設定することができます。

まず、<a-animation> のattribute 属性で、部品の何をアニメーションさせるかを指定します。例えば最初の <a-animation> では "position" を指定しています。つまり位置をアニメーションさせています。箱のプリミティブが上下方向に位置がふわりふわりとしていたアニメーションの設定です。

<a-animation> でほかに必須なのは to 属性と dur 属性です。to 属性はアニメーションさせる先です。この場合、初めに "0 2 -5" に置いた箱のプリミティブを、to で "0 3 -5" に移動させています。Y 方向に 1m 動かしています。dur 属性はアニメーションさせる時間です。ここでは 2000(単位はミリ秒 [ms])を指定して、2秒間で移動を終えるようにしています。

direction 属性はアニメーションの方向で、ここでは "alternate" つまり「両方向」を指定しています。これで、to で移動した先から最初の位置に戻ってきます。さらに repeat 属性はアニメーションを繰り返す回数(数字)です。ここでは "indefinite" つまり「無限」を指定して、いつまでも繰り返させています。

これ以外にも様々なアニメーションの設定ができます。詳しくはこちらを参考にしてください。

箱のプリミティブにはこれ以外に 以下のような3個のアニメーションが設定されています。

        <a-animation attribute="scale"
            to="2.3 2.3 2.3"
            dur="300"
            begin="mouseenter">
        </a-animation>
        <a-animation attribute="scale"
            to="2 2 2"
            dur="300"
            begin="mouseleave">
        </a-animation>
        <a-animation attribute="rotation"
            to="360 405 45"
            dur="2000"
            begin="click">
        </a-animation>

31行目からのアニメーションは、カーソルが箱のプリミティブに当たった時のアニメーションです。attribute 属性に scale を指定して、初め "2 2 2" だった大きさを "2.3 2.3 2.3" にしています。begin 属性に "mouseenter" とあるように「マウスカーソルが入ったら」アニメーションを開始させています。

あれ? スマホにマウスカーソルはありませんね。はい。それについては後ほど説明しますが、さきほど画面の中に見えていた○がマウスカーソルの代わりです。

残り二つのアニメーションは、"mouseleave" つまり「マウスカーソルが外れたら」はこのプリミティブの scale(大きさ)を元に戻すものと、"click" つまり「マウスがクリックされたら」rotation で箱のプリミティブを回転させるものです。

さて、スマホに無いはずのマウスカーソルについては、以下で指定しています。

    <!-- カメラを操作する a-camera タグ -->
    <a-camera>
        <a-cursor></a-cursor>   <!-- インタラクションするための a-cursor(視線カーソル)タグ -->
    </a-camera>

<a-camera> ~ </a-camera> タグの中で、<a-cursor></a-cursor> というタグを指定しています。これが画面に丸いカーソル(○)を出している部分です。

VR で頭を動かしたら見える方向が変わるのは、CG 世界の中にある仮想的な「カメラ」が動いているからです。その仮想的なカメラを置いているのが <a-camera> ~ </a-camera> です。通常はこれは書かなくても自動で置かれているのですが、ここでは <a-cursor></a-cursor> というタグを書くために、あえて <a-camera> ~ </a-camera> を置きました。スマホにはマウスカーソルが無いので、カメラの向いている方向(の真ん中)をカーソルに見立てます。<a-camera> ~ </a-camera> の中に <a-cursor></a-cursor> と書くことでこのカーソルを表示させています。

箱のプリミティブにこのカーソル(○)を当てたら(箱のプリミティブを画面の真ん中にもってきたら) "mouseenter" イベントが起きて、さきほど設定したアニメーションが動きます。同じようにこのカーソルがプリミティブから外れたら "mouseleave" イベントが起きます。また、このカーソルが一定時間プリミティブに当っていたら "click" イベントが起きます(通常は1500 ms でクリックとみなされます。この時間は変えられます)。

カーソルについて詳しくはこちらを参考にしてください。

また、カメラについて詳しくはこちらを参考にしてください。ちなみに、カメラは最初は position="0 0 0" に置かれています。アニメーションのひとつとして、カメラの場所を動かすこともできます。実際にこちらのページで、ゲームパッドでカメラを動かして VR 空間を動き回るプログラムを作ります。

参考

完成品をこちらに置いてありますからスマホで開いてみてください。

補足

背景のテクスチャ画像はこちら、床のテクスチャ画像はこちらのもの(A-Frame のサンプル用)をダウンロードして、サイズなどを調整しました。なお、a-sky に貼る背景画像については、360度カメラで撮影した写真を使うと、現実世界と VR 世界が混じり合った感じが楽しいことでしょう。

▲TOP

3. CG モデルを登場させる

ここまでは単純なプリミティブだけを使ってきましたが、普通の VR はもっと複雑な CG が使われていますね。次は、より複雑な CG を使ったコンテンツを作ります。

今から作るもの
今から作るもの

プログラミング

Visual Studio Code(または好みのエディタ)を立ち上げて、さきほどの vr2 の index.html をもとに以下のコードを入力しましょう。<title> タグ ~ </a-scene> タグ の部分のみを掲載します(このままコピペするだけでは動きません)。ファイルは、C:\xampp\htdocs フォルダの中に「vr3」というフォルダを作って、「index.html」として保存してください。それぞれのコードが何をしているのか考えながら入力していきましょう。

<title>CG モデルを登場させる</title>
<!-- A-Frame を使うための外部スクリプトの読み込み -->
<script src="https://aframe.io/releases/0.5.0/aframe.min.js"></script>
</head>

<body>
<!-- A-Frame の VR は必ず a-scene タグで囲み、その中に様々なオブジェクト(entities)を置く -->
<a-scene>
    <!-- メディアを入れておく a-assets タグ -->
    <a-assets>
        <a-asset-item id="modelObj" src="huchan.obj"></a-asset-item>    <!-- objファイル -->
        <a-asset-item id="modelMtl" src="huchan.mtl"></a-asset-item>    <!-- mtlファイル -->
        <img id="groundTexture" src="floor.jpg">    <!-- 地面のテクスチャ -->
        <img id="skyTexture" src="sechelt.jpg">     <!-- 背景のテクスチャ -->
    </a-assets>

    <!-- obj 形式の CG モデルを置く a-obj-model タグ、src 属性で obj、mtl 属性で mtl を指定 -->
    <a-obj-model src="#modelObj" mtl="#modelMtl"
        position="0 2 -5"
        scale="0.6 0.6 0.6">
        <!-- アニメーションするための a-animation タグ(a-entity の子要素として指定) -->
        <!-- attribute="動かす属性"  to="動かす先"  dur="持続時間"  begin="アニメ開始イベント" -->
        <a-animation attribute="position"
            to="0 2.5 -5"
            dur="2000"
            direction="alternate"
            repeat="indefinite">
        </a-animation>
        <a-animation attribute="scale"
            to="0.8 0.8 0.8"
            dur="300"
            begin="mouseenter">
        </a-animation>
        <a-animation attribute="scale"
            to="0.6 0.6 0.6"
            dur="300"
            begin="mouseleave">
        </a-animation>
        <a-animation attribute="rotation"
            to="360 360 0"
            dur="2000"
            begin="click">
        </a-animation>
    </a-obj-model>

    <!-- 地面と背景 src="#テクスチャ" -->
    <a-plane src="#groundTexture"
        rotation="-90 0 0"
        width="15"
        height="15">
    </a-plane>
    <a-sky src="#skyTexture"
        color="rgb(127, 127, 127)">
    </a-sky>

    <!-- カメラを操作する a-camera タグ -->
    <a-camera>
        <a-cursor></a-cursor>   <!-- インタラクションするための a-cursor(視線カーソル)タグ -->
    </a-camera>
</a-scene>

動作確認

このアプリを試すには、VR 空間に置く obj 形式の CG モデルを用意します。こちら(モデル本体の obj ファイル)こちら(マテリアル設定の mtl ファイル)をダウンロードしてください(パソコンのブラウザでリンクを右クリックして「名前をつけてリンク先を保存」)。ダウンロードした 2個のファイルは「vr3」フォルダの中に入れてください(index.html と同じ階層に)。

また、プリミティブ(床と空)に貼り付けるテクスチャの画像ファイルを用意する必要があります。さきほどの vr2 フォルダの中からコピーするか、以下の 2個の画像をダウンロードしてください(パソコンのブラウザで画像を右クリックして「名前をつけて画像を保存」などの方法で)。ダウンロードした 2個の画像を「vr3」フォルダの中に入れてください(index.html と同じ階層に)。

スマホのブラウザ(Safari や Chrome)を開き、アドレス欄に以下のように入力します。以下の「10.11.52.81」の部分はさきほど調べた IP アドレスです。

スマホで以下のように表示されます。さきほどと同じように VR ゴーグルのアイコンをタップして VR モードにして、スマホを VR ゴーグルに入れて覗き込みましょう。

アクセスすると
アクセスすると

vr2 までの箱のプリミティブに代わって、より複雑な形の CG モデルが表示されました(愛知淑徳大学人間情報学部のマスコットキャラクター「ヒューちゃん」の CG モデルです)。あとは vr2 と同じように、ヒューちゃんがふわりふわりと動き、頭を動かしてカーソル(○)をヒューちゃんに当てるとヒューちゃんが少し大きく膨らみ、さらにずっとカーソルを当てているとヒューちゃんがくるくるっと回転します。

回転する CG モデル
回転する CG モデル

解説

11・12行目で CG モデルのファイル(obj と mtl)をアセットに読み込んでいます。画像は <img> タグでしたが、CG モデルのようなファイルは <a-asset-item> というタグで読み込みます。

    <!-- メディアを入れておく a-assets タグ -->
    <a-assets>
        <a-asset-item id="modelObj" src="huchan.obj"></a-asset-item>    <!-- objファイル -->
        <a-asset-item id="modelMtl" src="huchan.mtl"></a-asset-item>    <!-- mtlファイル -->
        <img id="groundTexture" src="floor.jpg">    <!-- 地面のテクスチャ -->
        <img id="skyTexture" src="sechelt.jpg">     <!-- 背景のテクスチャ -->
    </a-assets>

次に、この CG モデルを <a-obj-model> というタグで VR 空間に置いています。<a-obj-model> では、src 属性で obj ファイルの id を、mtl 属性で mtl ファイルの id を指定します。

    <!-- obj 形式の CG モデルを置く a-obj-model タグ、src 属性で obj、mtl 属性で mtl を指定 -->
    <a-obj-model src="#modelObj" mtl="#modelMtl"
        position="0 2 -5"
        scale="0.6 0.6 0.6">

あとは、vr2 からさほど変わっていません(サイズや位置などのパラメータが、CG モデルの大きさなどの現物に合わせて少しずつ変わっているだけです)。

なお、今回は私が作った CG モデルをダウンロードして使いましたが、もちろん、自分で作った CG を置いたほうが楽しいでしょう。

参考

完成品をこちらに置いてありますからスマホで開いてみてください。

▲TOP

4. おまけ:スマホカメラと合成して AR & MR

ここまでで普通の VR はできました。あとは工夫次第で様々な VR コンテンツを作るだけです。

最後におまけとして、ちょっと不思議な応用を紹介します。A-Frame は VR 空間の中に動画(mp4 など)を置くことができます。もしその動画を、スマホのカメラの映像に変えることができたら、面白そうではないですか? 現実世界の映像の中に CG が現れます。

立体視(没入)はせず、カメラ映像に CG などを重ねる技術を AR(Augmented Reality; 拡張現実)といいます。

おまけ1:AR(拡張現実)
おまけ1:AR(拡張現実)

カメラ映像に CG などを重ねる AR をベースに、さらに立体視(没入)する技術を MR(Mixed Reality; 複合現実)といいます。

おまけ2:MR(複合現実)
おまけ2:MR(複合現実)

なんだか難しそうですが、プログラム自体は短いものです。挑戦してみましょう。

ただしこのプログラムは Android の Firefox でしか動きません。iOS ではどのブラウザでも動きません。パソコンの Chrome と Firefox では AR のみ動きます(Chrome では https 接続が必要です)。

プログラミング

Visual Studio Code(または好みのエディタ)を立ち上げて、さきほどの vr3 の index.html をもとに以下のコードを入力しましょう。<title> タグ ~ </script> タグ の部分のみを掲載します(このままコピペするだけでは動きません)。ファイルは、C:\xampp\htdocs フォルダの中に「vr4」というフォルダを作って、「index.html」として保存してください。それぞれのコードが何をしているのか考えながら入力していきましょう。

なお、ここまでは A-Frame のタグだけを使ってきて、JavaScript のプログラムは書きませんでした。このプログラムでは少しだけ JavaScript を使います。

<title>VR 空間にカメラ映像を置いて MR</title>
<!-- A-Frame を使うための外部スクリプトの読み込み -->
<script src="https://aframe.io/releases/0.5.0/aframe.min.js"></script>
</head>

<body>
<!-- A-Frame の VR は必ず a-scene タグで囲み、その中に様々なオブジェクト(entities)を置く -->
<a-scene>
    <!-- メディアを入れておく a-assets タグ -->
    <a-assets>
        <a-asset-item id="modelObj" src="huchan.obj"></a-asset-item>    <!-- objファイル -->
        <a-asset-item id="modelMtl" src="huchan.mtl"></a-asset-item>    <!-- mtlファイル -->
        <video id="cam" width="1280" autoplay>      <!-- カメラの映像を流す video 要素 -->
    </a-assets>

    <!-- obj 形式の CG モデルを置く a-obj-model タグ、src 属性で obj、mtl 属性で mtl を指定 -->
    <a-obj-model src="#modelObj" mtl="#modelMtl"
        position="0 2 -5"
        scale="0.6 0.6 0.6">
        <!-- アニメーションするための a-animation タグ(a-entity の子要素として指定) -->
        <!-- attribute="動かす属性"  to="動かす先"  dur="持続時間"  begin="アニメ開始イベント" -->
        <a-animation attribute="position"
            to="0 2.5 -5"
            dur="2000"
            direction="alternate"
            repeat="indefinite">
        </a-animation>
        <a-animation attribute="scale"
            to="0.8 0.8 0.8"
            dur="300"
            begin="mouseenter">
        </a-animation>
        <a-animation attribute="scale"
            to="0.6 0.6 0.6"
            dur="300"
            begin="mouseleave">
        </a-animation>
        <a-animation attribute="rotation"
            to="360 360 0"
            dur="2000"
            begin="click">
        </a-animation>
    </a-obj-model>

    <a-camera>
        <!-- 動画を置く a-video タグを a-camera の子要素にすることで -->
        <!-- リアルカメラの映像が CG カメラ(スマホの動き)についてくる -->
        <a-video src="#cam" position="0 0 -5" width="16" height="12"></a-video>
        <a-cursor></a-cursor>
    </a-camera>
</a-scene>

<script>
    // スマホのカメラやWebカメラ(mediaDevice)の映像を取得する
    var media = navigator.mediaDevices.getUserMedia({
        video: {facingMode: "environment"},             // バックカメラを使う
        audio: false                                    // 音声は使わない
    });
    // mediaDevice の準備ができたら
    media
    .then((stream) => {                                 // 取得成功時の関数
        var cam = document.getElementById("cam");       // video要素を取得
        cam.src = window.URL.createObjectURL(stream);   // video要素にメディアストリームを入れる
    })
    .catch((err) => {                                   // エラー時の関数
        window.alert(err);                              // 警告ダイアログにエラーを表示
    });
</script>

動作確認

このアプリを試すには、VR 空間に置く obj 形式の CG モデルを用意します。さきほどの vr3 フォルダの中からコピーするか、または、こちら(モデル本体の obj ファイル)こちら(マテリアル設定の mtl ファイル)をダウンロードしてください(パソコンのブラウザでリンクを右クリックして「名前をつけてリンク先を保存」)。ダウンロードした 2個のファイルは「vr4」フォルダの中に入れてください(index.html と同じ階層に)。

Android スマホの Firefox を開き、アドレス欄に以下のように入力します。以下の「10.11.52.81」の部分はさきほど調べた IP アドレスです。

スマホで以下のように表示されます。スマホのカメラ映像(現実世界)中にヒューちゃんが浮かんでいます。ヒューちゃんのアニメーションやカーソルでのインタラクションは vr3 と同じです。

AR(拡張現実)モード
AR(拡張現実)モード

さらにスマホを横にして、VR ゴーグルのアイコンをタップして VR モードにして、スマホを VR ゴーグルに入れて覗き込みましょう。カメラの映像は立体的ではないので完全に没入できる感じではありませんが、現実世界の中に立体的なヒューちゃんが浮かんでいます。

MR(複合現実)モード
MR(複合現実)モード

解説

13行目で <a-assets> タグの中に <video> タグを置いています。<video> タグは HTML 標準のタグで、src 属性に動画ファイル(mp4 など)を指定すると動画が再生できます。ひとまずここでは src 属性は指定していません。

これ以降、43行目までは vr3 とほとんど変わりません(床や背景は無くしてあります)。

    <!-- メディアを入れておく a-assets タグ -->
    <a-assets>
        <a-asset-item id="modelObj" src="huchan.obj"></a-asset-item>    <!-- objファイル -->
        <a-asset-item id="modelMtl" src="huchan.mtl"></a-asset-item>    <!-- mtlファイル -->
        <video id="cam" width="1280" autoplay>      <!-- カメラの映像を流す video 要素 -->
    </a-assets>

48行目で <a-camera> タグの中に <a-video> タグを置いています。

    <a-camera>
        <!-- 動画を置く a-video タグを a-camera の子要素にすることで -->
        <!-- リアルカメラの映像が CG カメラ(スマホの動き)についてくる -->
        <a-video src="#cam" position="0 0 -5" width="16" height="12"></a-video>
        <a-cursor></a-cursor>
    </a-camera>

<a-video> は VR 空間の中に動画を表示するパネルを置くタグです。通常は普通の部品(プリミティブや CG モデル)と同じように <a-scene> の下に置きますが、ここで <a-camera> タグの中にあるのがミソです。こうすることで、動画を表示するパネルが VR 空間を写す仮想的なカメラの子要素になります。そうすると、カメラが動くのと一緒に動画を表示するパネルが動きます。つまり、スマホを左右や上下に動かしても、常に真正面に動画が表示されるようになります。

今回の最もメインの処理は 53行目以降の JavaScript です。

<script>
    // スマホのカメラやWebカメラ(mediaDevice)の映像を取得する
    var media = navigator.mediaDevices.getUserMedia({
        video: {facingMode: "environment"},             // バックカメラを使う
        audio: false                                    // 音声は使わない
    });
    // mediaDevice の準備ができたら
    media
    .then((stream) => {                                 // 取得成功時の関数
        var cam = document.getElementById("cam");       // video要素を取得
        cam.src = window.URL.createObjectURL(stream);   // video要素にメディアストリームを入れる
    })
    .catch((err) => {                                   // エラー時の関数
        window.alert(err);                              // 警告ダイアログにエラーを表示
    });
</script>

まず 55行目で mediaDevices.getUserMedia() というメソッドを実行しています。これは、スマホやパソコンのカメラの映像やマイクの音声を取得する命令です。( ) 内のさらに { } の中でオプションを指定します。video 属性で {faceingMode: "environment"} と指定すると、スマホのバックカメラを使います(これが Chrome では対応していない)。音声は使わないので audio 属性に false を指定しています。

60行目以降は、mediaDevice の準備ができたら呼ばれる処理です。.then() の ( ) 内で、映像の取得に成功した時の処理を書きます。ここでは、さきほど置いた <video> タグを取得したうえで、その src 要素にカメラの映像を入れています。つまり、mp4 などの動画の代わりに、カメラで撮影されたリアルタイムの映像を <video> タグに流し込んでいます。window.URL.createObjectURL という命令はややこしいですが、ここでは「そういうふうにして映像を渡す」おまじないと思ってください(自身で調べてみてください)。

.catch() の ( ) 内は、映像の取得に失敗した時の処理です。単に警告ダイアログを出しているだけです。

処理の流れをまとめると...

少しややこしい手順ですが、これによってカメラの映像と VR が合成されました。なんだか不思議な感覚ではありませんか?

参考

完成品をこちらに置いてありますから Android スマホの Firefox で開いてみてください。

▲TOP

まとめ

スマホで VR、いかがでしたか?

VR の鍵は、CG と立体視とセンサです。従来は(2015年の末までは)、CG の表示も、立体視の処理も、センサの処理も、すべてプログラミングして初めて VR コンテンツを作ることができました。A-Frame を使えば、ほとんどプログラミングすることなく、HTML を書くだけで VR ができてしまいました。素敵ですね。そしてなにより、スマホと安価な VR ゴーグルだけで楽しめるのが良いですね。

VR を作るだけならこんなに簡単になりました。さぁ、あとはアイデア次第です。どんどん VR コンテンツを作りましょう!

なお、CG モデルの作り方はここでは紹介しませんでした。例えば Windows 10 には「3D Builder」というソフトウェアがはじめから入っています。他にも例えば、BlenderMetasequoiaGoogle SketchUp などが無料で使えるメジャーな CG ソフトウェアです。どれを使っても構いません。最終的に「*.obj」というファイル形式でモデルを保存すれば A-Frame で表示できます。また、A-Frame Inspector という機能を使うと、コンテンツ作成中にブラウザ上でプリミティブを組み合わせて複雑な CG を作っていくことができます。慣れてきたら挑戦してみてはどうでしょう?

今回紹介した A-Frame 以外にも VR コンテンツを作る方法はたくさんあります。しかし、現在最も簡単なのがこの A-Frame だと思います。A-Frame は簡単なだけでなく、今回「おまけ」で紹介したように、HTML や JavaScript が持っている様々な機能を組み合わせて使うことで VR コンテンツを強力にもできます。

まずは個人としてゲーム作りなどで楽しんで、慣れて、どんどん応用を考えてみましょう!

補足

上で作ったコードはすべてこちら(GitHub)に置いてありますから、参考にしてください。

▲TOP