読者です 読者をやめる 読者になる 読者になる

roman-tech

テクノロジーはロマンだ。

超お手軽VR開発フレームワーク A-FRAME入門:第5回 コスモ(小宇宙)を感じようpart1

a-frame vr

こんにちは。先日7/7は七夕でしたが、みなさんゆっくり夜空を眺めることができたでしょうか?僕は七夕のことはすっかり忘れていて見逃してしましました。七夕を見逃した人たちのために、本日はVRでコスモ(小宇宙)を感じることができるプロトタイプを作成したいと思います。ちょっと長くなりそうなので二回に分けてお送りします。

目的

  • 宇宙のようなVR空間を構築する
  • イメージとしては360VR空間内に星を無数に配置するような感じ

本記事で学べること

  • 三角関数を応用する
  • 動的にオブジェクトを作成する

開発編

前提として星の数は膨大でありHTMLに記載するのはかなり面倒くさいです。また、HTMLだけだと動的にオブジェクトを生成したり、オブジェクトの座標を変えたりするのが難しいため、今回から積極的にJavascriptを使用します。
さぁ、早速開発に入りましょう。

星の配置

星の描画には以下の画像を使います。

f:id:roman-tech:20160710125022p:plain:w300

この画像を自分を中心とした球上に貼り付けていきます。イメージとしては以下のような感じで、赤色の部分が星の画像になります。

f:id:roman-tech:20160710125628j:plain:w300

ここで問題となるのが、どうやって星の画像を配置する座標を決めるのか?です。
これを解決するのが三角関数(sin, cos)です。

学生のころ
三角関数なんか何に使うんや。。。
と思っていた方々!朗報です!今から使います!むしろ三角関数が無いと何もできません。

では早速球面上に星の画像を配置する方法を検討しましょう。
かなり今更ですがA-FRAMEの座標系は以下のようになっています。赤字で書いた部分がカメラになっており、起動時にカメラはZ軸のマイナス方向を向いています。

f:id:roman-tech:20160710131019j:plain:w300

次に画像を貼り付けるx, y, z座標の計算方法について考えます。色々な手法がありますが、今回はy座標を決めて、そこからx,z座標を求める方法について記載します。

y座標を求める

まずは、以下のようにVR空間をx, y軸平面に水平な方向から見ます。

f:id:roman-tech:20160710132129j:plain:w300

ここからy座標は以下の式で求めることができます。

y = radius1 × sin(theta1)

ここまでは簡単ですね。

x, z座標を求める

ここからがちょっとわかりにくいのですが、次にx, z座標を求めるためにVR空間をx, z軸平面に水平な方向から見ます。

f:id:roman-tech:20160710133018j:plain:w300

x, z座標を求めるにはradius2が必要になってきます。radius2はy座標を求める際にcosを使うことで以下のように求められます。

radius2 = radius1 × cos(theta1)

そしてradius2を使ってx, z座標は以下のように求められます。

x = radius2 * cos(theta2)
z = radius2 * sin(theta2)

そしてこれらをソースコードに落とし込んだのが以下です。

[index.html]
<html>
<head>
    <meta charset="utf-8">
    <title>universe</title>
    <script src="../lib/aframe.js"></script>
    <script src="sub.js"></script>
    <script src="Utils.js"></script>
</head>

<body onload="init()">
    <a-scene>
        <a-assets> <img id="star2" src="star2.png"></a-assets>
        <a-camera position="0 0 0"></a-camera>
        <a-sky color="#000">
    </a-scene>
    </a-scene>
</body>
</html>

以下では星の画像をidを付けてロードしています。

<a-assets> <img id="star2" src="star2.png"></a-assets>

そしてJavacriptの中で画像を動的にVR空間に配置していきます。このとき、貼り付ける場所をランダムにするようにrandom関数を使ってtheta1, theta2を初期化しています。

[sub.js]
/* 
画像の貼り付け関数
imgNameで指定した画像をsizex, sizeyのサイズでr_minからr_maxの半径の間にnum枚貼り付ける。

imgName:画像のID名
sizex:画像の幅
sizey:画像の高さ
r_min:radiusの最小値
r_max:radiusの最大値
num:画像を貼り付ける数
 */
function genStar(imgName, sizex, sizey, r_max, r_min, num)
{
    var theta1;
    var theta2;
    var radius1;
    var radius2;
    var tmp;
    // generate star
    var scene = document.querySelector('a-scene');
    for (var i = 0; i < num; i++) {    
        theta1 = random(0, 360);
        theta2 = random(0, 360);
        
        var star = document.createElement('a-image');
        star.setAttribute('src', imgName);
        star.setAttribute('width', sizex);
        star.setAttribute('height', sizey);
        
        radius1 = r_min;
        var y = radius1 * Math.sin(deg2rad(theta1));
        radius2 = radius1 * Math.cos(deg2rad(theta1));
        var x = radius2 * Math.cos(deg2rad(theta2));
        var z = radius2 * Math.sin(deg2rad(theta2));
        var str = String(x) + " " + String(y) + " " + String(z);
        star.setAttribute('position', str);
        scene.appendChild(star);
    }
    
}

/* ロード時に呼ばれる初期化関数 */
function setup() {
    genStar('#star2', '50', '50', 700, 1000, 500);
}

function init() {
    setup();
}
[Utils.js]
/* 度数法(0-360)からradianへの変換関数 */
function deg2rad( deg ) {
    return (deg * Math.PI / 180);
}

/* minからmaxまでの範囲の乱数を生成 */
function random(min, max)
{
    return Math.random()*(max - min) + min;
}

結果を見てみましょう!!
正面の方は

f:id:roman-tech:20160710135822j:plain:w500

お!なんだかいい感じに星画像が散らばってますね!
それでは横を向いてみましょう!!

f:id:roman-tech:20160710135931j:plain:w500

なんかちがくね?
それもそのはず。今は画像のローテーション設定ができていないため以下のように画像がすべて横向き状態になっています。

f:id:roman-tech:20160710140554j:plain:w300

まだまだ改善の余地がありますが、サンプルをとりあえずあげておきました。ご覧ください。超イマイチです。
universe



みなさんとりあえず、三角関数のリハビリはできましたでしょうか?次は画像のローテーション設定をA-FRAMEの機能を使って修正してプロトタイプを作りあげます。

お楽しみに!!



以下VR開発にオススメです!

© 2016 Tsukasa Horinouchi