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.

Saturday, April 6, 2019

Rainbows

Last week was rainy. On my way home in the evening I saw a bright double rainbow in the sky. It made me wonder how the physics of a rainbow works, so I looked it up online the next day. Rainbows are visual artifacts formed by the refraction of light through water droplets in the air back to the viewer. They span a viewing angle from 40 degrees (violet) to 42 degrees (red) around the viewer's field of view in the direction opposite the sun. There's sometimes also a second rainbow from 50 to 53 degrees, called a double rainbow. Rainbows aren't in any real physical location, they're more like projections onto the cloud/mist in the distance.

I'm not aware of any other games that display realistic rainbows, so it seemed like something interesting and unique to add to 3DWorld. I implemented a rainbow as a quad projected opposite the sun, where the colors are generated in a fragment shader as a function of radius using a color spectrum that I matched to images. This is both fast and close to physically accurate. 3DWorld only draws rainbows in the cloudy period after the rain has stopped, during the morning and evening times when the sun is low in the sky. The brightness of the rainbow is determined by integrating along the view ray using the depth buffer. The places where the rainbow falls over distant objects appear brighter than locations where there are nearby objects. Here is a screenshot:

Physically based rainbow drawn in a fragment shader. Those small black specks in the sky are birds flying in flocks.

That looks pretty good to me. It appears to blend correctly against the trees and mountains, and reflects in the water. If you look closely you can see that the center area inside the rainbow's color bands is slightly brighter. I suppose this rainbow looks a bit too perfect though, maybe because it has a nearly constant brightness against the clouds. I could probably add some random intensity variation to improve the realism. Also, I'm only drawing a single rainbow, not a double rainbow. I think the single rainbow is enough for now.