48
A-Frame Hands-on 2017/01/29 杉井庸一

A frameハンズオン 20170129

Embed Size (px)

Citation preview

A-FrameHands-on

2017/01/29 杉井庸一

お願いHTML、Javascriptの知識がある人を前提に書いています。

以下の機器をご用意ください◦ ハンズオン用のPC

◦ インターネットにつなげられる機器(ポケットWiFiやテザリングなど)

事前に以下のソフトウェアをインストール願います。◦ Google Chrome (スマホで確認したい人は、スマホにもGoogle Chrome)

◦ Node.js

◦ HTML開発に使用するお好きなテキストエディタ

自己紹介杉井 庸一@修羅の国(広島に単身出張中)

興味本位で買ったRicohThetaS、の画像を見るお手軽なViewerがほしくて、いろいろ調べてA-Frameに出会う。

ブラウザで手軽にコンテンツを作れるのが面白くて、いろいろ作ってFacrebookで公開していたら、いつの間にかハンズオンを開催@福岡することに。

仕事はバックエンドのシステムエンジニア。JavaやらSQLやらを好みます。実はA-Frameに出会うまでJavascript使ったことなかったです。

環境設定A-Frameのボイラープレートを使って環境構築します。

以下よりボイラープレートのZIPファイルを取得して解凍する。◦ https://aframe.io/docs/0.4.0/introduction/getting-started.html

◦ コマンドプロンプト(Macはターミナル)を起動し、解凍したフォルダへ移動します。初回設定のコマンドを実行する。

◦ > npm install

◦ ※各種ダウンロードします。しばらく時間がかかります。

サーバ起動のコマンドを実行する。◦ > npm start

◦ ※既定のブラウザが起動し、index.htmlを表示します。

終了する際は、以下のコマンドを実行する。◦ > Ctrl + c

詳細は、ZIPファイルに同梱のREADME.mdを確認ください。

目次環境設定

A-Frameとは

3Dシーンを扱うための基礎知識◦ 座標、向き、大きさ

◦ 登場人物

◦ カメラ

◦ ライト

Hands-on(1)◦ ソース構成

◦ 各エンティティ説明

Hands-on(2)◦ DOMの操作

◦ Entity-Component-System

◦ 追加コンポーネント

◦ ソース構成

◦ 実装手順

Hands-on(3)◦ コンポーネントの作成

◦ Javascriptのデバッグ方法

◦ 実装手順

A-frameとは

A-frameとはブラウザ上でVRを実現するための技術としてWebVRという規格があります。それを簡単に実現するためのライブラリがA-Frameです。

WebVR1.0規格を策定・提案しているMozillaがA-Frameを作成しています。

ブラウズとしては、Firefox、Chrome、EdgeがWebVR対応を表明しています。

A-frameとは複雑なWebGL、Three.jsをラップし、比較的簡単なHTML、Javascriptを用いてブラウザでVRを実現するライブラリ。

ブラウザだけではなく、OculusやHTCViveなどのHMDや、モバイルVRもサポート。

内部的にはThree.jsを使用し、加えてEntity-Component-Systemに代表されるゲーム開発のベストプラクティスを取り込んでいます。

A-frameとは公式サイト:https://aframe.io/

Document:https://aframe.io/docs/

ソース:https://github.com/aframevr/aframe

リンク集:https://github.com/aframevr/awesome-aframe

もちろんEnglishです。

3Dシーンを扱うための基礎知識

座標、向き、大きさ座標(POSITION)

◦ Y-up右手座標系◦ X座標:向かって右がプラス

◦ Y座標:向かって上がプラス

◦ Z座標:向かって後ろがプラス

向き(ROTATION)◦ 向きの単位は度。

◦ 0~360などを指定。マイナス値も指定可能。

大きさ(SCALE)◦ 長さの単位はメートル。

◦ 例:目線の高さは、Y座標:1.6

登場人物シーン(SCENE)

◦ 3D空間そのもの。ここにカメラ、ライト、エンティティを配置して3DCGの世界を構築していきます。

カメラ(CAMERA)◦ 構築した3DCGの世界をどのように見るかはカメラによって決まります。

ライト(LIGHT)◦ ライトがなければ3DCGの世界は真っ暗です。光源を設定しましょう。

エンティティ(ENTITY)◦ 3DCG空間に存在する物です。球や平面など様々です。

カメラA-Frameにてデフォルトで使われているPerspectiveCameraを説明します。

画角(FOV)◦ 視野角です。広いと魚眼になります。

ファークリップ(FAR)◦ 最長距離。これより遠いと映りません。

ニアークリップ(NEAR)◦ 最短距離。これより近いと映りません。

アスペクト(ASPECT)◦ 縦横比:width / height

◦ 通常は「画面幅/画面高さ」を設定

ライトライトには様々な種類があります。

平行光源(DIRECTIONAL)◦ 太陽光を表現する。

環境光源(AMBIENT)◦ 拡散光を表現する。

半球光源(HEMISPHERE)◦ 地面からの照り返しを表現する。

点光源(POINT)◦ 豆電球のような光源を表現する。

スポットライト(SPOT)◦ 一部を局所的に照らす光源を表現する。

Hands-on(1)A-FRAMEに触れてみよう

ソース構成(Index.html)

A-Frameライブラリの読み込み0.4.0に変更

ここにエンティティを追加していきま

す。

ENTITYA-SCENE

HTMLのBody句内に<a-scene>~</a-scene>と記載して使用します。

すべてのEntityはこのSCENEに属します。

シーンをつかさどる様々なプロパティを持っています。

デフォルトでカメラとライトを持っています。

A-BOX

a-sceneタグ内に、<a-box>~</a-box>と記載して使用します。

四角の立方体や直方体、壁などを生成できます。

v0.1.0以前はa-cubeというタグ名でした。

ENTITYA-SPHERE

a-sceneタグ内に、<a-sphere>~</a-sphere>と記載して使用します。

球を生成できます。

設定によっては、半球なども生成できます。

A-CYLINDER

a-sceneタグ内に、<a-cylinder>~</a-cylinder>と記載して使用します。

円柱を生成できます。

ENTITYA-PLANE

a-sceneタグ内に、<a-plane>~</a-plane>と記載して使用します。

2Dの平面を生成できます。

A-SKY

a-sceneタグ内に、<a-sky>~</a-sky>と記載して使用します。

半径5000の巨大な球を生成し、背景として利用します。

RicohThetaSなどで撮影した360度天球画像を、このa-skyのsrc属性に画像指定してViewerとする例が多くみられます。

ENTITYA-CAMERA

デフォルトが用意されています。

a-scene内に新たに作成するとデフォルトが消えて、置き換わります。

A-LIGHT

デフォルトが用意されています。

a-scene内に新たに作成するとデフォルトが消えて、置き換わります。

A-ANIMATIONEntityの属性を変化させることによりアニメーションを実現する。

変化させるEntityタグの子Entityとして設定する

属性 説明

attribute アニメーションさせる親エンティティの属性。

direction From-To間の方向、向き設定

from 開始時値

to 終了時値

dur アニメーション間隔(msec)

repeat アニメーション回数。回数制限なしの場合は”indefinite”を指定

easing アニメーションの進み具合

(例)<a-box position="-1 0.5 -3">

<a-animationattribute = "position"direction = "alternate"from = "-1 0.5 -3"to = "-1 1 -3"dur = 1000repeat = "indefinite"

></a-animation>

</a-box>

次メジャーバージョン(v0.5.0)から廃止予定

A-frame inspectorCtrl + Alt + iと入力する。

ブラウザ上で、エンティティの新規作成や修正を行うことができます。

移動:右クリック+マウス移動

回転:左クリック+マウス移動

前後:マウスホイール

作成したエンティティはHTML形式でExportすることもできます。

a-framer.com英語が苦手な人向けに、ドキュメント(v0.3.0ベース)の主要部分を翻訳されたサイトがあります。

http://www.a-framer.com/

本日ハンズオン主催の米本さんが作成されています。

本家の英語ドキュメントのニュアンスがわからない場合など、一読することをお勧めします。

Hands-on(2)JAVASCRIPTでA-FRAMEを操る

どんなの作る?ランダム迷路を作成します。

迷路作成ロジックの結果(二次元配列)を使ってa-frame上に壁(a-box)を作成することで迷路を実現します。

aframe-extrasという追加ライブラリを使用します。a-boxにstatic-body、a-cameraにkinematic-bodyの機能を追加して、衝突を実現します。

DOMの操作A-FrameのDOMは通常のHTMLと同様にJavascriptで操作可能です。

DOMの取得◦ document.querySelector(“#DOMのID”);

DOMの作成◦ document.createElement(“タグ名”);

属性の設定◦ 対象DOM.setAttribute(“属性名”, “値”);

DOMの追加◦ 親DOM.appendChild(追加するDOM);

(例)var sceneEntity = document.querySelector("#sceneId");var boxEntity = document.createElement("a-box");boxEntity.id = “box01”;boxEntity.setAttribute("position", "0 1.7 0");sceneEntity.appendChild(boxEntity);

Entity-Component-SystemA-Frameはエンティティ・コンポ―ネント・システム(ECS)の形式に基づいています。これはインヘリタンス(継承)よりもコンポーザビリティに重きを置くゲーム開発では一般的な形式です。

◦ エンティティ:本質的には何もせず、レンダリングも行わない汎用的なオブジェクトを指す。

◦ コンポーネント:エンティティの中に挿入され形、動き、機能を与えるための再利用可能なモジュール。挿入すればそのまま実行される。

◦ システム:コンポーネントのクラスにグローバルスコープ、サービス、マネジメントを提供する。

ECSでは、エンティティに異なるコンポーネントを挿入することにより、リッチなアクションを伴った複雑なエンティティを作ることができます。

ハンズオンでは、壁を通り抜けないように衝突を表現するコンポーネントを追加し、壁との距離に応じて壁の表示/非表示を実現するコンポーネントを作成します。

追加コンポーネントA-Frameには様々な追加コンポーネントが存在します。RegistryやGithubで見つけましょう。

名前 内容

aframe-extras Utility集。様々なコンポーネント

aframe-bmfont-text-component 3Dシーン内にテキストを表示する

aframe-look-at-component 指定したEntityの方向を自動で向き続ける

aframe-crawling-cursor 面に沿ってCursorが張り付くように表現

aframe-leap-hands LeapMotionを扱うことができる

・・・

ソース構成添付のZIPファイルをA-Frameボイラープレートフォルダ直下に解凍する。

> npm startで起動し、http://localhost:3000/maze/へアクセスする。

迷路ロジックは実装済み。3Dシーンに迷路エンティティを作成していきます。

修正するのはindex.htmlだけです。

本ページに添付している「ソースファイル」から取得してください。

aframe-boilerplate-master│ .gitignore│ AFRAME_SITE.yml│ index.html│ LICENSE│ package.json│ README.md└─maze

│ index.html└─js

maze.js

実装手順1

var sceneEntity = document.querySelector("#maze-scene");

後でA-BOXを追加するため、追加先のA-SCENEを取得します。IDの設定に間違いがないことを確認しましょう。

実装手順2

var wall = document.createElement("a-box");sceneEntity.appendChild(wall);

A-BOXエンティティを作成し、A-SCENEに追加します。足元に小さなBOXが現れています。A-BOXの場所を設定しましょう。

実装手順3

wall.setAttribute("position", posX + " 0 " + posZ);

A-BOXエンティティ追加前に、位置(POSITION)を指定します。位置情報は迷路のXZ座標に壁の横幅をかけた「posX」、「posZ」を使用します。このままでは壁が小さすぎます。

実装手順4

wall.setAttribute("width", width);wall.setAttribute("height", width);wall.setAttribute("depth", width);

A-BOXエンティティ追加前に、大きさ(WIDTH,HEIGHT, DEPTH)を指定します。設定値は、変数設定(width)している壁幅を利用しましょう。

しかしこれだと、壁が半分床に埋まっており、高さが足りません。

実装手順5

posX + " " + width/2 + " " + posZ

A-BOXエンティティ追加前に、Y軸位置を調整して

壁をすべて床の上に表示します。設定値は、変数設定(width)している壁幅を利用しましょう。見た目は迷路となりましたが、壁を突き抜けます。

実装手順6A-BOXエンティティ追加前に、static-bodyコンポーネントを追加し、壁との衝突を表現します。

これで迷路としては最低限完成です。色・画像を付ける、アニメーションさせるなど手を加えてみてください。

wall.setAttribute("static-body", "");

aframe-extras今回利用した「physics」、「static-body」、「kinematic-body」以外にも、様々なコンポーネントが存在します。サンプルサイトで動作およびソースを確認し、取り込んでみてください。

https://github.com/donmccurdy/aframe-extras

https://sandbox.donmccurdy.com/vr/

A-Frame助け合い所@Facebookある程度作れるようになると、一人では解決できないことも出てきます。

そんな時には、Facebookの「A-Frame助け合い所」に投稿してみんなで解決しましょう!

私も参加していますので、ハンズオンでの疑問や質問など気軽に質問してください。

Hands-on(3)A-FRAMEのコンポーネントを作成する

どんなの作る?Hands-on(2)で作成した迷路に機能・ふるまいを加えます。

カメラとの距離に応じて、壁の表示/非表示制御を加えることで、直前までどこに壁があるかわからないようにします。

Hands-on(2)ではコンポーネントを利用しましたが、今回はコンポーネントを自分で作成します。

コンポーネントの作成エンティティにつける新しい機能・ふるまいを作成します。

conponent-name: コンポーネントの名前。エンティティにつける際の名称となります。英字で好きな名前をつけます。

schema:エンティティにつけるときに引数を設定できます。

init:最初に呼ばれる処理です。主に初期化や必要な情報を取得する処理を書きます。

tick:画面が描画される1フレーム毎に呼ばれる処理です。連続した処理が必要な場合に使います。

AFRAME.registerComponent(‘component-name', {

schema: {

// コンポーネントの引数設定。

},

init: function () {

// 初期処理

},

tick: function() {

// 1フレーム毎の処理(最大60回/秒)

}

});

Javascriptのデバッグ方法(Chrome)Javascriptの動作確認方法を紹介します。

デバッグ画面を表示する。◦ F12を押すとデバッグ画面になります

コンソール出力を確認する。◦ Consoleタブを選択すると、ログが表示されます

コンソールへ値を出力する◦ Javascript内でconsole.log(変数)と入力すると、変数値がコンソールへ出力されます。

ブレイクポイントで途中経過を確認する◦ Sourcesタブでソースを表示し、行番号部分をクリックすると、処理がそこで止まるようになります。

AndroidスマホChromeもPCからデバッグ可能。

実装手順1まずはA-BOXに、今回作成するコンポーネントを追加しましょう。作成するコンポーネントはmaze.js内にひな形を用意しています。

wall.setAttribute("visible-wall", "");

実装手順2

this.el.object3D.visible = false;

js/maze.jsを開きます。初期処理で、壁を非表示とします。

実装手順3毎フレーム毎にカメラの位置と、壁の位置を取得します。

var cameraPosition = this.el.sceneEl.camera.el.object3D.position;var wallPosition = this.el.object3D.position;

実装手順4

if (wallPosition.distanceTo(cameraPosition) < 10) {if (this.el.object3D.visible == false) {

this.el.object3D.visible = true;}

}

以下の場合に、壁を表示します。・カメラと壁の距離が10m以内・壁がまだ非表示状態のもの

実装手順5

} else {if (this.el.object3D.visible == true) {

this.el.object3D.visible = false;}

}

逆に以下の場合に、壁を非表示とします。・カメラと壁の距離が10m以上・壁が表示状態のもの

実装手順6

distance: {default: 10},

10↓

this.data.distance

“”↓

“distance: 5”

10m固定としている距離を引数として渡せるように修正。A-BOX側に引数設定を入れます。

ハンズオンは以上ですありがとうございました