Ever find yourself in a position where you absolutely, positively have to get a ton of monkeys on screen with a single draw call?
Yeah, okay, me neither. (At least, not until I put together the demo for this post.)
But there's certainly occasions when it makes a lot of sense to redraw the same mesh many times with some minor tweak like position, orientation, color, etc. Simple examples of this are trees and other vegetation, streetlights, boxes in a warehouse, soldiers in an army, and so on.
Traditionally with WebGL the optimal way to draw those repeated meshes, commonly referred to as instances, would be something like the following pseudocode:
bindMeshArrays(gl);
for (i = 0; i < meshInstances.length; i++) {
var instance = meshInstances[i];
gl.bindUniform3fv(meshPosition, instance.position);
gl.bindUniform4fv(meshColor, instance.color);
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_SHORT, 0);
}
This is good, because we only set up the vertex attributes (implied to be in bindMeshArrays) once, then make many draw calls in quick succession, only changing the properties that are different from instance to instance. In this case just position and color. This makes for a near minimal amount of overhead for each draw call, and in an environment like Javascript where each call is expensive that's important!
(This example is pretty simple, and in fact you can actually optimize it further by getting creative with how you provide the GPU with the data. Check out Gregg Tavares' wonderful Google I/O talk for more ideas about how to render lots of geometry very quickly.)
Even in this scenario, however, you have to make at least three WebGL calls for every instance of the mesh. That doesn't sound terrible but in the real world that would probably be quite a bit more, and the fact is that in Javascript every call into native code (Like the WebGL API) carries a certain expense. Thus while drawing repeated meshes in this way works, and generally works well, it could still be better.
I tried out the new Blogger Google+ comments for a while, but after experiencing some weird behavior (like comments not displaying on mobile) and hearing from a couple of people that avoided leaving comments because they didn't want a Google+ account I've decided to turn them off. This may cause a couple of comments to disappear, and I apologize for the inconvenience, but I'd rather have a reliable commenting system.
Let's play a quick game: I'm going to describe a relatively recently announced web technology, and I want you to guess what it is.
It was developed by a generally well respected company that focuses on moving the web forward.
It was started to enable the web to move beyond the inherent limitations of javascript.
It allows developers to run applications programmed in a language other than javascript.
The company behind it encouraged others to join in its development, and has actively been improving it themselves.
It was designed so that when run in a specialized VM it could run much faster than an equivalent Javascript app.
To preserve backwards compatibility, however, the code is cross-compiled into standard javascript, allowing it to run on most modern browsers.
So if I stop there, what's your guess? If you've been keeping up with these things I bet you're probably thinking asm.js, which is a good guess because it meets all the criteria up above. Let me add one more hint, though:
When announced this technology was regarded with skepticism and vocal opposition.
Ah, that makes a difference. What's your guess now?
I mentioned this was coming in my last post, but it's a significant enough change that it's worth addressing on it's own. New Chrome builds, starting with today's Canary build, will begin including a new option in about:flags called "Enable WebGL draft extensions"
(This can also be activated via the command line with the --enable-webgl-draft-extensions flag)
When you enable this it will allow WebGL to access extensions that Chrome has implemented but are still in draft status on the WebGL Extension Registry. Previously these extensions would have been exposed without the flag, but with a "WEBKIT_" prefix. That goes against Blink's policy of avoiding vendor prefixes wherever possible, however, hence the new flag.
The only extension this flag exposes currently is the newly implemented EXT_frag_depth, and any extensions that you previously queried using a prefix will continue to work just fine.
So what does this mean for you, daring WebGL developers?
One of the topics that was suggested when I recently took a poll on Twitter/G+ of potential blogging topics was what kind of impact the switch to Blink has had on Chrome's WebGL implementation. I thought this would be a great area to talk about, because it allows me to dig into the guts of how WebGL works a bit more than most of you are used to.
If you're not familiar with the situation already, Chrome recently switched rendering engines from WebKit to Blink, which is based off the WebKit source. The fact that we're so early in the life of Blink means that the two rendering engines haven't diverged too much yet, aside from dead-code cleanup on both ends, but even this early there are a few changes in how Chrome handles WebGL.
Ready to jump head-first into wild speculation land? Come on, it'll be fun!
It occurred to me today that there's a slim possibility that in the near future Microsoft may actually become the biggest driver of WebGL adoption in the industry. Yes, that's right, "WebGL considered harmful" Microsoft. Sounds crazy (probably is crazy) but I feel the possibility is definitely non-zero. Why? Let's string together a series of massive assumptions, shall we?
So footage for the next installment in the "Battlefield" series was posted today, and it's got a lot of people excited. For good reason too, it's gorgeous! Totally worth your time to watch the full 17min preview:
Much respect goes out to the engine developers and artists, those are some pretty pixels!
Too bad the gameplay doesn't look like it got a similar overhaul. This is basically the same game we've been playing since Call of Duty: Modern Warfare in a new coat of paint.
For starters the enemy AI looks pretty braindead. They can't seem to aim, don't notice people running around 3 feet behind them, tend to stand in open "scope-approved" places, and don't really move around much. Yawn.
But that's okay, because the real point of playing a game like this is to be shuffled from one tightly scripted, minimally interactive set piece to the next. Right? Of course at some point that stops becoming a game, and that's what's got me a little down.
It's very interesting that this preview starts out showing us the ending, then bounces back in time to show how we got there. Flashbacks can be a very effective literary technique, but in the context of a game it carries some unwelcome subtext: "Nothing you do over the next hour matters, because you will always end up right here." And why not? After all, the animators spent a lot of time on that scene, the artists custom built an "upside down car underwater set" just for the occasion, the script writers agonized about the precise placement of all those swear words to convey the appropriate panic with a "mature" feel. There was a lot of blood, sweat, and tears (and money) that went into that 5 minutes of barely interactive cutscene, it would be a tragedy if the players missed it!
And as a result no matter what you do you're going to end up upside down in a car underwater. You'll never be able to outrun that helicopter, you'll never be able to save Soldier 3's leg, never be able to successfully defend the pickup point, and never spare your helicopter support her untimely end. What you can do (the "interactive" part) is fail to live long enough to witness yourself failing to do all these things. Did someone order a side of fatalism with their escapist hobby?
Maybe it's just me, but I was hoping that the next generation of game consoles would let us get away from these kinds of on-rails experiences. And yes, maybe that would mean that some game designers would have to give up on their secret Hollywood aspirations, but I'd have a lot more fun with the end result. I'm not saying games can't have a well-written narrative, but I'd really like to play a more active role in shaping it. By all means, have the helicopter pilot radio in and say "Extraction point is that building, go!" And then let me figure out how to get there. Sure, throw the enemy chopper at me right before I escape. But rather than forcing me into some pre-scripted "hanging off the building" scene, let me ACTUALLY defend the building! Wouldn't be awesome to be ducking around that shell of a structure, desperately trying to get pot-shots off, while the helicopter systematically rips the building to shreds around you? And if I or my teammates die in the process, so be it. It will be far more meaningful to me if I knew I could have saved them, rather than knowing that they're doomed from the start.
And hey, go ahead and keep that whole underwater car thing in there! There's a decent chance I'll be forced off the road anyway while swerving to avoid the hellfire raining down above me. It would be extra cool to know that the developers planned for that and didn't just throw up a "game over" screen when the car hit the water. But let me actually escape sometimes too!
Emergent gameplay is a tricky thing, because by necessity it's not going to be nearly as consistently intense as a carefully curated experience (though our increasing technological capabilities allow it to be more interesting). The times where it all comes together just right, though, are the moments that we as gamers remember forever. Those are the moments that we post to YouTube and rave about in forums. Those are the moments we share with friends the next day with giddy excitement. Rather than "Hey, have you reached the helicopter scene yet?" "Yeah! That was awesome!", which is a great reaction in it's own right, it becomes something personal, but with just enough shared context that everyone can relate:
"Hey, so you know that helicopter scene? So get this, I'm trying to fight it back but right before I fire my RPG the building supports get shot out and the whole floor starts to topple over! My shot goes wide, and I'm trying not to fall while desks and boxes and stuff are sliding past me. Then the chopper swings back around and I think I'm toast, but the RPG that I fired earlier hit that smoke stack off to the side, and it fell down right on top of him right as he began to fire! I had 8 health left! It was incredible! And so then I..."