This page best viewed with a quad-core CPU

gwtbox2d demo screenshot

[Update: this demo has evolved quite a bit and now has some actual interactivity and a few more options. See the updated version here.]

I wanted to post the simple demo I mentioned in the last entry, compiled against the latest version of the gwtBox2d library. There are actually two versions, one with the physics simulated in the main loop and one with it done in a Worker script.

A couple of notes:

The Worker version runs well in Chrome and Windows Safari, poorly in Firefox, and not at all in IE (no Workers). See my last post for details.

The main-loop version is operable in Internet Explorer 8 but there are a few too many shapes for the JScript engine to handle quickly. I’m also using the GWT incubator version of gwt-canvas which is choking while translating some command to VML, so nothing is displaying in IE8. gwt-canvas hasn’t been updated in a while; I really need to switch to a more up-to-date implementation (though I’m really tempted just to write a quick GWT wrapper for excanvas. Why reimplement when there’s already a community knee-deep in VML and Silverlight interoperability?).

The timer for the Worker version is fairly simple in this example, set to try to update 30 times every second. When a simulation step is late (which can also cause a subsequent step to be skipped if one is already enqueued), the simulated world slows because the length of a simulated time step is fixed while the time that actually passes is not. Unfortunately, unlike a typical interface animation, there are limits to how variable the time-step length can be since the simulation can quickly become unstable (see below). I’m not sure if the Worker script’s process (or thread? not sure about the Firefox implementation) is set to a lower priority, but there are occasional but noticeable hiccups. Because of the lack of concurrency controls, however, we will probably only get a reliable multi-threaded game engine out of Javascript when computer speeds have increased to the point that this code is laughably simple. For most applications, though, the status quo is fine.

That said, I’m kind of tempted just to wait until WebGL is wide-spread and just jam all the processing into GLSL. That might have been a ludicrous suggestion only a few years (months?) ago, but with WebGLArrays, why not? Most of my frustration here is probably with the slow performance of Canvas implementations. I might just be spoiled from other Javascript advances, but I swear I’ve written faster pixel pushing in Java (for Pete’s sake). Fill rate seems to be the issue. Since canvas methods are synchronous (aka, more or less, “immediate mode”), the bigger the canvas the slower your code (the norm in most other graphics contexts but not usually on the mind of someone animating CSS values). I don’t have to worry about buffering, but I’m definitely looking forward to Direct2D and OpenGL backends.

This demo came almost directly from the eighth JBox2D demo—I wanted code I was certain would run—but I don’t have mouse picking or bullets yet. Five sets of blocks fall from above, jittered slightly around five x-coordinates to get a different result every time the simulation is run. You’ll notice that in the Java version of the demo the stacks of blocks stay upright. In many rigid body physics libraries, apparently, stable stacked blocks are an indicator of quality as they are easy to produce in real life but difficult to simulate. The posted demos are running at  the suggested 10 constraint-solving iterations per step, but, since they only run at 30 steps per second (and can only run faster in Chrome and Safari), it is extremely unlikely that the engine will be able to recognize the stacks of blocks as at rest and let them stay stacked.

The effects of a lower framerate are usually easy to spot. Resonances, like in a swaying stack of blocks, are often self reinforcing until the medium can no longer contain them (and the blocks fall over). Due to the way positions are integrated, larger time steps cause objects to tend to overshoot slightly, intersecting one another and appearing somewhat “bouncy.” The goal is to simulate a system under constraints in a way that resembles reality, but as time steps lengthen to compensate for a dropping framerate, this becomes more difficult.  At 60 frames per second, the blocks fall into place and stay stacked almost every time; at 30, they almost always fall. The exact same physical setup, simulated at different rates, can lead to radically different results (paging Dr. Malcom). Stable numerical integration is a fascinating subject and marrying it to an environment like Javascript is just asking for the best kinds of trouble.

The “benchmarking” stats at the bottom of the Canvas are for the physics calculations only. On my computer, Firefox runs the first demo noticeably slower than 30 frames per second even though the physics calculation time would allow it to run faster that that. Rendering on a 750×400 pixel Canvas nearly doubles the time per frame (that’s 60 quads on a surface smaller than a Nexus One screen. We have hardware for that sort of thing!). Hence Worker scripts. While most people don’t want the average website to peg their processor, I see two processes that are largely independent; why not run them in parallel? Firefox 3.7?

Finally, I would really like to upload the demo source to the Google Code repository, but I would have to commit it from another Eclipse project. I’m still a total SVN noob, so I’m afraid I’ll screw up everything while trying to do that. Stay tuned.

gwtBox2d Demo 1—Main-loop Implementation

gwtBox2d Demo 2—Worker Implementation

This entry was posted in Uncategorized and tagged , , , , , , , , , , , . Bookmark the permalink.

One Response to This page best viewed with a quad-core CPU

Leave a Reply

Your email address will not be published. Required fields are marked *


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">