Experimenting with Emscripten

Let’s start the year with a bang!

No, I was not planning on adding support for Emscripten so soon, but I woke up on Saturday morning with that idea in my mind. I was assuming that the process to take a Crimild demo and make it run on a web browser would take me several weekends, but it turned out to be a lot easier.

So, here’s a–

Wait. I see it in your face. You don’t believe me, right? Take a look at THIS WORKING DEMO then.

Screen Shot 2018-01-07 at 1.36.25 PM

 

Keep in mind that it might take a while to load. Also, try rotating the model by dragging the left mouse button. You can use the WASD keys too, but you need to click on the frame first in order to give it focus.

The source code for this demo is already available at Github. It’s using a branch of the latest Crimild version just to make sure I’m not breaking anything else. I intent to merge this code with the main one once I’m confident enough.

Now, where were we? Oh yes: “So, here’s a postmortem”

First things first

The first step was the obvious one: install Emscripten in my computer. The official website has a todo list that is very clear and easy to follow. And I already had NodeJS on my computer so the whole process was quite simple.

After the installation, I made sure the most basic examples, like the Hello World one, were all working. And with my environment correctly configured, I moved on to write the first demo

Dumping a scene

I wanted to start with something simple. Create a scene (a similar one as in the Triangle example), and dump it to the standard output. That’s it. No simulation, no rendering. Just to make sure Crimild’s core module would build and work correctly.

In order to setup the project, I used the official toolchain for CMake also provided by the same Emscripten installation. That was the key to make the process a lot simpler.

The project’s CMakeLists.txt only needed to specify the location of Crimild sources, making sure that only the core classes would be included in the final Makefile. I used the same macros for building apps as in the example projects.

Then, compiled the whole thing and ran it using node.

There was no need to change anything in the code.

At all.

Moving on.

The GLFW affair

I wanted to render something on the screen next, but it wouldn’t be that easy this time.

First, I had to enable the modules that I needed from Crimild. I knew that Emscripten has built-in support for OpenGL ES and GLFW, that was all I needed.

I had to make some changes in Crimild’s CMake files in order to detect wether or not we’re building for Emscripting. That way we’ll use one version of the libraries or the other. For example, although Crimild has a reference to the GLFW project sources, we need to use the one provided by Emscripten in the end. Therefore, I had to make sure I was using the appropriated ones at linking time (which was not the case for the first couple of hours until I figure it out).

Several “undefined symbols” later, I managed to organize Crimild’s CMake files in a way that can be reused for any platform.

I also had to add some extra flags in the code, specially for handling cases like where to locate the OpenGL header files. In addition, I implemented the required methods to declare the main loop function that will be called each frame.

At that point, I started running the demo using a simple index.html page that only contained the canvas and the loading code for the demo.

S**t got real

With a triangle spinning on the screen, the next step was to actually load an animated model.

I didn’t even try to build the Import module, because I knew that Assimp may became a problem, so I took the easy way out: loading a model already saved as a binary stream.

It took me a while to figure out how to work with Emscripten internal file system, and the fact that, as with any other web project, I eventually had to ran an instance of an HTTP server (the SimpleHTTPServer from python, if you’re curious) in order to publish not only the code, but also de data files.

The result was the working demo you have seen above.

Not only was the character walking on the screen, but all the keyboard and mouse interactions worked as well. I wasn’t expecting that.

Closing comments

Like I said, integrating Emscripten was a lot easier than I originally though. And it works like a charm!

At the time of this writing, I still need to enable other modules, like scripting, but I’m pretty confident that it will be just as easy (specially because Lua is already written in ANSI C/C++). Audio support is still to be added as well.

Based on the results so far, I’m considering making a web version of The P.U.R.G.E Protocol as soon as I have the chance.

Who knows. Maybe my next project would be a web based one 😉

See you next time!

Hernan

 

 

 

Advertisements

Sorting particles the right way… I guess…

Close your eyes.

Actually, keep them opened because you have to keep reading.

Imagine a train moving at a constant speed. You’re traveling inside the train, in a seat near a window. There’s a computer resting on a table right in front of you. On its screen, a random frame from a secret project is being rendered looking like this:

Screen Shot 2017-09-09 at 12.10.35 PM.png

The Problem

The above image is the result of using a mixture of offscreen render targets and particle systems to generate a lot of soldiers in real-time, in a similar fashion as other impostor techniques out there. In this case, each particle represents a group of soldiers (in order to avoid clones as much as possible) and they are walking from the left to the right of the screen. Don’t pay attention to the bearded guy at the front.

Did you noticed how the “density” of the soldiers seems to increase after some point at around the middle of the screen? That’s the symptom for the problem. Particles are generated using a uniform distribution random algorithm, and therefore there’s no reason for the empty spaces between them.

If we look at the debug version of the same frame, we would see something like this:

Screen Shot 2017-09-10 at 5.18.59 PM.png

As shown in the image above, the particles are indeed uniformly distributed. Then, where are the soldiers?

Here’s another clue: if I turn the camera just a little bit to the left, I get the following result:

Screen Shot 2017-09-10 at 5.22.22 PM.png

This seems to indicated that, although the soldier-particles do exist, they are just not being rendered in the right way. Actually, I’ve dealt with this kind of problems before and they always seem to be related with object sorting and transparency.

Distance to the Camera

Before any particle is rendered on the screen, they must be sorted in the right order for the transparency to work. OK, so particles are not being sorted and we just need to implement that, right? Alas, after checking the code, it turns out that the particle system does perform sorting over live particles, ordering them from back to front based on the camera position. And yet the problem remains.

It turns out I was making the wrong assumption here. Particles are being reordered, true, but the algorithm handles them as points instead of billboards (quads that always face the camera).

Let’s look at the following diagram:

img_3586-1

The above diagram is quite self explanatory, right? No? OK, let me try and explain it then.

In the first case, particles are sorted using the camera position (just as in the current implementation). There are tree distances to the camera (d1, d2, d3). If we use the camera position as reference, the order in which the particles will be rendered will end up being 3, 2, 1 (back-to-front, remember). But that result is incorrect.

Particle 2 (the one in the middle) is indeed closer than particle 3 to the camera position, but it should be rendered before particle 3 in order to prevent artifacts like before.

Near-plane distance

The second scenario is the right one. We have to sort particles based on their distance to the near plane of the camera, not its position. That way, particles are correctly rendered as 2, 3, 1 (again, back-to-front).

This change produces the correct result:

Screen Shot 2017-09-10 at 5.32.11 PM.png

All soldiers are successfully rendered and our army is completed.

Final comments

We should keep in mind that, while this method fixes this particular sorting problem, it may not work when particles are rotated or they intersect each other. There are other approaches that attempt to solve those cases and, depending on what we’re targeting for, those might end up being too expensive to implement.

That’s it for today. Time to get back to my cave now.

See you later

PS: If you’re still wondering what that thing about the train was, well, I guess I’ve been watching too much Genius lately…

 

Shadow mapping improvements (I)

Just a brief update to build up some expectations for the next release (whenever that happens).

I’ve been working on improving the shadow mapping technique support in Crimild in order to make it more reliable in production environments. The current implementation had a lot of errors and artifacts and it’s not really usable in big open spaces due to incorrect light frustum calculations.

Here’s a quick look at the new Shadows demo:

 

This slideshow requires JavaScript.

Only directional and spot lights can cast shadows at the moment, but I’m planning on adding support for point lights shortly. I’m also planning on adding support for cascade shadow maps in a later release.

That’s it. See you later 🙂