|Programming, Projects||By Shamus||Apr 16, 2009||47 comments|
Setting up the World
One of the interesting decisions that a programmer must make at the start of a 3D project is figuring out what scale to work in, because the renderer doesn’t care. Perhaps you want to set things up so that nearby things are a unit away, and the stuff in the distance is 100,000 units away. Or nearby is 0.00001 and far is 0.0001. It’s up to you to pick a scale and to decide what the arbitrary units mean. Are you working in meters? Feet? Cubits? Fathoms? The effective range of an African swallow carrying a coconut? In Unreal Tournament, characters were around 160 units tall. (I think that the intent was for 128 units to = 1 meter.) In my day job, we work with a system where 1 unit = 1 meter.
While the renderer doesn’t care, it’s important to devise a system that makes sense to programmers and artists so that making content is as easy as possible. If you make something like 1 unit = 2.333 meters, then your artist making a 1.5 meter object is going to use a calculator all day and then spend their evenings plotting how they plan to conceal the body after they murder you. Perhaps 1 unit = 1 kilometer seems reasonable, but making furniture that’s 0.0005 tall is going to be really annoying.
In this program, I’ve decided to eschew using real-world measurements and adopt an arbitrary system of measurement where 1 unit = 1 window. A building that’s 20 units wide will have 20 windows across its face*. 1 unit will also equal 1 traffic lane, so a road 5 units wide will be 5 lanes. Is the typical building window really the same width as a traffic lane? I don’t know, but I’m betting it’s close enough to look believable from a vantage point over the city, which is how the place will be viewed.
* And by “window” I mean an 8×8 little square of pixels. I might have black lines in the space to make that square look like (say) two windows side-by-side, but it’s still a window as far as the program is concerned.
This scale will make it easy to track how I’m using land. I allocate space for my city: 1024 x 1024. According to Wikipedia, a U.S. traffic lane is 12 feet which works out to about 4 meters. So my city will be about 4 kilometers on a side, or ~16Km2 and have just over a million individual 4-meter plots that can be assigned as space for buildings or streets.
One thing you end up doing all the time in programming is subdividing things. Searching, sorting, and grouping things usually involves taking whatever stuff you’ve got and cutting the group in half until it’s found, sorted, or organized. Let’s take a group of 1,000 things and repeatedly divide it in half and see how it goes:
1,000, 500, 250, 125, 62.5, 31.25, 15.625, 7.8125, 3.90625, 1.953125, 0.9765625
Now let’s try it with 1,024:
1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1
But hey, we have the same number of numeric digits as we have fingers, and that’s pretty awesome, right?
So I take my city and mark areas of it as “streets”. The streets will be invisible in the final version, but I’m rendering them here as blue lines so I can see what I’m doing.
Now I place 20 big impressive skyscrapers in the middle area of the map. These are buildings with a large footprint and they range from 45 to 55 units tall. (And since units are windows, that’s how many stories tall they are.
Next I scatter around a few dozen smaller buildings. These are just as elaborate as the last batch, but these range from 25 to 35 stories tall.
And finally I fill in the remaining empty space with simple cube buildings.
4,752 buildings. The framerate is still shockingly high considering what I’m asking of the GPU. Still, I’m well under 100 FPS now and I’m betting this would be unacceptably choppy on low-end hardware. On the other hand, I have made no effort to optimize things yet. I don’t even know where the current bottleneck is. That will come in a later step, when I have a little more of the technology written.
I try turning off the dev background and the blue “roads” and seeing what it looks like. Disappointingly, the place looks a little… homogeneous:
Looking back to my reference pictures, I notice that each building seems to have its own color. This is either due to the color of the interior lights, the color of the interior stuff like walls and carpeting, or the tint of the windows. In any case, each building has a slightly different tint. I pick a narrow band of hues and apply them to each building:
It’s hard to see in this screenshot, but the overall effect is pretty striking. It adds another layer of randomness to the world, so that even if two adjacent buildings happen to be using the same texture, they’ll likely be different colors. COUNTERPOINT: Uh, in the middle of this screenshot are 3 buildings the same texture and color. Ugh.
I cruise around the city and take notes:
- I notice some buildings don’t look quite right. Yellow, blue, and white lights look fine. Green and red hues look wrong. This suggests that the real source of the color is the type of light used in the building. I do see some greenish windows in the photos (albeit very pale) but they look wrong in my simplified little world.
- The window distribution is just too uniform. As I pointed out last time, some buildings should have spaces of dark areas. Right now all buildings are unbroken grids of windows, and it just feels monotonous.
- Related to the above: I think some protruding ledges, rooftop A/C units, and other clutter would help a lot, particularly if those items were simple black silhouettes against all of these white grids.
- As some people have pointed out: The “mirroring” is quite noticeable in some places. The window pattern on the east side of every building will be an exact mirror image of the front, so that when you look at the northeast corner it’s like a Rorschach blot test. Same goes for the west and south walls. This is due to the cheap way I used to map textures onto walls. It was quick & dirty, and I thought it would be fine, but the mirroring is too obvious. How I think it needs to work is that I need to wrap a texture around a building, except that when I turn a corner I should step back exactly 1 window. This means the windows at the end of one wall will be identical to the column of windows that begins the next. Since those windows ostensibly look into the same room, their lighting pattern needs to match or it looks screwy.
- I don’t like the rigid grid of streets. Some angled or curving streets would help a lot, but that would add huge complexity to the program. Right now the fact that streets run perfectly along an axis without obstruction simplifies many things. I think I’ll live with this problem for now rather than over-complicating things.
We’re probably 15 or so hours into this 30 hour adventure. Still on my to-do list:
- Lights, both streetlights and lights on buildings.
- Car lights.
- The big one: Optimization. I’m eager to get to this step and find out what’s slowing the program down.
- All the fixes and changes I’ve mentioned earlier.