Simulating and rendering water from liquidfun.js, a box2d port
Jeffkillian.com initially started as a Geocities website when I was in 6th grade. Over the years, it has slowly evolved into a place where I can practice and become familiar with web development as it progresses. I started out coding with Microsoft Frontpage, then moved to Dreamweaver. Initially, there was very little coding, and it was all WYSIWYG. However, as I learned more, I could make it more interactive.


I incorporate drawings and blog posts to keep those that are interested updated. Through the evolution of the website, I was forced to learn HTML, PHP, CSS, XML, jQuery, javascript, and the handling of MySQL Databases. I've put online some code samples.
Simulating and rendering water from liquidfun.js, a box2d port
After some significant development in dangeraffe there was still one thing that really bugged me that I wasn't able to solve. Water just didn't feel right.

Rather than being a continuous liquid, it was just a series of differently sized balls. While the balls did have physics that mimicked liquid flow/properties, I couldn't stand how it looked. I had no idea even where to begin, but after a bit of googling, I was able to find a helpful page that explained the term I was looking for: Rendering.

In essence, I had the locations of all of the balls given to me by the liquidfun engine. What I wanted to do was find a way to render(display) those balls, without displaying the actual balls that were there. Instead I wanted to display something that moved and flowed like water, and looked like one coherent unit when all together.
I ended up on a blog post about Liquid Simulation in WebGL by Chris Wellons, which looked like it was right up my alley. However, it mentioned using something called WebGL, which I had never heard of at the time. From what I coudl tell, it was a way to take some stress off of the CPU when rendering, and instead use the GPU. Again, this was a foreign language to me, so I ignored it. Chris had made a bottle like simulation , and broadly detailed the steps needed to render water:
  1. Do a physics simulation of balls in a container
  2. Render the simulation onto a raster
  3. Blur the image
  4. Apply a threshold
Steps 3 and 4 were the crucial part. They were the actual solution to the question "how do you turn the balls in liquidfun/box2d into a liquid-like substance?"

While I won't get into too much detail about the actual mechanics behind rendering, (you can find more here), you must first blur the balls, and then you apply a threshold. Blurring the balls makes them appear more as one continous body. Applying the threshold allows a clear cut outline of any given water bodies. If the image is above the threshold, we paint it black (or in the case of water, blue). If it is not above the threshold, we paint it white.
While testing, you can alter the threshold to see what it would be best as. Too small, and nothign shows up because everythign is too blurred. Too big, and the threshold does not have any affect, and you get a blurred image.

Blurring and Thresholding
Now that I knew I had to use a blur and a threshold, (and because I had never worked with WebGL), my first thought was to look for a javascript library that would do this for me. My thought was, because my image is on a canvas, I can simulate all of the water balls on a seprate canvas, apply the blurring and thresholding, and then draw the image on that canvas. I looked at a bunch of different libraries, the most helpful were The problem with the libraries above is that they are all javascript based. glfx.js is actually a webgl framework, but I didn't even know enough to know that this is what I should be using, and that it was different. While I was able to get a tiny implementation running via stackblur, it required copying the red,green, and blue values for every pixel on the canvas. I had to do this every frame (the game runs at around 60 fps), and then redraw this on a new canvas. This was much too process intensive, and I was getting at maximum 5 or 6 frames per second. It was at this point that I decided to take a break, and admit defeat....or so I thought.

I developed some new features, but still couldn't get the water rendering out of my head. About three weeks later I decided to revisit the issue, and try from a fresh start. My new implementatation started as an actual copy of the bottle simulation mentioned before. I didn't know WebGL, and wasn't about to learn it. Water was important, but my time could better be used implementing other features. Therefore, I copied the entire bottle simulation repository, and pasted it into my directory. I then worked backwards, figuring out the coordinates relative to my coordinates, deleting the spikes on the sides, and so on. Eventually, I had a bottle simulation that was running over dangeraffe. The canvases were overlaid, with the bottle simulation being above dangeraffe.

I was able to transfer my points via an array to the bottle simulation, but the simulation kept crashing. This was a result of it having a memory leak from using an outdated version of box2d. I spent a while porting the included box2d into liquidfun.js (aka B.Vec2>b2Vec2, B.World>b2World...). I was relying on this fixing the memory leak, and it did.

The last step was to map the water points that I currently had in dangeraffe into points that were appropriate for the bottle simulation. This was the part that took the longest, as it turns out the y axes are inverted and the bottle simulation goes from -1 to 1 on both axes. Once I had a function that could map my points to the bottle canvas, it was just a matter of calling the render function from my source dangeraffe code, and we ended up with beautiful flowing water. It's not the prettiest implementation, but I'm not exactly going for coding points. Dangeraffe is for me, as much of a coding learning tool as it is a game, so the fact that the code is not pristine for the rendering is just fine by me :).

Write a comment...
Want more? Check the blog archives
Untitled Document