A brief introduction
When creating WebVR experiences, developers usually face a common problem: it’s hard to find assets other than just basic primitives. There are several 3D packages to generate custom objects and scenes that use custom file formats, and although they give you the option to export to a common file format like Collada or OBJ, each exporter saves the information in a slightly different way. Because of these differences, when we try to import these files into the 3D engine we are using, we often find that the result we see on the screen is quite different from what we created initially.
The Khronos Group created the glTF 3D file format to have an open, application-agnostic, and well-defined structure that can be imported and exported consistently. The resulting file is smaller than most of the available alternatives; it’s also optimized for real-time applications to be fast to read since we don’t need to consolidate the data. Once we’ve read the buffers, we can push them directly to the GPU. The main features that glTF provides and a 3D file format comparison can be found in this article by Juan Linietsky.
A few months ago feiss wrote an introduction to the glTF workflow he used to create the assets for our A-Saturday-Night demo. Many things have improved since then. The glTF Blender exporter is already stable and has glTF 2.0 support. The same goes for three.js and A-Frame: both have much better support for 2.0. Now, most of the pain he experienced by converting from Blender to Collada and then to glTF has gone, and we can export directly to glTF from Blender.
glTF is here to stay, and its support has grown widely in the last few months, being available in most of the 3D web engines and applications out there, like three.js, babylonjs, cesium, sketchfab, and blocks. The following video from the first glTF BOF (held at [Siggraph] this year) illustrates how the community has embraced the format:
# glTF Exporter on the web
One of the most requested features for A-Painter has been the ability to export to some standard format so people can reuse the drawing as an asset or placeholder in 3D content creation software (3ds Max, Maya, etc.) or engines like Unity or Unreal.
I started playing with the idea of exporting to OBJ, but a lot of changes were required on the original three.js exporter because of the lack of full triangle_strip
support, so I left it on standby.
#A-painter triangleStrip lines exporter to OBJ, #wip :) /cc @utopiah @feiss #aframevr pic.twitter.com/skxbcJtoXy
— Fernando Serrano (@fernandojsg) January 16, 2017
After seeing all the industry support and adoption of glTF at Siggraph 2017 I decided to give it a second try.
The work was much easier than expected, thanks to the nice three.js/A-Frame loaders that Don McCurdy and Takahiro have been driving. I thought it would be great to export content created directly on the web to glTF, and it would serve as a great excuse to go deep on the spec and understand it better.
glTF Exporter in three.js
Thanks to the great glTF spec documentation and examples, I got a glTF exporter working pretty fast.
The first version of the exporter has already landed in r87, is still in an early stage, and is under development. There’s an open issue if you want to get involved and follow the conversations about the missing features: #11951.
API
The API follows the same structure as the existing exporters available in three.js:
- Create an instance of
THREE.GLTFExporter
. - Call
parse
with the objects or scene that you want to export. - Get the result in a callback and use it as you wish.
var gltfExporter = new THREE.GLTFExporter();
gltfExporter.parse( input, function( result ) {
var output = JSON.stringify( result, null, 2 );
console.log( output );
downloadJSON( output, 'scene.gltf' );
}, options );
More detailed and updated information for the API can be found in the three.js docs.
Together with the exporter, I created a simple example in three.js, trying to combine the different types of primitives, helpers, rendering modes, and materials and exposing all the options the exporter has so we could use it as a testing scene throughout the development.
Integration in three.js editor
The integration with the three.js editor was pretty straightforward, and I think it’s one of the most useful features, since the editor supports importing plenty of 3D formats, it can be used as an advanced converter from these formats to glTF, allowing the user to delete unneeded data, tweak parameters, and modify materials, etc., before exporting.
# glTF Exporter on A-Frame > *Please note that since three.js v87 is required to use the GLTFExporter, only the master branch of A-Frame is currently supported, and the first stable, compatible version will be 0.7.0, to be released later this month.*
Integration with A-Frame inspector
After the successful integration with the three.js editor, the next step was to integrate the same functionality into the A-Frame inspector. I’ve added two options to export the content to GLTF:
- Clicking on the export icon on the scenegraph will export the whole scene to glTF.
- Clicking on the entity’s attributes panel will export the selected entity to glTF.
Exporter component in A-Frame
Last but not least, I’ve created an A-Frame component so users can export scenes and entities programmatically.
The API is quite simple, just call the export
function from the gltf-exporter
system:
sceneEl.systems['gltf-exporter'].export(input, options);
The function accepts several different input
values: none (export the whole scene), one entity, an array of entities, or a NodeList
(e.g., the result from a querySelectorAll
).
The options
accepted are the same as the original three.js function.
A-Painter exporter
The whole story wouldn’t be complete if the initial issue that led me to glTF wasn’t satisfied :). After all the previous work described above, it was trivial to add support to export to glTF in A-Painter.
- Include the
aframe-gltf-exporter-component
script:
<script src="https://unpkg.com/aframe-gltf-exporter-component/dist/aframe-gltf-exporter-component.min.js"></script>
- Attach the component to a-scene:
<a-scene gltf-exporter/>
- And finally register a shortcut (
g
) to save the current drawing to glTF:
if (event.keyCode === 71) {
// Export to GTF (g)
var drawing = document.querySelector('.a-drawing');
self.sceneEl.systems['gltf-exporter'].export(drawing);
}
# Extra: Exporter bookmarklet While developing the exporter, I found it very useful to [create a bookmarklet](https://en.wikipedia.org/wiki/Bookmarklet) to inject the exporter code on every A-Frame or three.js page. This way, I could just export the whole scene by clicking on it. If `A-FRAME` is defined, it will export `AFRAME.scenes[0]` as the default loaded scene. If not, it will try to look for the global variable `scene`, which is the most commonly used in three.js examples. It is not bulletproof, so you may need to make some changes if it doesn’t work on your app, probably by looking for something other than `scene`.
To use it, you should create a new bookmark in your browser and paste the following code in the URL input box:
What’s next?
At Mozilla, we are committed to helping improve the glTF specification and its ecosystem. glTF will keep evolving, and many interesting features are being proposed in the roadmap discussion. If you have any suggestions, don't hesitate to comment there, since all proposals are being discussed and taken into account.
As I stated before, the glTF exporter is still in an early stage, but it’s being actively developed, so please feel free to jump into the discussion to prioritize new features.
Finally, wouldn't it be great to see more content creation tools on the web with glTF support so you don't have to depend on a desktop application to generate your assets?