Fancy Drawing in WebGL with Babylon.js

Babylon.js
4 min readSep 18, 2020

--

Babylon.js is mostly widely thought of as a full game engine. However, what about creating other kinds of experiences? While thinking about this topic and trying to have fun learning something new, I took a shot at creating a simple but fancy drawing canvas with Babylon.js. The goal being to have a “Shiny Unicorn Poop” brush because… why not?

Special Thanks to Deltakosh for the drawing.

Without any further ado, have fun trying the Live Demo.

The entire code of the project is, as usual, open source and available on Github:

In this post, I will only try to focus on a handful of techniques that you might be able to reuse in creating your own experiences.

Because Size Matters

Actually, since we will only use a subset of the Babylon.js features here, the entire project has been built with our ES6 support. Tree Shaking functionalities in bundlers (Webpack, Rollup…) allow us to only import what we really need. If you want to know how to get started, @RaananW did an amazing job setting everything up for you here: https://github.com/RaananW/babylonjs-webpack-es6.

The only “trickery” I’d like to detail a bit further is how we benefit from Webpack Code Splitting so we can choose not download the Babylon.js Inspector until we are actually using it.

Basically, the inspector is a super duper tool and one of my favorite in the Babylon.js ecosystem. However, it is quite large and pulls down everything that it needs even if it may be unrelated to the current application. To simplify, we would like to have a single Build containing the inspector but not load it in the page as long as we are not using it.

The standard inspector loading code in ES6 looks like this:

And with this simple change, Webpack will take care of everything for you:

Keep that in mind as it is amazingly handy and powerful to improve your users experience :-)

I just want 2D !!!

As we only want to draw in 2D and have an easy coordinate system to rely on, what would be the easiest way to achieve this?

Fortunately, our camera system supports Orthographic Cameras, so it is easy to create a Camera that will see everything in a space fitting exactly with our screen and mouse position coordinates without any extra computation required. Also, the depth will not impact how the objects are rendered, ensuring a nice 2D feeling in your experience.

Draw Time

We are all setup to start drawing but how can we implement the drawing itself? There are plenty of possible techniques for this but for fun (and mostly learning purposes) I chose to dynamically create a mesh to represent the shape of what you draw called the PathMesh.

I will skip the gory math details and only focus on the heart of the technique. Basically on every frame, we upload the new data points to the GPU. We only upload the NEW data points so that we can speed things up and reduce the overall bandwidth. This would be easy to re-purpose for any kind of dynamically generated meshes.

Also the buffers holding the vertices are working similarly to vectors in c++ (I know I will be trolled for this ;-) but I said similarly). They would increase the allocated memory every time we reach the full length by a certain factor to prevent over allocation/GC slowness at the expense of only reserving a bit more space upfront.

Unicorn Poop !!!

I chose the easy way. I simply added extra info in my vertex data to know what the distance is (along the path) from one vertex to the start of the mesh. Then in the shader, I use a rainbow lookup to wrap around the path:

Sparkles

To make our unicorn poop shine, we are simply relying on our awesome particle system.

We simply update the emitter position to fit with the pointer on every frame and “voila”:

That’s all for today, hope you find some inspiration in this and it helps provide new perspective on how Babylon.js can be used outside of “Gaming”.

--

--

Babylon.js
Babylon.js

Written by Babylon.js

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