Sunday, April 14, 2019

Procedural City: Secondary Buildings

I've done a lot of work and written quite a few blog posts on 3DWorld's procedural city. Most of these showed my group of 8 cities filled with office buildings, along with a network of connector roads, bridges, and tunnels. The space between the cities was mostly filled with grass, rock, and dirt. It's time to fill that empty space with secondary buildings.

The procedural city system is split into the city part and the buildings part. The city part handles city plots, the road network, traffic lights, streetlights, cars, and pedestrians. The buildings part handles ... buildings. These two components interact with each other through an API. The city generation control flow works as follows:
  1. Choose mostly flat areas of land for rectangular city plot locations.
  2. Level the terrain under each city location and remove (technically forbid) vegetation.
  3. Divide each city into a grid of roads, intersections, and "blocks" for building placement.
  4. Attempt to connect each city to each other city by a set of roads using a road cost function.
  5. Place traffic lights in intersections and streetlights along roads.
  6. Place buildings in each city block.
  7. Place secondary buildings around the city. [New!]
The city generation algorithm provides parameters to the building generation module. I wasn't able to easily add secondary buildings outside of the city using the same building generator used for cities. Instead, I had to add a second building generator class to handle generation, drawing, and collision with secondary buildings. There are config file variables to set the placement area, sizes, densities, and types of secondary buildings for the scene. This set of variables is independent of the city/city building parameters.

I decided to only place secondary buildings in the flat-ish area in the center of the island map, surrounding the city sites. There are a total of 1625 city buildings and 12,660 secondary buildings. If I placed buildings over the entire island there would be about 25,000 of them. However, the edges of the island has a mix of water and mountains, and the resulting scattered buildings don't look very good. In addition, I get a few buildings on some of the tiny islands off the coast.

Building generation is very fast. It takes about a second to place and generate these 14,285 buildings. Compared to the 3.2s it takes to load the 64MB heightmap PNG image, that's pretty fast. In fact, most of the city scene load time is reading and setting up textures.

One of the most expensive parts of building generation is placement. For each building, the terrain height at the center point is used for the foundation height, and the terrain under the building's bounding cube is leveled to that elevation. Buildings aren't placed when the terrain is underwater or too high in altitude.

Here's a screenshot of some cities with secondary buildings placed around them. I've expanded the city rectangles and connector roads and marked them as keep-out areas for buildings. Buildings are placed with some separation between them for future addition of local roads. I started with random building orientations, but that didn't look quite right compared to the Manhattan orientation of the city buildings. It also produced some artifacts when flattening the terrain under each building. So I left them un-rotated instead.

Procedural city with surrounding secondary buildings, shown during the day.

I changed one other aspect of these brick and concrete block buildings. The windows are now stretched to fit the sides, which avoids partial/clipped windows and windows that wrap around the sides of the buildings. This was tricky to get right, but worth the effort.

Here's the same scene shown at night time. Buildings have randomly lit windows, which makes the cities feel more alive. Windows are actually drawn on top of the wall geometry in two additional shader passes, one for base windows and another for window lights. These windows add more detail and realism to the otherwise empty brick and block walls. Since they're made from special generated textures rather than geometry, they're very cheap to draw.

Procedural city with secondary buildings shown during the night.

Houses

I added a new class of building: houses. Houses are generally smaller/lower, and have sloped rather than flat or beveled roofs. They come in several geometric forms:
  • Simple cubes (+ sloped roof)
  • L-shapes (+ orthogonal roof sections)
  • Side-by-side large + small sections
  • Two adjacent cubes of different sizes (like a duplex)
Some of these house building types can be seen in the screenshot below.

Houses with sloped roofs and 1-2 sections (L and I shapes).

These buildings seem too large to be houses though. They look more like apartment buildings. That's fine, my city can use some apartment buildings too. After taking this screenshot, I went back and added config file options to generate houses of variable sizes. This produces a mix of smaller houses and larger apartment buildings. Take a look at the new mix of buildings.

Some houses are smaller than other building types. Maybe they have too many windows though?

That's better, but the houses still look a bit large. More specifically, they all have at least two floors, and most have at least three floors. There are no single story houses. Maybe the windows are too small and close together? Well, windows are about the right size when these buildings are compared to the office buildings in the city plots. I think the problem is that they're too tall. Most houses are shorter in height than their lengths/widths, especially when excluding the roof. That's the problem here, the roof it added to the base height of the house rather than being included as part of the height. That's a bit difficult to fix, given the order in which these building parts are generated. Instead, I'll just decrease the height of houses by a random amount. A house height scale factor of 0.6 to 0.8 seems to work well. Here is what I get now:

A mixture of secondary buildings and houses, with houses made a bit shorter. Some of them are single story now.

That's better. There are some single story houses mixed in with the larger ones. This looks improved, but now the grass appears to be too large. However, that's an issue to deal with another day. If you don't like the look of the grass, it can be disabled and replaced with a grass texture on the terrain. That type of grass is faster to draw anyway.

 Another view of houses and other building types.

Here is a night time scene showing a mix of larger buildings and houses with some lit windows.

Larger buildings, smaller buildings, and houses at night, with some lit windows.

That's pretty good for the first pass. I'm sure I can improve on houses later. I would like to add more variety to their geometry/architecture. In addition, it would be interesting to procedurally generate doors, porches, garages, sheds, fences, etc. Also, I can't forget roads. I'm not sure exactly how I'm going to connect all of these different buildings to the rest of the city road network, but it's a good future work item. I haven't yet decided if I want to allow cars and pedestrians in these areas.

3 comments:

  1. Don't forget the suburban dirt parking lots, and yards full of rusted out beaters.
    Would also be nice to have a few parks with trees and flowers in the city, since you've got a way to generate the assets anyhow.

    ReplyDelete
    Replies
    1. Thanks for the suggestions. I haven't added parks or non-city parking lots yet. I've mostly been concentrating on building interiors. I did add cars parked in garages and fences around yards though.

      Delete
    2. I made some of the city blocks into parks with trees and benches. I didn't add flowers yet because I don't really have the fine-grained control to place them only in parks.

      Delete