The geometry can be easily generated at runtime from an image:
// vanilla example
const geometry = new ClippedSpriteGeometry(
image, // an already loaded HTMLImageElement or a ThreeJS texture
8, // the number of desired vertices. 4/6/8 seem to give good results most of the time.
0 // alphaThreshold, 0 means only fully transparent pixels will be discarded
)
// r3f example
const myTexture = useTexture('myImage.png') // a r3f texture
<instancedMesh>
<clippedSpriteGeometry args={[
myTexture,
8,
0
]} />
<meshBasicMaterial />
</instancedMesh>
const [geometry, dataTexture, api] = createFlipbookGeometry(
image, // an already loaded HTMLImageElement or a ThreeJS texture
vertices, // the number of desired vertices. 4/6/8 seem to give good results most of the time.
horizontalSlices, // the number of horizontal slices in the flipbook
verticalSlices, // the number of vertical slices in the flipbook
settings // optional settings, see below
)
The flipbook version is a bit more complex.
Since we are dealing with a larger number of sprites, we need to generate valid positions for each step in the flipbook.
The data is then fed to a data texture of size [number of vertices, number of flipbook steps]
and can be used in the vertex shader using gl_vertexID
to draw the sprites.
Alternatively, the vertex positions can be generated as an array of vertices and consumed as a vertex attribute.
Note that the generated geometry only holds the correct amount of vertices and the necessary index.
You can use the testing tool at https://gsim.one/diet-sprite/ to test your configuration.
Drawing billboards, clouds, particles is a ROP bound operation [1], for which reducing the number of pixels being drawn is a key goal. A typical texture has significant areas where alpha is 0, leading to wasteful operations that don't contribute to the final image. This tool generates a geometry that fits tightly around the non-transparent parts of the image.
The tradeoff is having to render a few more triangles, but the downside would only be relevant for very small particles and is expected to be used with instanced meshes.
This method is based on Graphics Gems for Games - Findings from Avalanche Studios. Unreal Engine has a similar tool included from 4.11
The algorithm goes something like this: