Animating geometries in JavaScript can be pretty slow. If you have thousands of objects's positions and try to update them at once, or even worse, if you try to update all the vertices of a geometry, your GPU will struggle to receive so much new information. The GPU is best at doing the math, not at receiving the data.
To make better use of our GPU, we can turn to the vertex shaders and store any animation data into custom Buffer Attributes at the geometry's creation. Then, the GPU takes care of the animating in the shaders without the need to take new updates.
These custom InstancedBufferAttributes are the same as the usual position, uv, normals, and attributes. Large arrays with data per vertex that you can use to calculate the animation of each vertex. Or, with the right data, animate each triangle, or even each breakable piece.
Getting started
- Intro to vertex shaders and Buffer animations
- Three.Bas Buffer Animation System
- How to explore Objects in ThreeJS
sponsor
Become a sponsor with your sponsor spot here!
Promote your product/company in this spot to hundreds of creative developers interested in learning and creating. One spot per issue!
Learn More!Triangle Image Transition
For the animation timing in this demo by Szenia, there are two buffers: the startTime, and endtime buffers. Vertices are animated as triangles by using the centroid to calculate the timing, however, each vertex adds a little bit of delay to create a little bit of stretchiness.
For the movement, the vertex shader uses a bezier curve to animate the triangles from one point to another. Bezier curves have four parameters: startPosition, endPosition, control0, and control1. So, each one of those gets its buffer attribute. Then, with the timing and the
transformed += cubicBezier(aStartPosition, aControl0, aControl1, aEndPosition, tProgress);
Breaking up text
If you don't need to squeeze every single drop of performance, doing things in JavaScript might be just enough for your use case. In this project, visualdata creates text geometry that is then broken with ThreeJS ConvexBufferGeometry. Then the resulting meshes are animated in the update loop.
Model morph
In this model morph animation, they animate they animate the triangles to morph between models. To make sure triangles sort of stick together, you need to link them in some sort of way. My go-to approach is with the triangle's centroid. All three vertices share the same centroid, so we can use that for the timing:
Getting the centroid of a triangle is summing all the vertices and then diving by 3
centroid.copy(point0)
centroid.add(point1)
centroid.add(point2)
centroid.divide(3)
Triangle transitions
Here's an old but gold example that uses the same centroid technique. This uses Three.BAS to be able to add new attributes while still being able to work with built-in materials.
Instancing geometry morph
Another approach for vertex shader animation is using textures instead of buffers like Unseen Studio's Dala project. The animation data is either encoded in a texture, or the final animation is encoded into the texture, like in the case for gpgpu simulations. This texture is sampled in the shader to animate each instance or vertex.