The internet is a strange place where you can learn about things you need which you didn’t know you needed. For example, Left 4 Dead cookies.
Procedural City, Part 11: Demonstration Video
Here are the key points of the project, distilled into a short video.
Link (YouTube) |
Seeing the thing in motion really is more exciting than screenshots.
I know in the video I claimed it was released as source and a screensaver , but that step has been delayed and I’m to lazy to re-cut the video.
Soon.
Note that the stuttering apparent in the video is not from the program itself. It was running at 200-300fps with no slowdowns when I made this video. The stuttering either happened during video capture or during the encoding process, which I was obliged to do twice. (Cheapo Windows Movie Maker doesn’t support multiple audio tracks, so to get the typing sound and the music in there together I had to encode the entire movie with just the typing, then re-import that movie and add the music. There were probably better ways to have solved this, but all of them would have taken longer and I’d already spent more time on this than I’d intended.
The story of the cool cam is one many engineers (and by extension, programmers) need to take to heart, that marketing does not always deserve the scorn we give it, and that a little polish in presentation can go a long way to covering up the lack of polish in everything else. I applied that lesson to great effect here. The animated camera does a great job of showing off the cool stuff and hiding the rough edges.
Gamethread 5/1
Special today: Existing Steam users can play Left 4 Dead for free. Also, the game itself is down to $25.
I have a friend who is trying to get another server set up for us. It’s running, and it works well. But it doesn’t show up in the master server list, so you have to enter the IP directly. The server is behind a router, and apparently you have to jack into the port ROMs and resolve the webnet protocol drivers on the server matrix. Or something like that. My vision is for us to have two servers: One for survival mode, and another for campaign mode / versus. I know survival is intense, chaotic, and often cruel. It’s not everyone’s cup of tea, and the dangers of campaign mode seem placid by comparison. It would be nice if we could have access to both game types to suit everyone’s mood and play style. And also because 4 slots is just not enough for all 300+ of us.
Experienced Points: Reviewer, Amuse Me!
Attention game reviewers: Entertain me! Dance for my amusement! Say something witty! Engage in frivolous japery to wring a smile from my stony visage.
No? Then sod off.
Stolen Pixels #86: Left 4 Dumb: Part 8
People keep telling me they enjoy this series, but they can’t possibly be enjoying it as much as I am. It’s nice to have material that’s written ahead of time and to know I’ll be able to get the shots I need from the game. I seem to be coming to some sort of truce with Garry’s mod. Perhaps someday I’ll attain the lofty goal of becoming “competent” with the thing.
Procedural City, Part 10: More Performance
More Performance Enhancements
- I put more blank space between the buildings, gave the existing buildings a slightly larger footprint, and made the streets wider. Surprisingly, this ended up cutting about 25% of the buildings in the scene, which actually looked better.
- I merged the individual street lights into strips, like Christmas lights. This means all the lights on the same side of the street are actually one big polygon. This means streetlights look goofy if you get too low, but eliminated thousands and thousands of polygons from the scene. I doubt I’ll ever be really happy with how the streets look, but I think I at least have it to the point where I can live with it.
- I added a widescreen / letterbox mode where the drawn area will only take up part of the screen space. This saved a not-at-all-impressive 2fps on my machine, but I’m hoping it will make the thing run better on low-end graphics cards. Users with fill-rate problems should see improvement when they use it.
- I limit the cars to ten updates per second. The car movement code is fairly cheap, but there will potentially be a lot of cars in the scene and after few hundred iterations it starts to add up. Limiting the cars to 10fps means that their movement would look a bit stuttering up close. But since they creep along far away from the camera, there is no reason to waste time calculating each and every tiny little movement, most of which will be too minute to be visible to the user.
- Cars are limited in how far away you can see them. After a car gets a certain distance from the camera, it’s taken out of play and dropped somewhere into the visible area in front of the camera. This keeps the apparent car density high.
- Related to the above, the “distance” of the car is calculated in manhattan units. (I can’t find a definition of manhattan units anywhere online. I know I’m not the only person to use this term. I wonder what other people call it?) MU are a distance check that involves calculating the distance between A and B by simply adding the horizontal and vertical offset. If you’re a kilometer east and a kilometer south, then you’d walk about 1.4 kilometers on the diagonal but you’re 2 kilometers away in manhattan units. A real distance check calculates how from from A to B if you were flying. A manhattan check (do you still capitalize it when it’s the name of a unit and not a place?) figures out how far you would travel if you went from A to B by traveling only along one axis at a time. A real distance check requires two multiply operations, an add operation, and then a square root. Manhattan units require a simple addition operation. Using MU for visibility means that you can see farther looking down a grid-aligned street than you can by looking diagonally over the city. But this is ideal, since buildings are usually blocking the diagonal view. The cases where the user might see through a gap in the buildings several diagonal blocks away are rare and fleeting, and the user is not likely to notice a lack of cars. The performance boost from this is probably too small to measure, but I loved finding a case where I could shamelessly cut corners with no perceptible loss in quality.
- I fixed a bug where I was rendering all of the black flat-color stuff twice. I was rendering it once with the rest of a building, and with a texture on it. (Although since I wasn’t setting texture coordinates, it was just taking a single pixel and smearing it all over the object.) So it was being drawn once with a pure black section of a texture covering it, and then drawn again later as black polygons with no texture. I’m sure I don’t have to explain why this mistake wasn’t visible while the program was running.
The final tally: The program is taking up my entire 1920×1200 desktop and runs at over 200fps. It goes down to ~90 when bloom lighting is on and becomes very fill-rate sensitive (finally! it’s nice to know the GPU has some sort of limits) but I’m happy enough with performance now.
The biggest drain on performance now is bloom lighting, which is optional. I can really make bloom work twice as fast, but make it look a little less appealing. In fact, it’s only now that I’m questioning if I’m doing bloom “right”.
A Bit About Bloom
I’ve never looked up how other programs generate bloom lighting. I saw bloom in action for the first time when I played Deus Ex 2. I looked at the blobby artifacts it created and made some assumptions about how it was done. Here is how I thought I worked:
(Note that the example bloom I’m using here is a simulated effect, generated in Paint Shop Pro. The artifact I want to show you is really visible in motion, but actually kind of subtle in a still frame, so I’m exaggerating the effect for demonstration purposes.)
This is the full view of the scene at a given instant during the run of the program:
| The city, without bloom. |
But before I render that, I render a lower-resolution version of the scene into a texture:
| The bloom buffer, if you will. It’s actually not THIS pixelated, but you get the idea. |
After I have a low-res version of the scene saved in a little texture, I render the real, full screen deal for the viewer. (The first image.) Once I have that rendered, I take the pixelated bloom buffer and blend it with the scene using a “brighten filter”. People using Photoshop call it the “Screen” effect, I believe. OpenGL programmers call it glBlendFunc (GL_ONE, GL_ONE);.
| Split image. On the left side, the bloom is pixelated. On the right, it’s smooth. |
What you end up with is the left half of the above image: big glowy rectangles over bright areas of the scene, instead of blurry circular blobs of light. Again, it looks fine in stillframe, but when the camera is flying around the scene the rectangles tend to stick out.
But you can soften the rectangles out by rendering the bloom layer more than once, and displacing it slightly each time. This fuzzes out the edges of the rectangle and gives it the dreamy glow I want. It also means blending a huge, screen-covering polygon multiple times. As I mentioned in my previous post, blending is (or can be) slow.
Is this how games do bloom? I don’t know. (Actually, modern games will invariably be using pixel shaders to achieve this effect, which will be faster and probably let them soften those edges in a single draw. But I’m bull-headed and insist on building this thing using stone knives and bearskins.) At any rate, there is an annoying but unsurprising trade off between performance and quality going on here, and the “sweet spot” between the two is guaranteed to be very different for different hardware. Bloom way well be unusably slow just two GPU generations ago. All I can do is give users a way to turn it off and see how it goes.
Feedback & Performance Suggestions
Some people made some great suggestions on how the program could be further sped up. The use of vertex buffers was suggested. A vertex buffer lets the program gather up all of the geometry in the world and stick it right on the graphics card. (Assuming the graphics card has the memory for it, which isn’t a problem in my case.) This would eliminate the most expensive thing my program has to do, which is shoveling geometry to the GPU as fast as it can. However, I’m pretty sure integrated graphics cards don’t support them. (Actually, data on what hardware supports them and what doesn’t is as scarce as copies of Duke Nukem Forever.) Since I can’t count on all users having VB support, I’d have to use two rendering paths: The one I have now for people with low-end hardware, and the super-duper fast one for people with newer hardware. This means people with great hardware will go even faster still, and people with lower hardware will have no benefit. Adding a bunch of code to push my framerate up to 500fps while doing nothing to help the guy chugging along at 20fps is a brilliant way to expend effort in such a way so as to not benefit anyone. So let’s skip that. (This is assuming I’m right that there are computers less than five years old that don’t support VB’s.)
Someone else suggested that a quadtree would be an ideal way to handle the culling I was doing in my last post. It’s tempting, but that would be a lot of work and I’ve already hit my vaguely defined goal.
I know I promised a wrap-up to this series this week, but the tiresome impositions of my mortal form have frustrated my progress. Also I played a bunch of Left 4 Dead. But I am actually done working on the thing. I just need to write about the final steps and release it. My plan is to release it two ways:
1) The source and project files, so others may tinker or point and laugh.
2) As a Windows screensaver.
Next time: Finishing touches.
Insomnia
Insomnia is an interesting malady. It’s pretty common. (64 million Americans suffer from it on a “regular basis” each year. Which works out to, what? 1 in 5? Something like that.) I find it interesting because I get it pretty frequently, and it doesn’t seem to have any of the usual triggers associated with it. Yesterday was almost exactly the same as the day before. I woke at the same time, worked the same hours, knocked off work, spent time with the family, wrote on my blog, and played Left 4 Dead. It was a pretty good day, so I didn’t mind having it twice in a row. I even ate the same foods. No change in stress levels. (The only difference is that I was out for a routine dentist appointment yesterday, and I can’t imagine how that could have any effect.) But last night I never went to bed. The sun is up. Birds chirping. Still not sleepy.
I’d like to think this means I have some special, exotic case of insomnia. But the truth is that we probably just don’t understand it very well. I’ll bet a lot of insomnia like mine gets blamed on “stress”. It’s pretty hard to get through a day on this planet without a little stress at some point. You had stress? Oh, that must be what caused your insomnia.
Right now I feel like an old laptop that’s been left on and left unplugged. I’m idle now, but at some point the battery is going to fail and I’ll crash.
I didn’t finish a post for today, but I made this for some reason:
![]() |
Brains are weird.
Gamers Aren’t Toxic
This is a horrible narrative that undermines the hobby through crass stereotypes. The hobby is vast, gamers come from all walks of life, and you shouldn't judge ANY group by its worst members.
A Star is Born
Remember the superhero MMO from 2009? Neither does anyone else. It was dumb. So dumb I was compelled to write this.
Mass Effect 3 Ending Deconstruction
Did you dislike the ending to the Mass Effect trilogy? Here's my list of where it failed logically, thematically, and tonally.
Video Compression Gone Wrong
How does image compression work, and why does it create those ugly spots all over some videos and not others?
The Middle Ages
Would you have survived in the middle ages?
The Best of 2016
My picks for what was important, awesome, or worth talking about in 2016.
This is Why We Can’t Have Short Criticism
Here's how this site grew from short essays to novel-length quasi-analytical retrospectives.
Diablo III Retrospective
We were so upset by the server problems and real money auction that we overlooked just how terrible everything else is.
Deus Ex and The Treachery of Labels
Deus Ex Mankind Divided was a clumsy, tone-deaf allegory that thought it was clever, and it managed to annoy people of all political stripes.
Final Fantasy X
A game about the ghost of an underwater football player who travels through time to save the world from a tick that controls kaiju satan. Really.
T w e n t y S i d e d
