Posts Tagged ‘pixel city’

Cityscape – Hello, internet!

Thursday, July 9th, 2009

So, Shamus Young, the lovely man whose PixelCity project this entire developer diary is inspired by a tribute to a total rip-off of, has linked to it from his blog. Which means my pages views for the last couple of days have totally exploded.

I left a comment on his blog, but I should perhaps address a couple of the same points here:

  • I’m doing this because I can, and because I wanted something to do in the evenings that my wife is out of the house. I’m on a hiatus from World of Warcraft at the moment, so figured a programming project might be fun, and as an ex-games developer with a lingering interest in 3D graphics, PixelCity provided a perfect inspiration.
  • I’m focusing far more on the technical aspects of my project than Shamus did for his – this is because, as I said above, this is a total rip-off of his original project, so all the interesting stuff about what looks right and making things look realistic has all already been written about. This isn’t a “How to draw a realistic city” diary – it’s a “How I did it in C#/XNA using more modern techniques” diary. As things progress, I might head in a different direction on some aspects (like the city planning entry) – I’ll discuss what I’m doing there in a bit more detail.
  • The C#/XNA “ZOMG MS ARE TEH EVILS” thing is not something I’m interested in discussing. I just can’t get worked up about it, I’m afraid.
  • I make no promises about how often this will update. It was pretty rapid at the start but, as with many things, it’s sort of tailed off a bit lately. It’s got sunny, I’ve been busy at work, my chilli plants need tending – I fully intend to carry this through to… well, some poorly-defined and probably still distant end-point, but I have no idea when that might be yet.
  • I apologise for inconsistently switching between first-person singular (“I did [x]”) and first-person plural (“We need [x]”). I’m a programmer, not a writer.

I think that’s about it. Thanks for dropping by; I hope you enjoyed what you read.

Cityscape – update 6

Sunday, May 24th, 2009

Right, I’ve made definite progress towards getting things looking a bit better. It turns out that it doesn’t really matter than my buildings are ugly as hell, because buildings actually are ugly as hell – at least for the most part.

The first thing I needed to do was make the textures more interesting. And, again, I just went straight ahead and nicked the technique used in TwentySided‘s blog, althought it took some tweaking. In each window, I’ve darkened a random selection of pixels in the lower half of the window, and then addded a small colour modulation.

The next thing to do was to make the buildings more interesting. Currently, a building consists of a central main tower, and then on one or more of the building’s faces, a smaller sub-tower. This took a ridiculous amount of work to achieve, and several iterations of the maths concerned – and I’m probably still going to throw it away once I think of a nicer way of doing it. But it’ll definitely do for now.

The last thing this update adds is a movable camera – the spinny-round camera was handy for testing performance and getting an overview, but it was seriously limiting in terms of making cool screenshots 🙂 It’s pretty simple – we have a position, a rotation around the y-axis and a rotation around the x-axis. The WASD keys move the position, and the arrow keys affect the rotation. We generate a look vector by transforming a view straight down the Z-axis by the two rotations.

Oh, and I made the background darker and added a black base, to make things a bit more city-like. If I’m honest, the dark blue sky is the thing that adds most realism out of the entire update 🙂 One last screenshot:

Next, we make things a little less homogenous, and discover that it’s not as simple as we might think.

Cityscape – part 4

Friday, May 15th, 2009

Things have come on a bit since yesterday. I’ve added a first-pass of the building textures, and a polygon count (for reasons which will become apparent soon enough. Now, it looks like this:

The texture generation is simple enough (and mainly ripped off, like the rest of this project, from TwentySided’s PixelCity) – a 512×512 near-black texture, with 8×8 blocks of either light or dark grey scattered across it. To get the solid-black of the tops of the buildings, I’ve simply set the texture map to a single pixel at the bottom left of the texture.

Also, you’ll notice that I’ve added more buildings – in that screenshot, it’s a 31×31 grid of buildings (with random heights, for a bit of interest), and added a polygon count. Now, the reason I added the polygon count is interesting, and we’re going to learn a bit about how graphics cards work in the process.

So, I increased the number of buildings to 961, and the framerate stayed nice and happily at about 60fps. Excellent. Then, I got greedy, and made the grid 41×41, giving me 1681 buildings – and the framerate plumetted to around 40fps. This seemed odd – I’m not yet hitting really big polygon budgets. Games these days happily push hundreds of thousands, if not millions, of polygons per frame, and whilst XNA is doubtless adding some overhead, this machine manages to pull off things like Demigod and Dawn of War 2 on respectable settings without too much pain. So something, clearly, is up. I added a polygon counter just to check my sanity, and yes, we’ve nearly doubled our polygon budget, but it’s still only about 20k polys:

Hm. So, what do we do in this kind of situation? Well, we investigate! We’ve basically doubled our poly budget by doubling the number of buildings, right? Well, more or less, anyway. How about instead, we drop our number of buildings back to the original number, and increase their complexity? What happens then? So, I added the base back on, which is essentially just another box at the base of every building, and…

Wait, what? We’ve now got more polygons than we had in our 41×41 scenario and we’re still at ~60fps. Something odd is happening here. So what happens if we add more (mini-tower on top) and more (two stage body for the building) complexity? We can do three times as many polys as our original 31×31 city without a framerate drop – it’s only once we get to four times as many – fourty-six thousand, over twice as many polygons as in our 41×41 city – that we start to see any impact at all, and it’s only a couple of fps. What the merry hell is going on here, then?

Well, remember how our buildings are constructed: for each box, we insert the vertices and indices into an array, then convert these to fixed-size vertex buffers for use when rendering. There’s one of these buffers per building. As we’re adding more complexity to our buildings, we’re increasing the amount of stuff in each buffer; however, when we add more buildings, we’re increasing the number of these buffers that need rendering – so it seems that it’s the number of buffers (or, more accurately, the number of draw calls we make) that’s our killer here.

And this is an important point: think of a graphics card as being like a car engine. You get most efficiency out of an engine when you drive smoothly, and a moderately high (but not excessive) speed, without changing speed too much; driving around a city where you’re constantly braking, changing gear, stopping, starting and so forth is absolute murder on your engine’s efficiency – and it’s the same thing for graphics cards. Hand them a big buffer of triangles to go off and render, and they’ll tear through it at high efficiency. Hand them a whole load of small buffers, or change texture or shader regularly, and they really start to struggle.

The reason for this, more-or-less, is that the time for a render call is split into two parts – a fixed setup cost, and a variable rendering cost. If you’re rendering a large number of small batches, your render time is going to be dominated by a very large number of fixed setup costs; however, if you render a single large batch, you only have to do this setup once, and then the rest of the time can be spent on actually drawing the triangles.

So, what can we do about this? Well, that’ll have to wait until next time – but remember, all of our buildings are using the same texture, shader, vertex format, etc – so an obvious solutino should hopefully present itself!

(We’re up to bzr revision 13 now, if you’re following along at home)

Cityscape

Sunday, May 10th, 2009

So, I read this series of articles on building a simple, programmatically generated city. The techniques being used are surprisingly simple and really quite old-school (everything is being done with what amounts to the state of OpenGL about 10 years ago – no shaders, no bumpmaps, no vertex buffers, nothing) – but the results are really rather effective. Anyway, as long-time readers of this here blog will know, I used to be a games developer way back in the day, and I’ve still got a bit of a hankering after 3D graphics programming, so I thought I’d give a similar project a go myself: I freely admit that I’m totally stealing the original idea here, but hey – imitation is the sincerest form of flattery, and that.

Anyway, I’ve been meaning to give all of Microsoft’s shiny XNA/C# tools a proper go for some time now, so this seems like an ideal project. This means I get to mess about with things like shaders, funky post-processing techniques and other modern trickery without having to muck around with all the pain of resource management in DirectX/C++ – this will probably be at the expense of a bit of speed, but hopefully the ability to make use of hardware vertex/pixel processing should make up for this.

I’ve got vague plans that eventually this should have stuff like cubemapped reflections for windows, dynamic level of detail for speedup, atmospheric effects using rayleigh scattering and lots of other exciting things, if I have time. But, first things first: the very first thing to do is to get something up on the screen. In this instance, it’s a hugely exciting texture-mapped cube:

Actually, there’s quite a lot more to this than it looks: to render that, we build an array of texture-mapped vertices with normals, then render it using a custom XNA effect (which, at the moment, contains a very simple pair of vertex and pixel shaders to do diffuse lighting). The light source is fixed to the camera position, and the camera is rotated around the box at the speed of 1 radian/second.

There’s two classes involved here: the XNA Game class, and the Building class, which is derived from the XNA DrawableGameComponent class. When the Game object is Initialize()d, a Building object is created and added to the Game’s Component list. When the Building object is Initialize()d, it calls the AddBox() method, which populates a list of VertexPositionNormalTextures and UInt16s with vertex and index data for a box of the appropriate dimensions, and then copies that data into static arrays (for speed of rendering). A texture and the render Effect are loaded and bound appropriately.

Then, on Draw(), the Game sets up appropriate render states, positions the camera, and calls Draw() on all the child components; the Building’s Draw() calls then sets up the matrices for its Effect, and loops over the Effect’s passes (in this case, there’s only one) calling DrawIndexedUserPrimitive() to render the box.

It’s quite a lot of code to get up and running, but hopefully this setup should mean that progress from here involves rather less setup and skeleton code. If you want to follow the code for this as well, there’s a Bazaar repository at http://bzr.parm.net/Cityscape/ – it’s read only, although obviously you’re entirely free to create your own local branches and tool around with it as much as you like. We’re up to revision 4 at the moment – and the first couple of revisions are slightly broken.

I make no claims about the quality of the code, or even if it’ll work on your machine – it’s a Visual Studio 2008 project, using XNA 3.0; it ought to build in Visual C# Express with a small amount of poking, but I haven’t tried it. It seems to run reasonably well on my poky little netbook (as well as beefier machine with Real 3D Hardware) at the moment, so with a reasonably recent machine, you should be good to go.

Next step: Make an actual building!