Sunday, June 18, 2023

Procedural City Stop Signs

Up to this point, 3DWorld's procedural cities have traffic lights at every 3-way and 4-way intersection for both roads inside the city and connector roads between cities. This works well for cities that are full of cars, but it may be overkill for residential neighborhoods with lighter traffic. Stop signs may be a better fit for these situations. I've added stop signs to residential cities, except for the intersections with roads connecting to other cities, which continue to use traffic lights.

It was easy to find a stop sign texture to use. Each sign is a two sided textured quad with the red "STOP" texture on one side and a white octagon on the other. The sign is placed on a square post, with an additional smaller "4-WAY" sign underneath the main sign at 4-way intersections. These are placed at all corners facing cars that will be entering the intersection. Stop signs are positioned close to where the traffic lights would be and can mostly use the same pedestrian and player collision detection system.

The next problem was adding street signs. I really like how every road has a unique procedurally generated name, but there's no traffic light to attach the signs to. It doesn't look right adding the street sign to the top of the stop sign with a vertical extension. So instead I added a second, taller vertical pole just behind the stop sign with the street name on a green horizontal banner at the top. I had to make this high enough that the largest vehicle (the truck) can pass underneath.

Here is an example stop sign on a 4-way intersection with cars and pedestrians enabled.

A 4-way stop sign with a street sign above and behind it. Cars and people are both waiting to cross.
 

The most difficult step was writing the traffic logic that controls cars reaching stop signs. As with traffic lights, the only real function of this stop sign logic is to tell each car that's about to enter the intersection whether it must stop or can proceed. Once the car is in the intersection, it's free of the intersection control logic and only subject to the car and pedestrian collision checks.

The first step is obvious: Each vehicle must stop at the stop sign, independent of the intersection state. This is accomplished by braking/decelerating when approaching the intersection, starting a timer when fully stopped, and waiting until 0.25s has passed before querying the intersection for permission to enter. This small time delay is enough to prevent a rolling stop. I may decide to make the wait randomly generated per-vehicle to add some variation.

The next step is to determine whose turn it is. We conveniently already have a timer recording when each car reached the intersection for stopping purposes. Each car will then check if there are any other waiting cars with earlier times that should enter first. This check only applies to cars that will cross paths, using the following logic:

  • If cars start at the same location, this is an error.
  • If cars end at the same destination (one of the 3 or 4 exit directions), they definitely cross.
  • If either car is turning right, they don't cross.
  • If either car is turning left, they cross.
  • If we got here, both cars are going straight. They cross if they're going in different axes (one north-south and the other east-west).

I later discovered that the trucks make wider right turns and will in some cases clip through other vehicles making left turns. So I had to add an extra step into the logic:

  • If either one is a truck, one is turning right, the other is turning left, and their paths are diagonally opposite each other, then they cross.

This set of cases appears to be correct. But it's actually more complex than this, because we also have to consider other cars currently in the intersection. My solution was to have cars register themselves with the intersection when entering and remove themselves when exiting. The intersection has 3 or 4 slots corresponding to its entry points that store the turn direction and is_truck flag for each car that's using it. Then the intersection must run the same logic above on any active slots that cross the path of the current car that is asking for permission to enter.

The next problem I ran into was a deadlock case where cars were waiting at each stop sign but no one was going. This took me a long time to reproduce, debug, and fix. I eventually had to add code to detect this case by looking for cars waiting for more than 60s, show where it was happening in the world, and print debug state for the intersection. It turned out that this was caused by cars blocking the intersection because there was no space for them to turn and exit the intersection. This was because cars were queuing up waiting at a traffic light to exit the city, and the line of cars was backing up all the way to the intersection. This in turn was causing the car attempting to enter the intersection to stop while partially inside. The problematic car had already set the "entering intersection" flag for that lane/direction as it had started to move. But when transitioning back to a "waiting" state while space for it to turn became available, it was actually blocking itself from continuing when it was able to. The fix was to have a car clear it's own intersection usage state when stopping while inside and intersection. This will also allow other cars to continue while one car is blocked, which may or may not be correct. I think this is okay because we know they can't pass the initial car as the destination spot is known to be blocked by another car. Therefore, they must be waiting as well, and only one car can claim any spot that opens up.

This overall solution mostly works. There are still some rare cases when cars spawn inside an intersection, or a lag in frame rate causes them to cross through an intersection without properly registering a matching enter + exit event. If left unchecked, this can lead to deadlock where none of the cars can enter. I think one correct fix is to record time stamps for entry events and automatically remove them after a few seconds in the per-frame logic update pass of each intersection. However, I haven't seen this happen after some other tweaks, so it's either fixed now or very rare. I may have to let the simulation run for hours in the background to see if anything fails with the stop sign logic.

Here is a video showing cars following stop sign rules at an intersection. The only issue is that trucks cal still get too close to cars when turning. This can lead to odd behavior as they attempt to avoid collisions that shouldn't actually be possible. I haven't come up with a good fix for this, so I'm calling it done for now.



Wednesday, June 14, 2023

Procedural Building Additions, Interior and Exterior

Once again I have a number of procedural building changes that are too small for their own blog post. I'm working on stop signs, which is a larger topic, but they're not done yet. This post will list the various additions I've made to building interiors and exteriors.

Fires

I showed off the spark particle effects that were added for broken TVs and basement lights in a previous post. When I reviewed that video, it made me think that all of those sparks landing on the rug should set it on fire. So this is what I implemented. Now a spark landing on a rug while it's still hot and glowing has a chance of starting a small fire. I haven't worked out how to handle large fires that spread to the rest of the building, so for now the fires will go out after a few seconds. They do, however, leave lasting burn marks on the rug.

Fires also serve a minor gameplay purpose. In the (unlikely) event the player starts a fire and then walks through it in game mode, they take some small amount of burn damage. This provides a minor distraction from other gameplay tasks and forces the player to pay more attention in rooms with broken lights. Other animals such as rats and cockroaches have updated logic that attempts to avoid the fires. I haven't yet updated the building AI and zombie logic to avoid fires. I feel that zombies should be able to walk through small fires to get to the player.

Here's a short video showing fires created from sparks in the same room as the earlier sparks video.


Attic Vents

I wrote about 3DWorld's interior-exterior geometry in a previous post. This is where "room" objects can be added to building exteriors and will be lit from the sun and moon outdoor lighting rather than interior room lights. I used this a few weeks ago to add window frames and window sills. Now that I have this system in place, I can use it for more exterior detail objects.

One object I'm missing is exhaust vents that pass through the attic and its roof. I added these for furnaces, water heaters, and stove hoods. These are simple pipes that are split into two sections with the lower section inside the attic using interior lighting, and the upper section on the roof using exterior lighting. The vent sections inside the attic also participate in player collision detection and act as blockers for attic object placement. Anything I can do to increase attic clutter improves the realism of the scene.

Here is what these look like from both inside and outside the building.

House attic with a vent from the furnace on the left and another larger vent from the stove hood two floors below on the right.

The same two vents protruding through the roof with end caps that use sky/sun/moon lighting.

I may add more details in the future if I get around to it. Maybe I can make some of them have rotating blades like a fan? I might also add vents for the various plumbing fixtures such as sinks and toilets. I'm not sure exactly what needs a vent. My real life house has something like eight different vents on the roof of various sizes, and the roofs of my procedural buildings don't seem to have enough of them.

Parking Garage Sprinklers

I added large vertical fire suppression/sprinkler pipes to office building parking garages over a year ago. Then a few months ago I added smaller horizontal pipes that lead away from the main water pipe across the roof of each parking garage level. I finally got back to working on this sprinkler system by adding secondary horizontal lines that extend from these first lines. These pipes are placed relatively close together in a grid pattern that attempts to cover all reachable areas of the parking garage.

The placement system must check for intersections with objects such as stairs, elevators, and support pillars. I allow sprinkler pipes to pass through parking garage separator walls in a similar way to water, gas, and sewage pipes. I hung these lower than most other pipes so that they touch the bottoms of the ceiling support beams and stay out of the way of many other ceiling objects. They're placed after other types of pipes, so I need to check for pipe intersections as well. I wrote some code that is able to place partial sprinkler pipe sections in incrementally shorter lengths when the full pipe fails to be placed. In some situations, sprinkler pipes can clip through ceiling lights. I fixed this by a combination of moving the lights to the side and shortening the pipes. I would say that about 75% of the total pipe length can be added on average, which is good enough for now.

Next came the sprinklers themselves. I added upward pointing vertical sprinklers at regular intervals along the smallest diameter (last placed) horizontal pipes. Once again, I had to check for overlaps with other objects near the ceiling and omit the sprinklers in those cases. I also shortened pipes to remove extra segments that had no sprinklers or other connecting pipe sections. Short pipes that don't end at walls are attached to the ceiling with small metal loop hangers/brackets.

All sprinkler pipes are drawn as red cylinders with brass fittings, connectors, and end caps. The bright red color makes them stand out and adds contrast to the otherwise gray parking areas. Sprinklers are formed from three cylinders of different lengths, radii, and colors. I considered using real 3D models for each one, but I'm worried that too many will be visible in large parking garages and this will hurt the framerate. In some cases nearly 100 sprinklers can be seen in the player's view.

Here are two screenshots of a parking garage with pipes and sprinklers. The first is without cars, while the second is with cars and indirect lighting enabled.

Parking garage with a network of red pipes and sprinklers attached to the ceiling.

The same parking garage as above, this time with cars and indirect lighting enabled. I feel it's easier to see the pipes with this lighting.

Newsracks

This one was suggested by my mother. I've added newsracks along the sidewalks of some city streets. They come in four different shapes/styles and a number of different colors taken from reference images of real newsracks. These are all drawn with geometry generated from code, mostly cubes of different sizes. I added a fake newspaper image I found online to the transparent doors of each one. As usual, newsracks are collisions objects that block the player and participate in pedestrian path finding. At some point I may decide to make these interactive so that they player can open them up and take a newspaper. Maybe the player will need to find coins in a building to do so.

Here are two example images, again without and with cars.

An example city sidewalk with newsracks of various sizes and colors along the edge of the road.

More "The Fake News" newsracks, this time with cars enabled.

Rooftop Water Towers

A few weeks ago I did a Google search for other people's procedural buildings to see if any of them inspired me to do something new. One YouTube video showed buildings with rooftop water tower models. That seemed like something easy to add to 3DWorld's buildings that would increase the variety of their roof areas and improve city skylines. Water towers are relatively simple to model out of cylinders and cones for the tower and pipes, plus cubes for the support structure. So I decided to generate the geometry rather than using an existing 3D model from somewhere online. I used a metal plate texture for their exteriors and pipes.

Water towers are placed on some buildings above a certain height and a minimum rooftop area. These are skipped for buildings that already have helipads, skylights, antennas, or other previously placed objects. Water towers are placed before smaller objects such as AC units, signs, and roof access doors, so these objects must check for existing water towers before being placed. Each water tower is also connected to the network of water pipes in the basement, if present.

I may as well continue the trend with two images of the water tower and different sun positions. I added a vertical pipe under the tower in the second image. That Ferris wheel in the background is a great landmark for navigation!

Initial metal water tower 3D model created from a texture cylinder, a cone, and five cubes.

The same water tower viewed with a different sun position and a metal cylindrical pipe added to the bottom to carry water.

Pool Decks

At this point I had both in-ground and above ground swimming pools in the back yards of some houses in my residential neighborhoods. The above ground pools had ladders, but the in-ground pools were simply surrounded by grass. This isn't realistic. All of the in-ground pools I've seen, including the one in my own back yard, have decks around them. So I placed a randomly selected concrete or wooden deck on the ground between the pool and the house. In rare occasions there was some other object between the pool and house, so the deck is omitted in that case. I added some additional random variation that extends the deck to the length of either the house, the pool, or both rather than only inserting it between the shared edges of the two objects. Sometimes the deck will line up with the back yard fence, which I think is a nice touch. This was a minor change that was easy to add.

As expected, two images of concrete and wood pool decks. I think I need to add more details around these pools to make them look interesting.

Simple concrete pool deck placed between the house and a rectangular in-ground swimming pool, enclosed by a fence.

Another swimming pool with a long wooden deck connecting it to the house.

House Balconies

Some of the other procedural building posts and videos I looked at included balconies in their residential buildings. I decided to use the exterior geometry system yet again to add balconies to upper floor rooms of some houses. There are a variety of different balcony styles with wood slats, metal railings, and 45-degree rotated railings, possibly with metal trim of different colors.

Next, I added potted plants to some balconies. These initially didn't work well because the plant leaves aren't drawn as they're on the wrong side of the transparent windows. It took me awhile to rearrange the transparent and alpha mask drawing code to make this work properly. I plan to add small tables and chairs to balconies, but I haven't gotten around to doing that yet.

Balconies are somewhat incomplete at this point and have some issues. First, they're not actually connected to the houses with a door, so the player can't walk out on them. Adding this type of door appears to be complex and difficult. I have the same problem with fire escapes. It may require significant changes to the building creation control flow because currently the balconies (and fire escapes) are added after the doors and windows.

Second, the lighting and shadows aren't quite right. Since balconies are between the exterior and interior, they should have interior light shining through the windows onto them. At this point they don't. Balconies receive shadows from the house but don't self shadow because room objects don't contribute to the sun and moon shadow pass. This also means they don't shadow the rest of the house or the ground below them. I don't have a good fix for this, so I'm hoping the player doesn't notice. I actually didn't notice the lack of shadows at first.

I'll add several screenshots this time since balconies come in so many varieties. I also changed some settings and fixed a few things (like the missing plant leaves) in the process of taking these.

A house with a small balcony with white metal railings and an empty flower pot. The edge (non-corner) railings are rotated 45 degrees just to show I can add shapes other than axis aligned cubes!

Balcony with wooden slat sides and black metal railing and edges.

A longer railing along the side of a house, this time with a black metal railing and bars. This one has two "empty" flower pots.

A balcony with wooden sides and a brown railing, with two flower pots. These ones have actual plants because I fixed the alpha mask material drawing to work outdoors.

I should probably add vertical posts to support the corners of some of the larger balconies. That means I do have to figure out how to enable collision detection for what are supposed to be indoor room objects that happen to be placed outside the house. The lack of shadows may also be more obvious when I add the posts. I'll have to experiment with this later.

I think this post is long enough now. The next post will probably be on the topic of stop signs.

Monday, June 5, 2023

Cockroaches in Buildings!

I can't resist adding another "animal" type to 3DWorld's procedural buildings. It was a lot of fun (and also a lot of work) to add rats, spiders, snakes, and flies. Now that I have all of the framework in place for animal drawing, animation, physics, collision detection, behavior, etc., it should be easy to add more animal or insect types. Cockroaches are somewhat of a cross between rats and flies. (Well, assuming you only have the four animals/insects mentioned above to work with.) They walk on the floor and run away when scared like rats do. Their placement and drawing code is closest to that used for flies. I was able to reuse enough code from existing animals that it took me less than a week to add cockroaches, compared to several weeks for rats and spiders.

Cockroaches have some unique behavior characteristics. They only spawn in dark rooms away from the player, building AI people, and zombies. They have a random walk => stop => turn cycle similar to rats with some degree of random speed variation. When they're startled by a light, a sound, the player, or another person, they immediately run toward the closest wall in a direction away from whatever scared them. When reaching a wall or other object flagged as a hiding spot, cockroaches disappear inside and are respawned somewhere else in the building. Their new location will be somewhere dark and out of view of the player. If they instead hit an object they can't hide under, they turn away from the object, suspend their fear state for a few seconds, and walk in a random path.

So far I haven't assigned any gameplay purpose for cockroaches. They don't affect the player or zombies. The player can't pick them up, but they can be squished by dropping objects such as books on them the same way as spiders. However, it's quite challenging to squish cockroaches due to their fast speed, small size, and ability to hide under objects. Maybe I should track kill counts for both spiders and cockroaches. As a placeholder for this, I add $10 damage for each squished bug for building cleaning costs. (For reference, cleaning the blood stains from a player death is $100.)

I originally drew cockroaches as simple stretched brown hemispheres: long and flat. I didn't bother to add legs because it was difficult to get close enough to see them. Later, I decided they looked too plain, so I found a 3D model online that looks much better. So far I haven't felt the need to animate their legs because they're so small and move so quickly. The 3D model rendering code is almost identical to that used for rats, in particular because they're both always oriented in the XY plane on the ground.

Here's a video showing a building with 1,000 cockroaches. They scatter when I turn on the light and approach them. Note that these are drawn at an incorrect height and their legs are under the surface of the floor. I've fixed that in the other screenshot and video below.

And here's a screenshot showing the 3D cockroach model I used. Yeah, it's pretty small and hard to see.

Cockroach on the floor, drawn with a 3D model.

Here is a video showing me attempting to drop books on cockroaches to squish them. It's challenging and took me a number of tries to get the first one. They have yellow blood!

Do you have a suggestion for what animal or insect I should add next? If so, please leave me a comment.