4.0 KiB
| id | title |
|---|---|
| animation | Animation |
In the Three.js custom renderer guide we rendered a static cube using Three.js. What if we want to rotate or move things around inside MapillaryJS? Well, we can do that too, we just have to add a few lines of code to our cube renderer.
:::info You will learn
- How to animate objects in MapillaryJS
- How to trigger rerender to ensure that the animation continues
:::
Creating the Animation Renderer
We will add functionality to the cube renderer from the Three.js Renderer guide so make sure that you have to study that before jumping into this example. Here we will just go through the new functionality that we will add.
Specifying the Rotation Speed
We want to be able to change the rotation speed of our cube, so we add a rotationSpeed property.
const cube = {
// ...
rotationSpeed: 1,
};
Keeping the Time
We will add a Three.js Clock member to our renderer. The clock will be readonly so we assign it in the constructor.
class RotatingCubeRenderer {
constructor(cube) {
// ...
this.clock = new Clock();
}
}
Storing a Viewer Reference
We will make use of the viewer in the render method so we store a reference to it through the viewer parameter of onAdd.
class RotatingCubeRenderer {
// ...
onAdd(viewer, reference, context) {
this.viewer = viewer;
// ...
}
}
Trigger Rerender
Our onReference and onRemove implementations remain the same, so let's move on to the render method. Here we make use of the clock to rotate the cube mesh according to our rotation speed and the elapsed time between each animation frame.
Finally, we call the Viewer.triggerRerender method to force the Viewer to rerender and call our render implementation on every animation frame. We need to trigger rerender on every animation frame because we want our cube to rotate indefinitely.
class RotatingCubeRenderer {
// ...
render(context, viewMatrix, projectionMatrix) {
const {camera, clock, scene, cube, renderer, viewer} = this;
const delta = clock.getDelta();
const {rotationSpeed} = cube;
cube.mesh.rotateZ(rotationSpeed * delta);
cube.mesh.rotateY(0.7 * rotationSpeed * delta);
// ...
viewer.triggerRerender();
}
}
:::note
Rerendering on every frame has a performance impact. Whenever it is possible, for example if your animation has completed, it is advices to avoid triggering rerender.
:::
Adding the Renderer
Now that we have implemented our rotating cube renderer, we just need to add it to the Viewer through the Viewer.addCustomRenderer method.
:::tip
Try changing the cube's rotation speed.
:::
function render(props) {
let viewer;
function init(opts) {
const {accessToken, container} = opts;
const imageId = '3748064795322267';
const options = {
accessToken,
component: {cover: false},
container,
};
viewer = new Viewer(options);
const cube = {
geoPosition: {
alt: 1,
lat: -25.28268614514251,
lng: -57.630922858385,
},
mesh: animation.makeCubeMesh(),
rotationSpeed: 1,
};
const cubeRenderer = new animation.RotatingCubeRenderer(cube);
viewer.addCustomRenderer(cubeRenderer);
viewer.moveTo(imageId).catch(mapillaryErrorHandler);
}
function dispose() {
if (viewer) {
viewer.remove();
}
}
return (
<ViewerComponent init={init} dispose={dispose} style={{height: '400px'}} />
);
}
Recap
- To animate objects in MapillaryJS, use the elapsed time when applying object transforms
- Trigger rerender to ensure that the animation continues
- Avoid triggering rerender if your animation has completed to optimize resource usage
:::info
You can view the complete code in the Animation example.
:::