Before diving into the API details of Angular Three, let’s create a simple scene together to get a feel for what it’s like to use Angular Three.
Create the SceneGraph component
This component will be the root of our scene graph.
CUSTOM_ELEMENTS_SCHEMA is required to use Angular Three components.
selector is left empty because we’re not rendering SceneGraph as a regular Angular component.
Set up the Canvas
The SceneGraph component will be rendered by the NgtCanvas component.
NgtCanvas uses the sceneGraph input to render the SceneGraph component with the Custom Renderer as well as sets up the following THREE.js building blocks:
A WebGLRenderer with anti-aliasing enabled and transparent background.
A default PerspectiveCamera with a default position of [x:0, y:0, z:5].
A default Scene
A render loop that renders the scene on every frame
A window:resize event listener that automatically updates the Renderer and Camera when the viewport is resized
Set the dimensions of the canvas
We’ll set up some basic styles in styles.css
Next, let’s set some styles for :host in src/app/app.component.ts
Extending Angular Three Catalogue
As a custom renderer, Angular Three maintains a single catalogue of entities to render. By default, the catalogue is empty. We can extend the catalogue by calling the extend function and pass in a Record of entities. Angular Three then maps the catalogue to Custom Elements tags with the following naming convention:
For example:
For the purpose of this guide, we’ll extend THREE.js namespace so we do not have to go back and forth to extend more entities as we go.
Render a THREE.js Entity
Now that we have extended the THREE.js namespace, we can render a THREE.js entity. Let’s render a cube with a Mesh and BoxGeometry from THREE.js.
And here’s the result:
Animation
The best way to animate a THREE.js entity is to participate in the animation loop with injectBeforeRender. Let’s animate the cube by rotating it on the X and Y axes.
Make a Component
Using Angular means we can make components out of our template. Let’s do that for our cube
Everything is the same as before, except we now have a Cube component that
can have its own state and logic.
We will add 2 states hovered and clicked to the cube component:
When the cube is hovered, we’ll change its color
When the cube is clicked, we’ll change its scale
Our cube is now interactive!
Render another Cube
Just like any other Angular component, we can render another cube by adding another <app-cube /> tag to the template.
However, we need to render the cube in different positions so we can see them both on the scene.
Let’s do that by adding a position input to the Cube component
position input is a NgtVector3 which is an expanded version of THREE.Vector3. It can accept:
A THREE.Vector3 instance
A tuple of [x, y, z]
A scalar value that will be used for all axes
and now we have 2 cubes that have their own states, and react to events independently.
Lighting
Let’s add some lights to our scene to make the cubes look more dynamic as they look bland at the moment.
Next, we will want to change the Material of the cube to MeshStandardMaterial so that it can be lit by the lights.
Our cubes look better now, with dimensionality, showing that they are 3D objects.
Bonus: Take control of the camera
Who hasn’t tried to grab the scene and move it around? Let’s take control of the camera and make it move around with OrbitControls.
three-stdlib provides a better API to work with THREE.js extra modules like OrbitControls.
If we were to use OrbitControls in a vanilla THREE.js application, we would need to
instantiate it with the camera and WebGLRenderer#domElement.
With Angular Three, we use NgtArgs structural directive to pass Constructor Arguments to the underlying element.
To access the camera and glDomElement, we use injectStore to access the state of the canvas.
And that concludes our guide. We have learned how to create a basic scene, add some lights, and make our cubes interactive.
We also learned how to use NgtArgs to pass arguments to the underlying THREE.js elements. Finally, we learned how to
use injectStore to access the state of the canvas.
What’s next?
Now that we have a basic understanding of how to create a scene, we can start building more complex scenes.