Skip to content

Commit

Permalink
Add gltf-model component and system. (#2333)
Browse files Browse the repository at this point in the history
* Add gltf-model component and system.

Fixes #2261.

* Set *.bin extension as binary.

* Remove model; reference assets repo.

* Rename system API to (un)registerModel.

* Add component docs.

* Add primitive wrapper, and docs.

* Revert .gitattributes changes.

* Add registration for <a-gltf-model/>.

* Add tests.

* what other tests

* Fix errors in docs.

* Add formats to meta title/desc.

* Remove material extensions from collada and gltf primitives.

* Add tests for gltf-model system.

* Add labels to models demo.

* Add 'Why use glTF' section.

* Wording tweak.

* sigh
  • Loading branch information
donmccurdy authored and ngokevin committed Feb 2, 2017
1 parent 1cdd87a commit 6306459
Show file tree
Hide file tree
Showing 17 changed files with 590 additions and 6 deletions.
81 changes: 81 additions & 0 deletions docs/components/gltf-model.md
@@ -0,0 +1,81 @@
---
title: gltf-model
type: components
layout: docs
parent_section: components
---

[about-gltf]: https://www.khronos.org/gltf

[glTF][about-gltf] (GL Transmission Format) is an open project by Khronos providing a common, extensible format for 3D assets that is both efficient and highly interoperable with modern web technologies.

The `gltf-model` component loads a 3D model using a glTF (.gltf or .glb) file.

## Why use glTF?

[obj-model]: ./obj-model.md
[collada-model]: ./collada-model.md

In comparison to the older [OBJ][obj-model] format, which supports only vertices, normals, texture coords, and basic materials, glTF provides a more powerful set of features. In addition to all of the above, glTF offers:

- Hierarchical objects
- Scene information (light sources, cameras)
- Skeletal structure and animation
- More robust materials and shaders

For simple models with no animation, OBJ is nevertheless a common and reliable choice.

In comparison to [COLLADA][collada-model], the supported features are very similar. However, because glTF focuses on providing a "transmission format" rather than an editor format, it is more interoperable with web technologies. By analogy, the .PSD (Adobe Photoshop) format is helpful for editing 2D images, but images are converted to .JPG for use on the web. In the same way, glTF is a simpler way of transmitting 3D assets while rendering the same result.

In short, expect glTF models to work with A-Frame more reliably than COLLADA models.

## Example

Load a glTF model by pointing to an asset that specifies the `src` for a glTF file.

```html
<a-scene>
<a-assets>
<a-asset-item id="tree" src="/path/to/tree.gltf"></a-asset-item>
</a-assets>

<a-entity gltf-model="#tree"></a-entity>
</a-scene>
```

## Values

| Type | Description |
|----------|--------------------------------------|
| selector | Selector to an `<a-asset-item>` |
| string | `url()`-enclosed path to a glTF file |

## Events

| Event Name | Description |
|--------------|--------------------------------------------|
| model-loaded | glTF model has been loaded into the scene. |

## Loading Inline

Alternatively, load a glTF model by specifying the path directly within `url()`. This is less performant than using the asset management system.

```html
<a-entity gltf-model="url(/path/to/tree.gltf)"></a-entity>
```

## More Resources

The glTF format is fairly new, and few editors will export a `.gltf` file directly. Instead, various converters are available or in progress:

[fbx-converter]: http://gltf.autodesk.io/
[collada-converter]: http://cesiumjs.org/convertmodel.html
[obj-converter]: https://github.com/AnalyticalGraphicsInc/obj2gltf

- [FBX → glTF][fbx-converter] - coming soon.
- [COLLADA → glTF][collada-converter].
- [OBJ → glTF][obj-converter].

[spec]: https://github.com/KhronosGroup/glTF

See the [official glTF specification][spec] for available features, community resources, and ways to contribute.
33 changes: 33 additions & 0 deletions docs/primitives/a-gltf-model.md
@@ -0,0 +1,33 @@
---
title: <a-gltf-model>
type: primitives
layout: docs
parent_section: primitives
---

The glTF model primitive displays a 3D glTF model created from a 3D
modeling program or downloaded from the web.

## Example

```html
<a-scene>
<a-assets>
<a-asset-item id="tree" src="tree.gltf">
</a-assets>

<!-- Using the asset management system. -->
<a-gltf-model src="#tree"></a-gltf-model>

<!-- Defining the URL inline. Not recommended but more comfortable for web developers. -->
<a-gltf-model src="tree.gltf"></a-gltf-model>
</a-scene>
```

## Attribute

[gltf]: ../components/gltf-model.md

| Attribute | Component Mapping | Default Value |
|-----------|------------------------|---------------|
| src | [gltf-model][gltf].src | null |
12 changes: 10 additions & 2 deletions examples/test/model/index.html
Expand Up @@ -2,24 +2,32 @@
<html>
<head>
<meta charset="utf-8">
<title>Model</title>
<meta name="description" content="Model - A-Frame">
<title>Models (glTF, OBJ, COLLADA)</title>
<meta name="description" content="Models (glTF, OBJ, COLLADA) - A-Frame">
<script src="../../../dist/aframe-master.js"></script>
</head>
<body>
<a-scene stats>
<a-assets>
<a-asset-item id="crate-obj" src="../../assets/models/crate/crate.obj"></a-asset-item>
<a-asset-item id="crate-mtl" src="../../assets/models/crate/crate.mtl"></a-asset-item>
<a-asset-item id="brainstem" src="https://cdn.aframe.io/test-models/models/brainstem/BrainStem.gltf"></a-asset-item>
<a-asset-item id="monster" src="monster/monster.dae"></a-asset-item>
</a-assets>

<a-entity position="0 0 -12">
<a-entity collada-model="#monster" material="color: green" scale="0.25 0.25 0.25"
position="-10 0 1"></a-entity>
<a-text value="COLLADA" color="#000000" position="-2 -2 6" scale="1.5 1.5 1.5"></a-text>

<a-entity gltf-model="#brainstem" position="10 -1 5" scale="3 3 3"></a-entity>
<a-text value="glTF" color="#000000" position="9.75 -2 6" scale="1.5 1.5 1.5"></a-text>

<a-entity obj-model="obj: #crate-obj; mtl: #crate-mtl" position="5 0 5"></a-entity>
<a-entity obj-model="obj: #crate-obj; mtl: #crate-mtl" position="5 2 5"></a-entity>
<a-text value="OBJ" color="#000000" position="4.75 -2 6" scale="1.5 1.5 1.5"></a-text>

<a-sky color="#FAFAFA"></a-sky>
</a-entity>

</a-scene>
Expand Down
37 changes: 37 additions & 0 deletions src/components/gltf-model.js
@@ -0,0 +1,37 @@
var registerComponent = require('../core/component').registerComponent;
var THREE = require('../lib/three');

/**
* glTF model loader.
*/
module.exports.Component = registerComponent('gltf-model', {
schema: {type: 'model'},

init: function () {
this.model = null;
this.loader = new THREE.GLTFLoader();
},

update: function () {
var self = this;
var el = this.el;
var src = this.data;

if (!src) { return; }

this.remove();

this.loader.load(src, function gltfLoaded (gltfModel) {
self.model = gltfModel.scene;
self.system.registerModel(self.model);
el.setObject3D('mesh', self.model);
el.emit('model-loaded', {format: 'gltf', model: self.model});
});
},

remove: function () {
if (!this.model) { return; }
this.el.removeObject3D('mesh');
this.system.unregisterModel(this.model);
}
});
1 change: 1 addition & 0 deletions src/components/index.js
Expand Up @@ -3,6 +3,7 @@ require('./camera');
require('./collada-model');
require('./cursor');
require('./geometry');
require('./gltf-model');
require('./hand-controls');
require('./light');
require('./look-controls');
Expand Down
1 change: 1 addition & 0 deletions src/extras/primitives/index.js
Expand Up @@ -2,6 +2,7 @@ require('./primitives/a-camera');
require('./primitives/a-collada-model');
require('./primitives/a-cursor');
require('./primitives/a-curvedimage');
require('./primitives/a-gltf-model');
require('./primitives/a-image');
require('./primitives/a-light');
require('./primitives/a-obj-model');
Expand Down
6 changes: 2 additions & 4 deletions src/extras/primitives/primitives/a-collada-model.js
@@ -1,9 +1,7 @@
var getMeshMixin = require('../getMeshMixin');
var registerPrimitive = require('../primitives').registerPrimitive;
var utils = require('../../../utils/');

registerPrimitive('a-collada-model', utils.extendDeep({}, getMeshMixin(), {
registerPrimitive('a-collada-model', {
mappings: {
src: 'collada-model'
}
}));
});
7 changes: 7 additions & 0 deletions src/extras/primitives/primitives/a-gltf-model.js
@@ -0,0 +1,7 @@
var registerPrimitive = require('../primitives').registerPrimitive;

registerPrimitive('a-gltf-model', {
mappings: {
src: 'gltf-model'
}
});
2 changes: 2 additions & 0 deletions src/lib/three.js
Expand Up @@ -19,6 +19,7 @@ if (THREE.Cache) {
}

// TODO: Eventually include these only if they are needed by a component.
require('three/examples/js/loaders/GLTFLoader'); // THREE.GLTFLoader
require('three/examples/js/loaders/OBJLoader'); // THREE.OBJLoader
require('three/examples/js/loaders/MTLLoader'); // THREE.MTLLoader
require('three/examples/js/BlendCharacter'); // THREE.BlendCharacter
Expand All @@ -27,6 +28,7 @@ require('../../vendor/VRControls'); // THREE.VRControls
require('../../vendor/VREffect'); // THREE.VREffect

THREE.ColladaLoader.prototype.crossOrigin = 'anonymous';
THREE.GLTFLoader.prototype.crossOrigin = 'anonymous';
THREE.MTLLoader.prototype.crossOrigin = 'anonymous';
THREE.OBJLoader.prototype.crossOrigin = 'anonymous';

Expand Down
41 changes: 41 additions & 0 deletions src/systems/gltf-model.js
@@ -0,0 +1,41 @@
var registerSystem = require('../core/system').registerSystem;
var THREE = require('../lib/three');

/**
* glTF model system.
*/
module.exports.System = registerSystem('gltf-model', {
init: function () {
this.models = [];
},

/**
* Updates shaders for all glTF models in the system.
*/
tick: function () {
var sceneEl = this.sceneEl;
if (sceneEl.hasLoaded && this.models.length) {
THREE.GLTFLoader.Shaders.update(sceneEl.object3D, sceneEl.camera);
}
},

/**
* Registers a glTF asset.
* @param {object} gltf Asset containing a scene and (optional) animations and cameras.
*/
registerModel: function (gltf) {
this.models.push(gltf);
},

/**
* Unregisters a glTF asset.
* @param {object} gltf Asset containing a scene and (optional) animations and cameras.
*/
unregisterModel: function (gltf) {
var models = this.models;
var index = models.indexOf(gltf);
if (index >= 0) {
models.splice(index, 1);
}
}
});
1 change: 1 addition & 0 deletions src/systems/index.js
@@ -1,5 +1,6 @@
require('./camera');
require('./geometry');
require('./gltf-model');
require('./light');
require('./material');
require('./tracked-controls');
Expand Down
Binary file added tests/assets/box/Box.bin
Binary file not shown.

0 comments on commit 6306459

Please sign in to comment.