Using with three.js
Note: This documentation is for the old 0.4.0 version of A-Frame. Check out the documentation for the current 1.6.0 version
Being a framework based on three.js, A-Frame provides full access to the three.js API. We’ll go over how to access the underlying three.js scene, objects, and API that lay underneath A-Frame.
Relationship Between A-Frame and three.js Scene Graphs
- A-Frame’s
<a-scene>
maps one-to-one with a three.js scene. - A-Frame’s
<a-entity>
maps to one or more three.js objects. - three.js’s objects have a reference to their A-Frame entity via
.el
, which is set by A-Frame.
Parent-Child Relationships
When A-Frame entities are nested in parent-child relationships, so are their three.js objects. For example, take this A-Frame scene:
<a-scene> |
The three.js scene graph will correspond and look like:
THREE.Scene |
Accessing the three.js API
three.js is available as a global object on the window:
console.log(THREE); |
Working With three.js Objects
A-Frame is an abstraction on top of three.js, but we still operate with three.js underneath. A-Frame’s elements have doors that lead to three.js’s scene graph.
Accessing the three.js Scene
The three.js scene is accessible from the <a-scene>
element as .object3D
:
document.querySelector('a-scene').object3D; // THREE.Scene |
And every A-Frame entity also has a reference to <a-scene>
via .sceneEl
:
document.querySelector('a-entity').sceneEl.object3D; // THREE.Scene |
From a component, we access the scene through its entity
(i.e., this.el
):
AFRAME.registerComponent('foo', { |
Accessing an Entity’s three.js Objects
Every A-Frame entity (e.g., <a-entity>
) has its own
THREE.Object3D
, more specifically a THREE.Group
that
contains different types of Object3D
s. The root THREE.Group
of an entity is
accessed via .object3D
:
document.querySelector('a-entity').object3D; // THREE.Group |
Entities can be composed of multiple types of Object3D
s. For example,
an entity can be both a THREE.Mesh
and a THREE.Light
by having both
a geometry component and light component:
<a-entity geometry light></a-entity> |
Components add the mesh and light under the entity’s root THREE.Group
.
References to the mesh and light are stored as different types of three.js
objects in the entity’s .object3DMap
.
console.log(entityEl.object3DMap); |
But we can access them through the entity’s .getObject3D(name)
method:
entityEl.getObject3D('mesh'); // THREE.Mesh |
Now let’s see how these three.js objects were set in the first place.
Setting an Object3D
on an Entity
Setting an Object3D
on an entity adds the Object3D
to the entity’s Group
,
which makes the newly set Object3D
part of the three.js scene. We set the
Object3D
with the entity’s .setObject3D(name)
method where the name
denotes the Object3D
s purpose.
For example, to set a point light from within a component:
AFRAME.registerComponent('pointlight', { |
We set the light with the name light
. To later access it, we can use the
entity’s .getObject3D(name)
method as described before:
entityEl.getObject3D('light'); |
And when we set a three.js object on an A-Frame entity, A-Frame will set a
reference to the A-Frame entity from the three.js object via .el
:
entityEl.getObject3D('light').el; // entityEl |
There’s also a .getOrCreateObject3D(name, constructor)
method for creating
and setting an Object3D
if one has not been set with the name. This is
commonly used in the case of THREE.Mesh
when both the geometry and material
components need to get or create a mesh. Whichever component gets initialized
first creates the mesh, then the other component gets the mesh.
Removing an Object3D
From an Entity
To remove an Object3D
from an entity, and consequently the three.js scene, we
can use the entity’s .removeObject3D(name)
method. Going back to our example
with the point light, we remove the light when the component is detached:
AFRAME.registerComponent('pointlight', { |