ここではプリミティブという要素とエンティティコンポーネントフレームワークの関係性について見ていきます。 もしあなたがHTMLとプリミティブの利用法を探しているのなら、ベーシックシーンを作る guideを当たってください。

# HTML

A-FrameはHTML (opens new window)とカスタム要素をポリフィルとして使ったthe DOM (opens new window)の上に作られています。 HTMLはWebを作る際のブロックであり、世界で最もアクセシブルなコンピューター言語です。 インストーラーやビルド作業は不要で、HTMLタグをHTMLファイルに書き、ブラウザで開くだけです。

全てのWebはHTMLの上に作られており、ReactやVue.js、Angular、d3.jsやjQueryのようなライブラリを利用できます。

HTMLのシーン

もしHTMLに慣れていなくても問題ありません。A-Frameは二次元のHTMLより簡単に概要を掴むことが可能です。 HTMLの基本的な構造や作法(開始タグ閉じタグ、属性など)さえわかっていればOKです。

HTMLについてはこちらを御覧ください (opens new window).

HTML

# プリミティブ

HTMLの階層構造は初心者にも優しいですが、A-Frameを使う上では、HTMLとDOMは唯一の抽象的なレイヤーとなります。 この仕組のもとで、A-Frameはthree.jsを宣言的に用いるエンティティコンポーネントのフレームワークとして動いています。

A-Frameには数えられるほどの要素しかありません。例えば<a-box><a-sky>などです。 これらはプリミティブと呼ばれており、エンティティコンポーネントパターンを内包することで、初心者にも優しい作りとなっています。 このドキュメントのナビゲーションバーの最下部にはA-Frameを用いた様々なプリミティブを見ることができます。 開発者は自身で自由にプリミティブを作ることもできます。

#

以下の方法で恒例のHello, WebVRを基本的なプリミティブを使って表示させることができます。 A-Frameではプリミティブを用いてメッシュを作成し、360度のコンテンツを描画して、環境をカスタマイズしカメラを置くことができます。

<html>
  <head>
    <script2 src="https://aframe.io/releases/1.2.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>

# フードの中身

プリミティブは非常に使い勝手の良いレイヤーとして振る舞います。主に勝手の知らない人にとってはわかりやすいです。 プリミティブは<a-entity>の中にあるものだということを忘れないでください。 プリミティブは

  • セマンティックな(意味のある)名前を持っており (たとえば <a-box>)
  • ディフォルト値を持ったコンポーネントをまとめたプリセットがあり
  • component データに対して マッピングもしくはプロキシ化されたHTML属性が与えられています

プリミティブはprefabs in Unity (opens new window)と似ています。 エンティティコンポーネントシステムパターンに関する文献では、それらをassemblages (opens new window)と紹介しています。 これはコアコンポーネントAPIを

  • 有益なコンポーネントを予め定義されたデフォル値をもって事前に結合し
  • <a-sky>のように複雑でありながら簡潔なエンティティを使うための簡略語として機能させ
  • A-FrameがHTMLを新しい方向性で利用していることによって、初心者にもわかりやすいインターフェースを提供している ことを通じて抽象化します。

フードの下では <a-box> プリミティブは

<a-box color="red" width="3"></a-box>

このようなエンティティコンポーネントの形を取ります

<a-entity geometry="primitive: box; width: 3" material="color: red"></a-entity>

<a-box>geometry.primitiveプロパティをboxとしてデフォルト化します。 そしてこのプリミティブはHTMLのwidth属性をgeometry.widthとして置き換え、そしてcolor 属性を material.color プロパティに置き換えます。

# プリミティブにコンポーネントをつける

プリミティブは フードの下では <a-entity> として配置されます。 これは、プリミティブが位置や角度傾き、縮尺、追加コンポーネントなどのようなエンティティと同じようなAPIを持つことを意味しています。

#

物理コンポーネントにプリミティブを追加してみましょう。 Don McCurdy's aframe-physics-system (opens new window) を使って HTMLに以下のように記述して物理コンポーネントを追加します。

<html>
  <head>
    <script2 src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
    <script2 src="https://unpkg.com/aframe-physics-system@1.4.0/dist/aframe-physics-system.min.js"></script>
  </head>
  <body>
    <a-scene physics>
      <a-box position="-1 4 -3" rotation="0 45 0" color="#4CC3D9" dynamic-body></a-box>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" static-body></a-plane>
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>
  </body>
</html>

# プリミティブの登録

自分でプリミティブを登録することもできます。(言い換えれば、エレメントを登録する、という意味です) それには AFRAME.registerPrimitive(name, definition) に書きます。 name は文字列で、ダッシュで囲う必要があります。('a-foo'のように)。 definition はJavaScriptのオブジェクトで以下のプロパティを定義しています。

We can register our own primitives (i.e., register an element) using AFRAME.registerPrimitive(name, definition). name is a string and must contain a dash (i.e. 'a-foo'). definition is a JavaScript object defining these properties:

Property 説明 Example
defaultComponents プリミティブの初期コンポーネントを定義するオブジェクト。コンポーネントの名前と値がコンポーネントのデフォルトデータとなることが重要ですdata. {geometry: {primitive: 'box'}}
mappings HTMLアトリビュート名とコンポーネントのプロパティ名の合致を定義するオブジェクトです。HTMLのアトリビュート名が更新されたときは、このプリミティブは対応するコンポーネントプロパティを更新します。このコンポーネントプロパティは${componentName}.${propertyName}のようにドットとシンタックスで定義されます
{depth: 'geometry.depth', height: 'geometry.height', width: 'geometry.width'}

#

下記は<a-box>の登録例です。

var extendDeep = AFRAME.utils.extendDeep;

// この mesh mixin はメッシュベースのプリミティブを生成する際に共通のマテリアルプロパティを提供します
// これはマテリアルコンポーネントをデフォルトのものとし、基本となるマテリアルプロパティをマッピングします。
var meshMixin = AFRAME.primitives.getMeshMixin();

AFRAME.registerPrimitive('a-box', extendDeep({}, meshMixin, {
  // デフォルトコンポーネントのプリセットです。 コンポーネントとコンポーネントプロパティはboxの外部にあるエンティティに付与されます。 
  
  defaultComponents: {
    geometry: {primitive: 'box'}
  },

  // HTMLから定義された突き合わせはコンポーネントプロパティに属性を与えます(ドットを区切り文字として使うことができます)
  // もしHTMLで`depth="5"` と書いた場合、プリミティブは自動的に`geometry="depth: 5"`.とセットされます。
  mappings: {
    depth: 'geometry.depth',
    height: 'geometry.height',
    width: 'geometry.width'
  }
}));

Don McCurdy氏の aframe-extras (opens new window) パッケージには、<a-ocean> プリミティブが入っており、その中に ocean コンポーネントが含まれています。

<a-ocean> の定義は以下のとおりです。

AFRAME.registerPrimitive('a-ocean', {
  // Attaches the `ocean` component by default.
  // Defaults the ocean to be parallel to the ground.
  defaultComponents: {
    ocean: {},
    rotation: {x: -90, y: 0, z: 0}
  },

  // Maps HTML attributes to the `ocean` component's properties.
  mappings: {
    width: 'ocean.width',
    depth: 'ocean.depth',
    density: 'ocean.density',
    color: 'ocean.color',
    opacity: 'ocean.opacity'
  }
});

登録された <a-ocean> プリミティブで、伝統的なHTMLを用いた海を作り出すことができます。

<a-ocean color="aqua" depth="100" width="100"></a-ocean>