Developer. Creative Geek. Composer.

In this tutorial, you should have a lot of fun. You’ll learn how to create a 3D Maze using Babylon.js/WebGL based on a dynamically generated QR Code! This is based on a demo I’ve written for our big annual French conference named Techdays 2014 and more specifically for our famous Coding4Fun session. The idea was to create a maze for the one you love during the Valentine’s Day. Indeed, isn’t it cool to create a 3D procedural maze in the name for your girlfriend/wife?

Yes, this is our famous geeks’ touch in action my friend!

The name of this demo is “Le labyrinthe de l’amour”. (The love maze). I’ve kept it in French as we all know that Paris is the city of love!

Then, enter the name of your girlfriend and click “Create”. You’ll be able to move into the maze dedicated to your beloved using the arrow keys & mouse. Press the “space” key to launch a specific camera’s animation, and you’ll be able to view the QRCode. Flash it using your smartphone and you should see “[NameOfYourGirlFriend], I love you!”. Your girlfriend should be impressed. 😉 It’s much better than flowers or chocolates to my point of view!

You’ll also notice also that if you click on the “isolated cube”, it will throw them into space. I’ve setup the physics engine on them to add a dramatic moment. Stay calm! Thanks to the 30% error correction algorithm, you’ll still be able to flash QR Code most of the time. 😉

Pre-requisites

To be able to follow this tutorial, it’s better if you first read the following tutorials/articles/wiki:

Well, the code should be relatively straightforward and self-explicit. We’re creating a ground and enabling collisions & gravity on the free camera. You can then move on the ground without flying into the air or falling though the ground. We’re also creating a skybox to create our universe surrounding us as well as 2 lights with colors taken from the skybox.

You’ll see this cube and by moving the camera, you shouldn’t be able to go through thanks to the native collisions engine embedded into babylon.js:

But if you’re disabling the gravity on the freeCamera object and you’re moving the camera above the cube, you’ll see that its top doesn’t have the proper material set yet for our future QR Code recognition algorithm:

We need to have a different material for the top. For that, we’re going to use the multi-materials approach of babylon.js: Using multi-materials using this code:

Note: as you can read, I’m turning the cube using Quaternion rather directly working on rotation.x. It’s because cannon.js needs to have the information set this way. If you’re setting it the other way, cannon.js will not take into account your rotation transformations. Oh yes, and I’m doing a rotation of the cube because otherwise the specific face with the top material associated is pointing down.

Step 3: creating the 3D QRCode maze

We’re now going to call the qrcode.js library to build the QR Code based on a specific text. This library normally needs a div to inject into. We’ll give it a fake div element. Then, it builds the QR Code and draw the output into the div. I was more interested in the 2-D array built inside it. This array represents the complete QR Code by a series of rather dark or white pixels.

In conclusion, replace in your code the mCount variable declaration by this:

// It needs a HTML element to work with
var qrcode = new QRCode(document.createElement("div"), { width: 400, height: 400 });
qrcode.makeCode(nameOfYourGirlFriend + ", I love you!");
// needed to set the proper size of the playground
var mCount = qrcode._oQRCode.moduleCount;

Step 4: optimization with cloning

Currently, in our loop, we’re creating the very same object up to 500 times. A better approach is to create the geometry once and then clone it. It’s better for the memory consumption and for the performance. The CPU will send a unique geometry to the GPU. GPU will then clone this geometry as needed without asking more information from the CPU. It could be an important point especially on mobile devices. It could also have an impact on the rendering performance. In my case, my base geometry (a cube) is far too simple to have an immediate performance boost just thanks to cloning. But this doesn’t mean you shouldn’t do it every time you will duplicate the very same mesh.

More interestingly, during a game, it’s also much faster to instantiate a clone (of an enemy for instance) rather than creating it again from scratch. If you’re spawning a new enemy during your game by creating it without the cloning mechanism, you’ll probably have some fps drops. In conclusion, this is really a best practice to use cloning if you need to duplicate several times the very same mesh.

Step 5: performance optimization by merging meshes

Maybe you’ll notice than even if we don’t have a lot of triangles currently being displayed, the performance are not stellar. This is because we have a lot of small objects and thus small operations associated to them. We’re then spending too much time between the CPU and the GPU. The CPU is doing a lot of roundtrips with the GPU to send the orders for the 500+ potential cubes to be displayed. It’s much more efficient to send a big mesh from the CPU to the GPU and then ask for specific operations on this big mesh (rotation, scaling, lights, etc.).

The idea is then to merge all the generated cubes into a big mesh. It will really enhance the global rendering performance.

Let’s launch the F12 UI Responsiveness tool of IE11 to check the current results before merging meshes:

The average fps is around 30 fps. And the CPU usage reaches 100% which tends to prove that the CPU is doing more work than expected.

Insert the merging function into your code by copy/pasting it from our wiki: How to merge meshes.

You can verify the performance boost in your browser/machine with the previous version in step 3.

Step 6: animating the camera

To be able to view the QR Code from the space and flash it with your smartphone, we need to change the current camera position and rotation to a specific place. Rather than jumping directly to this specific position, let’s animate the camera from its current place in the maze to the best position in the space for flashing.

Now, launch your code and press the “space” bar, you should obtain this view:

Using my Windows Phone native QR Code app, it works!

Step 7: enabling physics on isolated cubes

In this last part of the tutorial, we’re going to see how to enable some physics on isolated cubes (cubes without direct neighbors on their left/right/up/down direction). Then, we’ll see how to select a mesh by clicking it and apply some impulse force to throw these isolated cubes in the space.

First, you need to enable physics on the scene:

scene.enablePhysics(new BABYLON.Vector3(0, 0, 0));

In my case, I’m setting a zero gravity as we’re supposed to be in space. Then, you need to define the various impostor for the ground and the isolated boxes.