Monday, October 21, 2019

Procedural City Update

It's been a few months since I posted something to the 3DWorld blog. I've been busy with various other things and most of the work I've done on 3DWorld has been optimizations, bug fixes, and cleanup. I've made various minor improvements to my procedural city in the past few months:
  • Grass is now properly scaled to match buildings (it was previously much too large)
  • Added chimneys to some of the generated houses
  • Secondary buildings now show up in overhead map view
  • Overhead map view optimizations (~2x faster)
  • Added doors to some building types (cube based buildings for now) 
  • Pedestrian destinations now include parked cars in parking lots (in addition to buildings)
  • Fixes/improvements to tunnel end point placement to reduce the oversized facades
  • Bug fixes to building and tunnel ray casting/queries and collision detection
I'll provide more detailed descriptions of some of these items and a few screenshots showing what I've done.

Grass Scale

the original grass scale was way off. Grass blades were half the height of the door in the house below. This was because I was using the same grass scale/size for both ground and tiled terrain mode, even though distance scales are different in these modes. The grass looked bad enough that I disabled it when capturing most of my city screenshots in previous blog posts. It was time to fix that.

I've finally scaled the grass 4x smaller, and it looks much better. I suppose it's still a bit too large. I think it's good enough though. Smaller grass comes at a somewhat reduced framerate because there are more blades drawn. Technically, the level of detail (LOD) falloff scales as well, so there should be the same number of blades. In reality the LOD is determined based on the distance between the camera/player and the closest point of the grass block within a tile. This means that LOD can only be applied per grass block and the nearest blocks must all be the highest detail. I lose some fine LOD control due to the coarse granularity of the LOD blocks. If I make the grass much smaller (denser), the performance will be unacceptable.

Here's a screenshot showing the current quarter length grass height in tiled terrain mode.

Houses with more realistically sized grass blades. They're still a bit large, but much better than they were before.

House Chimneys

I decided to add chimneys to 67% of houses. This makes them look a bit more interesting and realistic. Now houses can have multiple sections, sloped roofs, doors, porches, garages, sheds, and chimneys. I wonder what I'll add next? Swimming pools? A screenshot of some houses with chimneys is shown below.

Procedurally generated houses now have a 67% chance of having a chimney.

Overhead Map View

I went back and made another pass at city and building support in overhead map mode and made two significant changes. First of all, secondary buildings are now shown. There are a lot of them, as can be seen in the image below.

Overhead map mode showing both city buildings and secondary buildings (and all cars!) at around 12 FPS.

Map view can be zoomed out to show the entire city with pixel-sized buildings, and zoomed in to show individual (moving) cars and benches filling the screen.

Overhead map view zoomed in on a city showing buildings, individual parked and moving cars, and benches.

This looks good, but really hurt performance. Map draw time was increased from 100ms (10 FPS) to around 160ms (6 FPS). [Note that this mode colors each pixel on the CPU by doing ray queries into the scene, which is flexible but somewhat slow compared to drawing on the GPU.] The framerate doesn't have to be that high for map view because the player isn't walking around. It only supports pan and zoom with the arrow keys and mouse, similar to Google Maps. However, 160ms made panning feel too slow. I made various optimizations such as adding improved acceleration structures for querying buildings and cars. Now draw time is down to around 80ms (12.5 FPS), which is about half of what it previously was.

Building Doors

I added building doors to complement my house doors. These use a different texture of a pair of glass doors rather than the single white wooden door used for houses. Each building has between one and four pairs of doors randomly assigned to an exterior wall on one of the four sides. Doors look reasonably good on brick and stone buildings, but tend to conflict with windows and other features present in the textures of metal/glass office buildings. The problem is that I can't move the windows around to avoid the door in these buildings because I'm not placing individual windows. They're part of the building textures. Here are some screenshots of what these doors look like on various building types and textures.

Door placed on the side of a concrete block building. Note that the entire bottom row of windows has been removed so that the door doesn't overlap them.

Door placed in a glass office building. The style of the door matches that of the building, though the vertical height isn't quite aligned with the windows.

Door placed in another office building. The height is correct compared to the windows, but it's placed over/next to a window.

The door texture I used contains a reflection that doesn't match the scene in 3DWorld. Almost all of the real door textures (from photographs) I was able to find online had reflections. I tried filling the glass windows in the doors with a uniform gray, but that made them look too artificial. So for now I'll keep the false reflections.

Maybe at some point I can generate real reflections for nearby doors as the player moves around the scene using a system similar to how 3DWorld does water plane reflections. Or maybe I could use the system I have for cube map reflections in ground mode. However, I'm not sure how many people would actually notice the reflection on such a small door. It's a lot of code complexity, development effort, and frame time dedicated to a minor feature that could go unnoticed.

Pedestrian Parked Car Destinations

The original pedestrian navigation system chose random buildings as destinations. Once a pedestrian reached the building, he/she was re-spawned at a random location outside the player's view. I decided that it would be interesting to have some of the pedestrians (25%) choose to walk to parked cars instead to add a bit of variety. This mostly worked, but I did encounter two unexpected challenges.

First, some of the parked cars were walled in between other parked cars such that pedestrians couldn't reach them without intersecting the bounding cubes of surrounding cars. There isn't always enough space between parked cars for pedestrians to fit. They would just walk around the block of parked cars and never reach their destinations. The fix was to group blocks of contiguous cars in a parking lot into a bounding cube and consider the pedestrian at their destination on a collision with any car in the group, even if it wasn't the correct car. How can the player tell which car was the destination anyway? Yes, I do have debug visualizations for this, but that's really for my own use. Problem solved.

The second problem was related to using separate threads for updating cars and pedestrians. This caused 3DWorld to crash after running the simulation for a few minutes. I was eventually able to track it down to the code that sorted cars by city and distance to the player. This sorted parked cars as well as moving cars. If a pedestrian happened to query a car that was in the process of being moved by the sort algorithm on the other thread, it could occasionally read incorrect values that lead to asserts and other odd behavior. I tried a number of fixes that failed to solve the problem, then came up with something simple. All that's really needed is the bounding cube of the car for collision detection purposes. I can simply generate a vector of bounding cubes for the cars in each parking lot, and use that for pedestrian destinations and collision detection. Since this vector never has to be sorted, the other thread won't touch it and everything works correctly. That changed fixed the second problem, and now car destinations are working.

Tuesday, August 6, 2019


It's time to take another break from my procedural city project and work on something different until I figure out what the next steps are. Last week someone posted a video of real lightning in slow motion on Reddit, which reminded me of the lightning effect I added to 3DWorld way back around 2008. I went back and looked at the lightning in 3DWorld, created a video, and posted it on YouTube. Here it is, but I'll warn you that the lighting doesn't look very good.

Here's an image of one lightning strike and some fires that have been started in the trees and grass. Keep in mind that I haven't worked on lightning in many years.

Original lightning paths were mostly vertical, heavily overlapping, snapped to a grid, and not very realistic.

There are several problems here. First, the lighting is too vertical. Some of the lines are entirely vertical and others are mostly vertical. Second, the individual paths are too close together. They should diverge rather than converge and intersect each other. Third, you can somewhat see the regular grid structure in the individual path vertices, which are spaced too regularly from each other. So of course I went back to try and improve the lightning path generation algorithm.

I won't go over the details of how lighting is formed and the physics of a lightning path. If you're interested, you can read about it here. I'm only trying to model cloud-to-ground lightning. In 3DWorld, I start with a uniform 2D grid of random charge distribution values in a plane at the altitude of the clouds. These represent charged ice particles during a thunder storm. Each lightning strike originates from the grid point containing the largest charge, and depletes the charge in a circular area around that point. This ensures that lightning doesn't start from the same location each time, and models real lightning charge formation to first order. Lightning rarely strikes the same place twice! This part of the system works fine and doesn't need to be changed.

A lightning strike is composed of a number of different paths that recursively fork from the main path and flow from the clouds to the ground in a random path. Any path that reaches the ground without going outside the scene bounds creates a fire and some smoke, unless it hits a water surface. (Yes, even when it's raining.) This sets the trees and grass on fire and will eventually burn the entire scene to black. Lightning hits also damage the player in gameplay mode, though I can't remember ever being hit by lightning while playing. This is probably because players are down below the level of the trees.

Each path is represented by a series of line segments, which are drawn as long, thin, camera-oriented quads. The vertices of adjacent quads in the path are connected together to from a sort of ribbon. These quads are textured with a Gaussian falloff alpha (transparency) value with mipmaps to make them decrease in brightness with distance and toward the edges of the path. In addition, the primary path's end point generates a high intensity point light source. Lightning strikes only last a few hundred milliseconds, but I'm able to freeze-frame them in place with a keyboard key so that I can get good screenshots.

The original algorithm generated paths by building a 3D voxel grid where each grid cell stored the direction of the nearest grounded object (tree, terrain, water, building, etc.) The grid was generated on the first lightning strike and cached for later use. Lighting would start at the point of highest charge and follow the shortest path to ground, with a bit of random variation mixed it. It stored a set of cells that had been previously visited so that each fork would follow a different path. Unfortunately, this often resulted in many of the forks following similar paths straight down to different parts of the same tree. It also had a noticeable grid pattern because each line segment was about the same length.

My new idea was to discard the 3D voxel grid and replace it with a downward biased random walk. A current direction is maintained at each step, initialized to pointing down in -z. Each iteration adds a random spherically distributed vector to the direction, re-normalizes it, and moves the path a random distance in that direction. The z component of the direction is negated if it ever becomes positive to keep the lighting pointed downward. This guarantees it will eventually reach the ground. If a direction is chosen that moves the path outside the scene bounds, a new direction is generated. Each iteration has a random chance of forking the path. The first path created is the primary path, which must continue until it hits a grounded object. This way the algorithm ensures there's at least one valid full path and one hit point. All other paths have a random chance of ending early, resulting in shorter segments.

Here is a lightning bolt generated using this algorithm. As you can see, the individual forks are well separated and hit at very different locations. They're no longer vertical and have more random segment length variation.

Improved lightning path using random walk algorithm and modified splitting constants.

However, this still isn't quite realistic. Lightning doesn't normally hit many places at the same time. There's usually only one dominant path the ground and lots of dead-end "feeler" paths that reached out but went in the wrong direction. These paths ionize the damp air, decreasing its resistance so that more current can flow. The air resistance is still high though. Once the path to ground is found, this much lower resistance channel allows a huge amount of current to flow, generating most of the light and energy of a lightning strike as the charge is sent into the ground.

I decided to try to model this effect. A final postprocessing step is run when all paths have either ended or reached the ground. The algorithm calculates the shortest completed path to ground and makes that the primary path, increasing the brightness by 2x. This is the path of least resistance where the majority of the charge will flow to ground as electric current. The other feeler paths are shortened to the length of the shortest path if there's enough distance from their last fork position. Any paths that reach the ground after this step are considered hits and generate fire and smoke.

Here are daytime and night time images created using the modified algorithm.

Lightning path with random walk and shorter segments that don't reach the ground. The primary path to the ground is brighter and spawns fire.
The same lightning strike as above, but at night, with fog and clouds.

I decided that I didn't like some of the sharp bends in the paths. As a finishing touch, I decreased the amount of random direction change added to each segment. Here are some night time images of the final lightning path code + constants. I haven't really decided if this is an improvement or not.

Lightning path with many branches shown at night, with area lighting effect.

Another nighttime lighting strike. Most of the scene lighting comes from the lightning.

Here's a newer video I recorded and posted on YouTube of lightning strikes at night. The rain looks much better uncompressed at native 1080p resolution. I don't know why it looks so bad with YouTube compression. I can freeze the physics simulation and catch lightning in mid-strike, though I don't get the point lighting effect on the terrain when it's paused. Each strike creates one or more fires in the trees and grass that will eventually spread and burn everything down.

3DWorld's lightning definitely has improved, but it's still not perfect. It's difficult to get a good trade-off between branching forks and jagged edges. If I set the random walk value too strong it tends to produce sharp turns, spirals, and self-intersecting paths rather than a regular forked tree like I see in many photos of lightning. It's difficult to find resources online for generating and drawing lighting. Maybe I'll get back to it later.

I might need to work a bit more on drawing the paths. Blending doesn't always work against transparent objects, it and would probably look better if the paths ended in something other than a sharp edge.

Fortunately, neither generating nor drawing the lightning takes any measurable amount of time, so there's no need to add complexity to optimize this system. That seems to be a pretty rare occurrence in 3DWorld.

As usual, the code is all on 3DWorld's GitHub project. The lightning source code is fairly simple and self-explanatory, and can be found here.

Saturday, June 1, 2019

Procedural City: Doors, New Building Types, and Infinite Buildings

This is another one of those update posts where I show various procedural city changes I've made in the past few weeks. I haven't done any one particular thing that's interesting and complex enough to deserve its own blog post.


I've finally added doors to houses. Each house has exactly one simple white door. If the house has a porch, the door is placed under the porch. Otherwise, it's placed on a random wall with at least some distance between the door and the other walls and edge of the house. Here is my first pass at adding doors to houses. (I've disabled the grass blades because they're too large relative to these houses and obscure the doors and first floor windows.)

Houses now have white doors under their porches or along a random side (if there's no porch).

At this point, the doors and windows ignore each other's placements, so they often overlap. That's a bit difficult to solve given how doors are generated on the CPU and windows are added in a shader during drawing. I suppose the easiest fix is to remove the bottom row of windows on the wall of the house that has the door. This can be done by clipping the wall geometry in Z (vertical) for the windows pass. However, it was actually more difficult than I expected to get everything to line up again. There was a lot of work with integer rounding and choosing correct scaling parameters to get exact multiples of windows in various places.

That change fixes the overlap case, but now leaves some empty wall space with no first floor windows. I guess it's an improvement. Maybe sometime later I can go back and add some extra wall sections to the left and right of the door. I expect it could be a lot of work to make the windows line up with the row of second floor windows above them. Anyway, it's good enough for now.

Same view with the bottom row of windows removed from the sides of houses that have doors.

New Building Types

I've added more building types. Non-rectangular buildings (cylindrical, triangular, 5-8 sided, etc.) can now have multiple levels and multiple overlapping sections. In addition, multi-section buildings can have roof details and antennas on their tallest section. This adds in some more complex buildings and introduces new variety to the building architecture. Here are some screenshots showing the new building types.

New multipart non-rectangular building types, from left to right: elliptical, cylinder with flat edge, and hexagonal.

New building types with overlapping elliptical/cylindrical sections.

One of my favorite buildings, composed of multiple tall elliptical cylinders with flat sides. There's another interesting building with a large curved face behind and to the left.

Infinite Buildings

I did some experiments with my older city system where buildings are placed within a large region. This is similar to the secondary buildings where there are no roads, but in this case buildings can also be rotated. I was able to increase the building count up to 270K for that scene. That's a lot of buildings! It took over a minute to generate them and used about 600MB of building data. However, once the buildings were generated, 3DWorld was able to draw them just fine. They're not all visible at the same time, but it still looks impressive to see them drawn out to the horizon. Here I've removed the terrain and fog so that you can get a better idea of just how many buildings this is. Larger buildings are in the center, and smaller buildings and houses are further out in the background.

~70K visible buildings from the set of 270K drawn at around 100FPS. The terrain and fog have been disabled to get a better view of the buildings. The gaps are areas of water where there are no buildings.

That's a lot of buildings, but we can have more. How many more? How about an infinite number. The next thing I'm working on is "infinite buildings" mode. In this mode, buildings are generated incrementally in tiles that become visible to the player as the player moves around in the world. That way, cities can be unlimited in size rather than limited to the initial building placement area. This won't work for city grids with roads, only the unconstrained buildings shown in older images and the secondary buildings shown in the previous post.

This mode is intended for use with procedural terrain rather than fixed heightmap terrain. Building generation is fast enough that I can probably pre-generate all of the buildings for any size heightmap that can fit in memory. I've verified that I can generate 40K buildings in a few seconds to fill the 7Kx7K = 50M pixel island heightmap. My 270K buildings can probably fill a 16K x 16K = 256M pixel  heightmap.

Now, that does mean I can't flatten terrain under buildings because that only works with terrain read from heightmaps, not procedurally generated terrain. The underlying heightmap values can be edited and updated in realtime. That doesn't work the same way with procedural functions. I'll have to solve that problem later.

I decided to start with generating buildings for each terrain tile at the same time the tile was generated, and also deleting them when the tile was deleted. That saved a lot of effort duplicating all of the distance update and visibility logic. I was able to get infinite buildings to work in a few hours. At first they were too slow to generate and draw, and it took me much longer to fix that problem. It's a lot harder generating and drawing buildings quickly when they're spread across 300 individual tiles. Here's what I have at this point:

Buildings generated for each visible tile, for any tile the player can walk or fly to.

Yeah, it doesn't look any different from "regular" buildings mode. That's the point. You get the same quality, but you can walk forever in any direction and never reach the end of the buildings. Collision detection, shadows - everything just works. This was one of my long-term goals for 3DWorld. Now I just need to figure out how to add roads, cars, people, etc. Should be trivial, right? I don't know. One step at a time.

Here are some stats. There are between 298 and 316 tiles at any given time, and around 75-80 of them are visible for a 60 degree field of view. Each tile contains an average of 57 buildings for the parameters I've chosen; that's 17K-18K active buildings. There are about 20 different building materials, each with different sets of textures, and about 50 total textures including normal maps. Building tiles take an average of 2.7ms to generate and the entire thing takes 2.3ms to draw. The generation time is acceptable because it's rare to generate more than one tile per frame, even when moving at max speed.

Drawing requires 5 passes:
  1. Draw distant buildings with a simpler shader.
  2. Draw distant windows on top of distant buildings using different shader parameters.
  3. Draw nearby buildings with a more complex shader that includes shadow maps.
  4. Draw nearby windows.
  5. If night time, draw window lights using a different shader.
In some cases the same building may be drawn in both steps 1+2 and 3+4. It took quite a bit of effort to organize all of the drawing passes, view frustum culling, sorting by material, combining vertex buffers, etc. to get the draw time down to 2.3ms. I'm sure there's still some room for improvement, but at this time building generation and drawing are fast enough.

3DWorld is open source on GitHub.

Saturday, May 4, 2019

Procedural City: Secondary Buildings Update

I'm still working on secondary buildings for 3DWorld's procedural city. I've made various minor improvements since the last post:
  • Added porch roofs to some houses.
  • Added garages and sheds to some houses.
  • Made the antennas on building roofs pointed and darker.
  • Reduced building draw time by more than 2x.
  • Various minor fixes to house placement and drawing.
  • Added logic to keep buildings from overlapping user-placed 3D models.
  • Added logic to keep buildings from being placed over the player start location.
House roofs and porches are simple geometry added to the building models. Porch roofs consist of a small, low roof placed about halfway down on the inside corner of L-shaped houses, plus a thin vertical support cube. Garages and sheds are really the same thing. These are additional smaller cube structures placed separate from the main house for L-shaped houses that may or may not have windows. The random number generator is used to choose sizes and placements of these objects. Here are some images showing examples of these new features.

House with covered porch (front) and house with shed (back).

House with garage (left) and house with covered porch (right).

I made a few changes so that user-placed 3D models interact correctly with buildings. The most important change was to prevent the building placement algorithm from placing a building that overlaps the XY bounding box footprint of any 3D model. Collision detection (for the player) somewhat works with models placed in tiled terrain mode. 3D models already project correct shadows onto buildings and themselves. However, buildings don't project shadows onto models yet. This is difficult due to the transformed coordinate space of the models, and the fact that models can be larger than terrain tiles. This limitation forced me to choose a model that was larger and higher than the buildings.

A Ferris wheel seemed like a good fit. It took a while to find one online that was free, in a file format that 3DWorld supports (obj and 3DS), and didn't have any issues. The model I used has no textures, so it's completely white. Well, I suppose that's pretty common for a Ferris wheel. They tend to be mostly made of white painted metal. It looks a bit odd though, because the cabins, base, and and smaller details aren't textured. Maybe I can add colored lights to it later. That would actually look pretty good at night. Anyway, here is what the Ferris wheel looks like when placed near a city.

Ferris wheel model placed in the city scene with interesting shadows. Buildings avoid overlapping it.

Note that the model flattens the terrain underneath it just like buildings, producing a depression around it's bounding box. There are no buildings overlapping the Ferris wheel.

There's quite a lot of geometry in this city scene now. We have the terrain, buildings, grass, trees, clouds, benches, roads, bridges, tunnels, cars, pedestrians, and placed models (the Ferris wheel). Here's a wireframe screenshot showing the high geometric density of the scene.

Wireframe models of Ferris wheel, buildings, city grid, terrain, and grass showing geometric complexity.

The grass blades seem to produce the most geometry, with a few million grass blade triangles in this view. There are about 250K triangles in the Ferris wheel, about 2M triangles in the terrain, about 500K triangles in the buildings, and maybe a few hundred thousand triangles in everything else. Many of the objects have occlusion culling enabled, which improves draw times. Both the terrain and buildings can act as occluders. I get almost 100 FPS (frames per second) on my GTX1070 for this view.

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.


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


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.

Sunday, March 17, 2019

Pedestrian Animation Update

This is a quick update. I made some improvements to 3DWorld's pedestrian walking animations that were introduced in the previous post. I've added a knee joint to go with the hip joint on each leg. This looks much more natural than any of the strange animations from last time. I'm still applying the exact same animation code to all three models.

It's not perfect though. Some of the models have their legs spaced out too far for a casual walking animation. Also, none of their arms move. Real people swing their arms at least somewhat while walking, and also move the other parts of their bodies a bit. Still, it's good enough for now. I've gotten the basic animation down. That's 90% of the way there with 10% of the work.

I'll continue to add new models of people, improved walking, and new animations in the future. In fact, I've already added one new model of a man since recording this video. The model looks good and has high quality textures. However, the animations don't quite work because the area between the bottom of his shirt and the top of his pants stretch in an unnatural way. I'll get back to it later.

Once again, the code can be found here in my 3DWorld project on GitHub.