Trail effect with Babylon.js

Babylon.js
3 min readFeb 15, 2021

--

In my last demo, I exploited a technique to do light trails behind each ship. As I got few questions about it, I believed it deserved its own blog post. The trick itself is very simple and can be derived for various effects like smoke trails, weapon trails, missile smoke…

Let’s dive in!

The playground for this experiment is accessible here!

How does it work ?

Trail mesh is a simple ribbon that is deformed by a vertex shader to align it toward the camera eye. Also, positions are sorted in a float texture. Each frame, a new position is appended and the oldest position is discarded. The mesh needs UV with U ranging [0..1] on the width and V ranging [0..1] on its length. UV is needed to retrieve the position in the texture. That’s basically it. Now with more details!

CPU side

At init a float texture is created. The width is 1 texel while the height is 256 in this playground example. The more texels the more precise. Note that for fast changing direction, intermediate (more points appended per frame) might be necessary.

Create a tesselate ground mesh and an array to hold the positions.

Then, for each frame, a new position is pushed in the array, previous position is removed (using typed array shift function). The texture data is updated each frame, ready for the GPU to render.

Create or update the float texture the positions array.

GPU side

This is where the magic happens. For each vertex, the corresponding world position is sampled in the texture. As the V component of the UV is ranging from 0 to 1, no special operation is needed here.

But as you can see in NME graph, there is another texture sampling. For that sampling, the V component is offset a little (-0.001) in order to get a position a little behind in the curve described in the texture. The position difference of the 2 sample is the direction of the curve at that point. This derivative vector is then normalized.

The output of Normalize is the normalized world direction of the trail.

With the curve direction in world coordinates and the eye position, it then become possible to compute the bitangent with the direction from eye to the position. The bitangent is the perpendicular to the direction and the eye vector. As a consequence, this vector is perpendicular to the view. We now have a solution to orient the curve so it always faces the camera. Just like a billboard but per vertex.

The cross product of (world position — camera.position) and previously computed direction vector gives the perpendicular right vector.

For the color, a sine is computed on the width, depending only on U so it’s bright in the middle and dark on the side. And another sine is used on the length of the mesh so it’s bright at the start and dark at the end.

A sine along width and another along length. Multiplied together and you get the alpha for the texel.

The complete NME graph for this effect is accessible here : Babylon.js Node Material Editor

PG demo + PG infos

Time for a demo!

Relaxing trails around a PBR sphere

https://playground.babylonjs.com/#PX1VV2#6

This PG follows what’s described before. With 3 trails and a parametric function for the position. The position is function of time and nothing else. At init, the trail texture data is filled with positions computed back in time instead of random or (0,0,0). A light and a mesh are attached and their position set at the same point as the trail end.

https://twitter.com/skaven_

--

--

Babylon.js
Babylon.js

Written by Babylon.js

Babylon.js: Powerful, Beautiful, Simple, Open — Web-Based 3D At Its Best. https://www.babylonjs.com/

No responses yet