Saturday, May 9, 2026

Procedural Park Restrooms, etc.

In this post I continue my work on parks from the previous blog post. Before I get into bathrooms, let me discuss some of the smaller park additions and improvements I made first. In reality I worked on some of these changes at the same time, alternating between code edits.

I did eventually get hills working in parks. I had to add collision avoidance for AI people, include them in blockers for placing other objects, and adjust the elevation of previously placed trees to move them on top of the hill. (Trees are added first since they're part of the terrain.) I added player collision with hills by interpolating the Z-value of the player position from the nearest heightmap corners. This also allows the player to walk below the water in ponds, which means that I no longer need to block off that area for the player.

My daughter suggested adding fish to the ponds, so that's what I did. I split the class that handles fish in building fish tanks, pools, and flooded basements and created a city version for use with ponds. The only major difference is that fish are constrained to a bowl-shaped area rather than a box shape. They swim around in the pond and occasionally change direction, but otherwise ignore the player. They don't run from the player like fish in the ocean.

Residential parks now have cube map reflections enabled. I previously only had reflections in commercial cities because some of those office building types used reflective exterior materials. This has changed so that reflections are always enabled when the player is in parks in any type of city.

 

Park Water Fountains 

Next, I added water fountains along park paths. I wanted to add those green metal water fountains with the lower dog water part that I see in the parks around my house. I believe this is referred to as the "Fido and Me" fountain. Apparently these cost $4000? Crazy! Anyway, I couldn't find a free 3D model of one of these, so I had to construct them procedurally from cylinders, cones, and a few cubes. They have cube map reflections enabled with a painted metal material. So far I haven't made these fountains interactive for the player.

Park water fountain next to a walking path and some picnic tables.

Here's another water fountain, this time with a sneak peek of a park restroom in the background. I'll get to restrooms below.

Park water fountain with restroom in the background. More on this below.
 

Park Restrooms 

I added small restroom buildings to parks containing two rooms, one for men and the other for women. These are placed so that they don't overlap any ponds, creeks, park paths, trees, etc. Yes, trees are placed first. We don't want to be cutting down trees to build restrooms, right? There's a constraint that no two restrooms can be placed within a block of each other, so two parks on adjacent blocks will have one shared restroom. Restrooms come in two flavors: doors in the front, and doors at the sides/ends. I initially couldn't decide which I preferred, so I added a 50/50 chance for each style.

Let's start with the exterior. These buildings use a similar system as gas station convenience stores. They're owned by the city system rather than the buildings system. This means the placer has complete control of all parameters rather than relying on randomness to choose the size, shape, and material. The size is fixed with an aspect ratio of 1.25:1. Technically this is the "house" floorplan type. I used a random selection from the concrete block and brick exterior wall set and a sloped ("peaked") roof style. Each interior room has a single exterior door with a sign next to the door indicating gender. I added wooden privacy fences next to the doors. Restrooms with both doors on the front also have a concrete patio area between the fences and a water fountain mounted on the wall in the middle. Like this: 

Closeup of the park restroom from the previous screenshot. This one has both doors on the front and a water fountain between them. Walls are concrete block.

One downside of having restrooms placed by the city object placer inside parks is that they don't automatically get connected to the power lines. However, I was able to update the power line logic to connect restrooms with power but not cable TV wires relatively easily. Technically they also don't connect to the underground tunnel/sewage system either, though they don't have basements to begin with.

Restrooms with doors at the ends have their gender signs on the adjacent walls, and fences directly across from the doors. Maybe I should add a concrete patio at each end as well? The limitation here is that I'm actually drawing these as driveways, which means I can have only one. I did attempt to add the driveway under the entire building and that seems to work, assuming there's no basement. I haven't updated the screenshot though.

Both styles of restrooms have long, thin, and high windows along the walls that don't have doors. I had to make them high so that they don't overlap with objects placed inside such as urinals and hand dryers. These are glass block windows that let light pass through but the player can't see through. 

Second variant of park restroom with the doors at each end.

Pedestrians will choose these buildings as destinations just like normal houses and office buildings. I did add the logic for women to choose the women's room door while men choose the men's room door. Parks are neutral territory not owned by anyone, which means that people can walk through them at any time, as long as they avoid colliding with buildings that aren't their destinations.

After I added those two screenshots above, I realized that the doors don't look right. House doors don't fit with restrooms. I later changed them to use door textures from office building interiors, which I feel is a better fit. I took one new screenshot, shown below.

Park restroom with office style doors that open outward. This one has brick walls.

I also changed restroom doors so that they open outward rather than inward. The restrooms in my local park all open outward. While I was at it, I changed some other types of buildings such as restaurants to open outward. I think every building type other than houses should have doors that open outward for fire safety. The only problem with this is that the interior door handles don't have correct lighting or reflections when they rotate outside the bounds of the building. Now that I think about it, I should add exterior door handle 3D models as well.


Restroom Interiors

Park restrooms have the same plaster walls as most other buildings because I don't have a good alternative. I could make the walls smooth and untextured, but that would look boring. Floors and ceilings are bare concrete. Maybe ceilings should be high and reach to the peaked roof? It could be similar to attics with metal rather than wood beams. That sounds like a lot of effort though. I'll probably at least attempt it.

I've made some improvements to restroom interiors. Note that these apply to all multi-person building restrooms (office building, restaurant, park, mall, etc.) Stalls now have metal trim, hinges, and door latches. These look much better now that I have proper (though distorted) interior reflections. There are four paint colors for stalls: light blue, light green, light gray, and dark gray. Here's a new screenshot of light blue bathroom stalls with shiny metal hardware.

New bathroom stalls with shiny metal trim, hinges, and door latch.

I added three new bathroom objects: paper towel dispensers, soap dispensers, and hand dryers. These are all drawn as 3D models I found online because the shapes were too complex to create with code. Or rather I've done enough of this lately and I wanted to take a break after the water fountains, etc. They're placed on the walls of larger bathrooms that have been divided into stalls. I should probably add some of them to the small bathrooms as well for non-residential buildings. ... There, I've added paper towel and soap dispensers to single use office bathrooms.

The paper towel dispenser is placed first, in the middle between the sink/mirror and the door. It's added to whichever wall has more space. I believe there's always room to place the paper towel dispenser. Or at least I haven't come across a bathroom where it's missing due to placement constraints.

The hand dryer is next added to the door's wall, between the paper towel dispenser and the door, if there's space. In the case of interior rooms with doors that open inward, the dryer is placed to avoid the path of the opening door. I added it closer to the door in the case of a wide bathroom with a long wall.

Finally, soap dispensers are placed between the paper towel dispenser and the sink mirror if they fit. This usually only happens in bathrooms with a gap between the door wall and the sinks. There's no gap for some of the short-but-wide bathrooms that are added to office buildings. Park restrooms are fixed size and large enough, so it should always be possible to place all three objects. 

Park front entrance restroom interior showing the new hand dryer, paper towel dispenser, and soap dispenser together by the door.

Here's another view that shows the entire park restroom interior with (old texture) door, window, stalls, and sink in the back. The hand dryer is visible on the far wall under the window. Oh, I almost forgot. I also added those shiny cylindrical trash cans previously seen in malls to larger bathrooms.

Park side entrance Women's restroom with black (very dark gray) stalls and high block window.

Park restrooms have lower lighting levels compared to office buildings. Part of this is just due to the lower color temperature, which makes the light more yellow compared to the bright white of commercial spaces. The other reason is because park ceiling lights are smaller. I had to restrict their size to avoid the door clipping through them back when doors opened inward. (Take a look at the door and light position in the screenshot above.) Park restroom doors sometimes open into the short side of the room, while office restrooms usually have their doors at the long end near the sinks and urinals.

Here is what an office building restroom looks like for comparison. Note that these have the same object additions as above. Some wider rooms have sinks, paper towel dispensers, hand dryers, and soap dispensers on both sides of the door.

Office building Men's restroom with brighter and higher color temperature lighting.

I think I'm mostly done with bathrooms for now. I need to go back and work on door handle models, and maybe make a few other minor changes.

Friday, April 10, 2026

Nature in Procedural Cities

I'm switching back to cities after working on buildings for a while so that I can add more nature elements. Specifically, I've added creeks to city parks and ivy to house walls. Both of these are pretty simple effects, but they took a surprising amount of time because they're so different from buildings. Natural/organic elements are generally more difficult than cube-shaped man made objects. I also feel like plants and water are easier for people to find flaws in since they're so common.

Creeks

One or more parks are added to both commercial and residential cities. Parks currently have one or two curving walkways and an optional pond. Ponds only occurred in around 50% of parks. I do like them, especially now that the water is reflective, so I increased this to more like 75% by doubling the number of placement iterations from 100 to 200.

Ponds are drawn in several passes using different textures and effects. The ground is formed by a cone shape to create sloped sides and a flat bottom, with a darker color circle on the bottom to add fake light attenuation with depth. (I didn't use the same water shaders I had in buildings because I didn't want the runtime overhead and complexity of switching shaders while drawing city objects.) Water is drawn as a partially transparent textured oval on top of the pond as the last step so that alpha blending works. This is done before drawing the park terrain quad, and has depth writing enabled, so that the ground isn't drawn over the pond. The result is a hole cut into the terrain where the interior geometry is visible.

I wanted to add creeks flowing across parks, under the walkways, and into these ponds. I reused the same sine wave path logic that I had been using for park paths to create the shape of the creek. That was easy, but drawing it proved to be more difficult. My first attempt was to do something similar to ponds with a sloped ground layer on the bottom and a partially transparent water surface drawn as a path on top. However, this presented some problems. First, it's not easy to create a sloped shape for a curved path that forms a hole free mesh and blends correctly with the existing geometry, including the edge of the pond. Second, the two water layers don't join nicely where the creek meets the pond because the intersection is an ellipse formed from straight sides. And third, the trick of using a depth write to mask off the terrain under the creek causes problems with the walkways, which should be drawn over the creek and not masked off.

After making several attempts to correctly render the creek, I gave up and decided that it had to be done with actual geometry rather than the depth masking approach. And the solution to joining the creek with the pond was to drawn them both as a single textured quad that covered the entire park. But this quad had to be drawn below the terrain height rather than above it so that it was under the park path. To do this, I needed to add proper heightmaps to parks instead of drawing them as single flat grass-textured quads.

Park Heightmaps

The general idea was to create a mesh as a 2D array of height values, similar to the way the tiled terrain was drawn. Except parks don't align to terrain tiles, they're not necessarily square, they don't use the same shader, and so on. Interestingly, the closest code I could find to draw this was the code I used to draw ... pillows! (Yes, the pillows placed on house beds are in fact 2D height maps using curve functions to shape them.) So I factored out the shared code and reused it when creating parks. I initially used a heightmap size of 128x128 to match the terrain tiles (compared to only 24x24 for pillows), but I later decided that 256x256 looked better. I needed at least several texels of creek width to get reasonable edges. These heightmaps are only drawn when the player is close to a park, and there's usually only one or two parks visible, so the added frame time is negligible. Distant parks continue to be drawn as flat planes with the creek skipped.

The park heightmap is initialized with all heights set to the park/city elevation. The pond is added by lowering height values using a X/Y weighted 2D sine function that produces an elliptical perimeter where the edges gradually slope down to the lowest point at the center. The creek is added by lowering the terrain along its path based on the distance to the creek center line. The code is similar to how I level the terrain under roads. I added custom vertex coloring so that grass at higher elevation remains green, while lower values transition through a brown dirt color to complete black at the deepest part of the pond. An example pond is shown below.

City pond drawn with the new park heightmap system, with city reflection.

Creeks need more work. They're shallower than ponds, which means the bottoms are brown dirt rather than black. That seems okay. But the banks are jagged rather than smooth because the creek is only a few height samples wide, which means the underlying 2D grid shows through. I initially attempted to fix this, but eventually gave up and accepted the fact that this makes it look more "natural".

I still had to handle the case where the creek passed under walkways and the sidewalk along the road where the park ended. I decided to add a cylindrical metal pipe to both locations with the same corrugated steel texture I was using for buildings. That looked acceptable, though the walkway was obviously a flat plane as it had zero thickness. So I added a bit of thickness by drawing the sides of walkways, which looked better even in areas where there was no creek. Maybe it's still too thin? The pipe doesn't align exactly with the creek and has water above it, but it's good enough for now.

If I turn around I can see the creek feeding the pond, which goes through a pipe and under the walkway.

Creek vs. walkway crossings only look good when they happen at nearly right angles. In some situations I saw creeks meet up with walkways and continue partially under them for some distance, which looked wrong. What orientation was the pipe supposed to be in? The fix was to check for intersections between the creek and walkway paths and calculate their angles. If the angle is outside the range of about (70, 110) degrees or the paths crossed multiple times within a small area, the creek is rejected. The placer makes up to 100 attempts to place a valid creek until it gives up. I've only seen one park with two very windy walkways where the creek can't be placed.

Residential park creek that crosses under walkways three times (two visible).

Another nice property of park heightmaps is that they should allow me to add other features such as hills in the future. The reason I haven't added hills yet is because pedestrians currently assume all of the city is a flat plane. They'll clip through the hill when walking near it. I may be able to fix this by adding pedestrian colliders for hills, but that's a task for some other day. Oh, and I'm sure I would have to fix the player collision for hills as well. And adjust park path, tree, bench, and picnic table placement - you get the idea. Like this:

First attempt at adding a hill to parks. See, there are problems with the tree already.
 

The terrain doesn't cast shadows because there's not much below it to shadow. I actually didn't even think about shadows until writing this post. Maybe the water passing under walkways should be shadowed, but it's not very noticeable. I would probably need to add shadows if I place hills in parks. Update: After writing this, I did go back and change walkways to cast shadows over creeks. It doesn't make much of a difference.

 

Hedges

Next, I was inspired by some procedural ivy posts on Reddit and decided to add ivy to the concrete walls separating the yards of some houses in residential cities. I started by copying the class that draws the leaves of hedges near the player, since it's similar to how I want to handle ivy. Have I shown hedges in this blog yet? I don't remember, I'm up to 190 posts! Maybe not, so I'll go over this briefly now.

There are three types of residential plot dividers: hedges, walls, and fences. Well, technically there's also "none" for some blocks. Fences can be either wooden or chain link. Plot dividers are currently all represented as boxes with five of the sides drawn (excluding the bottom). Oh, four for chain link fences since they're thin and have no tops. Hedges don't look particularly convincing as simple textured boxes, so I added a randomly generated cluster of 40K leaves around the perimeter of the shape to give them some volume and improved shadows. Leaves use the same texture as the flat quads so that they blend together well. There's a single instance of this "leaf shell" that's translated, rotated, and scaled to fit each hedges box. They're only drawn for hedges close to the player as an optimization.

Hedges added to residential yards, drawn as textured boxes with additional random leaves with random orientations added using the same texture.


Ivy on Walls

I factored out a base class for vegetation drawing that could be used with both hedges and ivy. Note that I wasn't able to reuse the existing system I had for drawing terrain plants for a number of reasons: different shaders, placement on objects rather than terrain, generated with cities rather than tiles, can't easily use instancing for ivy, etc. I felt that I had to create a new system here that fit into the city drawing framework.

Each residential city has its own ivy manager class. Since cities are spaced out over the terrain, only the nearest visible city needs to draw its ivy, which means I can clear any ivy from the previous city when the player moves to a new one. A city has multiple blocks, each block has multiple residential plots, some of which have walls, with two sides, with multiple ivy plants. Except ivy is only placed on a subset of the possible wall faces for performance reasons. I suppose that's realistic as well, since most walls aren't covered in ivy. I walk down the object hierarchy and randomly skip some of the nodes when placing plants.

Ivy is generated per-wall. All walls within the nearby player view area are evaluated and any necessary ivy geometry is created and stored in a map using the wall index as a key. Each individual ivy plant is unique and customized to fit its wall and any surrounding plants that were generated earlier. Ivy is represented as a set of branches formed from connected series of cylinder segments and randomly chosen split points. A root location is selected as the starting point for each plant, and a branch is constructed using a random path. 4-8 additional branches are generated from a randomly selected point along a previous branch. Each new branch uses a radius slightly smaller than the branch is was split from. Consecutive branch cylinders are joined cleanly by merging their vertices at shared path points, similar to how I draw tree branches. Each branch end with a cone that forms a point.

I added a constraint that branches must always move upward to reach toward the light. That's not always true with real ivy, since it tends to sag and fall over time. But I found that rule made the results look cleaner, lead to fewer branch intersections, and avoiding the need to check for collisions with the ground. The only exception is when a branch is split from the bottom side of an existing branch that's somewhat horizontal. In that case it will still have an upward bias that will take effect over time as new cylinders are placed. This rule tends to produce ivy in a somewhat inverted triangular shape that's narrow at the base and fans out to a wide top.

Leaves are added along branches on alternating sides with a random rotation away from the wall. The rotation reduces the chance of two nearby leaves overlapping. Each leaf is drawn as a flat quad with two triangles. Leaf size is random within a small range, except for the ends of branches, where smaller leaves are added. Branches check for intersections with other branches of the same vine, while leaves check for overlaps with other leaves. I allow two nearby ivy plants to intersect because it's difficult and expensive to check for this. Leaves are allowed to overlap slightly since their textures don't cover the entire quad. Branches are also constrained to stay within the bounds of the wall, leaving some area open at the ends where the wall meets other walls, fences, or hedges. Leaves can only extend outside the wall bounds at the top.

Multiple ivy plants growing up walls that enclose the backyard of a house.

The final step was to allow ivy to wrap onto the top of the wall. This works by effectively rotating the placement plane by 90 degrees to the top surface and continuing branches that extend off the top of the wall. Some ivy plants don't extend high enough to wrap along the top of the wall. Since the branches bend at sharp angles close to 90 degrees at the edges of the wall, I draw an extra sphere to connect vertical to horizontal branches. All of this took me quite a few attempts to get right.

Ivy modified to grow over the tops of walls.

I did also consider having ivy wrap around the sides of walls, but that's quite a bit more difficult. Some walls are adjacent to other walls, so I would at least need to track which wall ends are open. And I'm generating ivy on both sides of the wall independently, which means I don't know where the existing ivy is on the other side when a branch wraps around the wall. So I haven't yet added this behavior.

Another future improvement is to add proper transmissive lighting for ivy leaves. I already use this approach for tree leaves. This works by calculating an attenuated lighting value for the side of the leaf facing away from the sun rather than leaving it dark, to simulate light passing (scattering) through the leaf. I haven't added this because the shader that supports it doesn't have some of the other features I want for cities. 

Wednesday, March 11, 2026

Procedural City Car Washes, Service Stations, and Convenience Stores

I've been working on various optimizations and improvements to 3DWorld's building indirect lighting and reflections. There's not much to show or explain in a blog post though because it's mostly technical details. Everything is faster but looks similar. I did continue working on city gas stations on and off over the past month. I've added some other smaller buildings around the gas stations: car washes, service stations, and convenience stores. I'll show my progress on each of these building types below.

Car Dirt

The first type of gas station sub-building I added was the car wash. But wait, we can't have car washes without dirty cars. I added a dirt shader effect that's applied to car drawing using 3D volumetric noise at two different size scales to add both large and small dark spots of dirt to car exteriors. This is similar to the shader used to draw wet areas onto extended basement walls, ceilings, and floors. A dirty car is shown below.

A very dirty red car about to enter the car wash.
 

Cars start with a random amount of dirt between 0 and 1, and it increases slowly over time while the car is moving. When dirt exceeds 0.5, the dirty shader effect starts to show, with dark areas growing in size and frequency as the value increases to 1. When max dirt is reached, the car will attempt to reserve a spot at the nearest car wash. The dirt value decreases back to 0 while the car is being washed. Dirt does not apply to ambulances, and trucks have a lower dirt cap because they're too large to fit in car washes. I haven't yet applied a dirt effect to cars parked in building parking garages because they have no way to clean themselves.

Car Washes 

Now that we have car dirt, we can have car washes. These are small buildings placed next to gas stations that share the entrance driveway/parking lot. The building is rectangular with a sloped metal roof and four "bays" for cars, with lights on the ceiling of each bay. I've left both ends open so that cars can drive straight through and exit on a second driveway back onto the road. These buildings aren't named and don't have signs. They're treated as city objects rather than buildings, which means the player can't interact with them but cars can.

Car washes use a lane reservation system for both the four individual bays and one shared exit driveway. There's no need to reserve the entrance driveway because all cars enter it from the same point in the feeder road, and the traffic system can only allow one car to enter at a time. Bay reservation is needed to prevent cars from queuing up and blocking the road. The exit lane must be reserved so that a car doesn't collide with another car that already exited and is either driving down the exit driveway or waiting to turn onto the road. The traffic system that controls car behavior isn't activated until the car pulls out onto the road.

Car logic is instead run by a finite state machine while in the gas station area and on driveways. The states for using a car wash are:

  • Turning into driveway
  • Driving on driveway
  • Turning into bay
  • Entering bay
  • Stopped + washing
  • Exiting bay
  • Turning onto exit driveway
  • Driving down exit driveway
  • Turning into road 

The wash cycle itself starts by turning on the light above the car. I've changed these lights so that they're enabled during both day time and night time. Shortly after entering, water starts to flow, and is drawn by a series of random semi-transparent lines running down the space from the inside roof to the ground. Then soap is applied, which is rendered using a foam shader effect. Foam is similar to dirt but uses a lower frequency noise, a sharper edge cutoff, and a vertical animation to make it look like the soap is running down toward the ground. I've added day time and night time screenshots of the water and foam effects.

Car wash with a car in one bay where the water is running and the car is soapy.


The same car wash, viewed from the other side and at night.

I actually recorded three different videos as I worked on car wash graphics. Each time I found something that I needed to improve on. You can find them on my YouTube channel, but I'll also link them here. 




Service Stations

I added service stations next, with a 50/50 chance of service station or car wash. They're very similar to car washes and have the same size, number of bays, texture, roof type, and lack of player interaction. The only difference in drawing is that they have only one end open rather than two. This allowed me to reuse much of the code.

Service station with one car inside and one light on.

Service stations have stacks of tires in front. I wrote new code to generate thick cylinder geometry so that I could add these tires. In the end, I didn't use that code for tires, but I did use it to replace the drawing of toilet paper rolls, paper towel rolls, and tape in buildings. The previous code drew these as a cylinder with a transparent hole cut into it. This was inefficient and didn't always alpha blend correctly with objects visible through the hole, in particular when the player was holding the cylinder. Now this has been fixed by making the hole out of real geometry.

Service station with stacks of tires in front.

I haven't added any dynamic car update for service stations yet. Currently, cars are spawned there at object placement time and never leave. They're the same as parked cars placed elsewhere in the city. 

Convenience Stores

Where are the gas station employees? Shouldn't someone be watching the pumps and car wash? I'm missing something that often comes with gas stations: small convenience stores such as 7 Elevens. These are now added on the other side of the gas station away from the road, 90 degrees from the car wash or service station. Of course they're only placed when they fit, which means they may be absent in situations where gas stations are placed close to office buildings. Since gas stations are the first city objects to be placed, they override anything else such as parking lots.

Convenience stores use the same random name generator as houses and some office buildings. And what do you suppose was the name of the first store I saw near the player's starting location?

Apparently my name generator has chosen "Farto" for this store. Sigh. Really, this is the first store I found.

Convenience stores are similar to the retail areas I added to the ground floors of some office buildings, though they're much smaller. They have rows of shelves with food and drink items placed over tile floors with bright lights overhead. I added a counter to the front and a single user bathroom and a storage room at the back. There's one exterior front door facing the gas pumps and an optional back door on the opposite side. It's a fixed floorplan, though it does stretch to fit a building that's variable sized based on the amount of available space.

Interior of convenience store with a person browsing the items. Yes, I know the pizzas should be frozen or at least refrigerated.

The front area has a counter with a cash register and a person standing behind it. There are other items such as a coffee machine and various food and drink related objects. I placed a drink vending machine to one side and a snack vending machine on the other side. A digital clock that shows the actual time can be found on the back wall. As a final touch, I hid a handgun under the edge of the front counter near the cash register. The player can search for and take the gun for some fun target practice.

Front counter of store with someone at the register and a view outside through the windows.

I added a new type of object to these stores: the commercial drink fridge. They can be found along the back wall near the storage and restrooms, and sometimes along the sides between windows. These contain drink bottles, drink cans, and cartons of milk. The player can slide the two front glass doors back and forth to access the drinks inside. There's also a small interior light to illuminate the contents even when the room lights are turned off. I made the interior surfaces and glass reflective using the cube map system described in an earlier post.

A pair of commercial fridges along the back wall of the store, filled with drinks behind glass doors.

I made sure to leave enough space around all of these smaller buildings for pedestrians to walk between them and along the sidewalks. Dumpsters are placed behind most of the stores. I may add other trash related items in the future if I get back to this at some point.

Back side of a convenience store with a dumpster and storage room visible through the window.

Stationary People in Buildings 

There are some additions I made to my AI people to make them behave more realistically in buildings such as these. The first was to add support for what I call "stationary" people. These are extra people placed in specific locations and facing in particular directions. They're implemented by assigning slots during building room object generation. I added these locations at counters in front of cash registers in stores and mall restaurants, as seen above. I also added people behind checkout counters in retail stores, and at the front entrance of restaurants where they can greet customers.

I would like to take this further in the future. For example, if I ever add sitting animations, I can place people sitting at desks. That would probably work well for office building reception desks on the ground floor. I just have to be careful not to add so many people that there are performance problems. For this reason, I capped the number of filled positions to the max number of people that can be placed in that building type. When there are more slots than there are available people, they're randomly assigned to, and some will be vacant.

Note that stationary people don't become stationary zombies. They'll leave their positions and come after the player when zombie gameplay mode is enabled, and will continue to walk around even after gameplay mode is disabled. This helps to increase the density of zombies in large open areas such as malls and retail stores.

Building AI People Points of Interest

While I was working on the building people AI logic for convenience stores, I noticed that they would walk around aimlessly and stand in random places. So I took a break before finishing convenience store interiors to work on what I call "points of interest". These are locations around objects placed in buildings that include information for where people stand and what directions they look in. The goal was to have people walk up to and face store objects such as shelf racks, vending machines, and the front counter. I later expanded this to include various rows of items in mall stores (shelves, clothing racks, bookcases), restaurant counters, and checkout counters. I even added points of interest for bathroom toilets, sinks, and urinals. Now people have a reason to enter the bathrooms!

POIs are grouped by room and are selected from when the person chooses that room as their destination. POIs override the default location, which is often the center of the room, but only when they're reachable from the entrance. (It's the job of the object placer to ensure all POIs are reachable.) I plan to add more similar features in the future to improve the realism of 3DWorld's AI behaviors.

Monday, January 19, 2026

Procedural Restaurants

My previous "restaurants" post was a bit misnamed because mall food court fast food stores aren't really restaurants. This time I've added proper restaurants in their own buildings. I decided to start with the house floorplan, since restaurants are smaller than office buildings and there are plenty of houses available to reassign. I limited restaurants to simple single cube houses to keep the logic simple. There are no garages or sheds. I also restricted them to two floor tall buildings with a large horizontal footprint, to provide ample space for the dining area and additional rooms. This produced a reasonable number of restaurants that seems to be around 5% of all secondary city houses. (None of the residential city houses are large enough to be a restaurant.)

The internal floorplan of a restaurant is simple and shared across all buildings of that type. The main dining area occupies around two thirds of the total space, which is separated by the remaining rooms by a wall that runs the entire length of the building and a series of doors. The other rooms consist of a kitchen, two bathrooms, and an optional storage room for large restaurants. The kitchen takes up about two thirds of that extra space. The actual size distribution depends on the number of windows along the exterior walls as the interior room dividing walls can't end at windows. The storage room can either be connected to the dining area or the kitchen with a door. All doors remain unlocked as there are no items for the player to search to find keys. Restaurants currently have no attic or basement.

The dining area features many small wood tables arrayed in a 2D grid pattern. Most of these tables have four wood chairs. Tables can be either square, rectangular, or round, with optional place mat or table cloth of a variety of textures/patterns. Each table has full place settings for each seat with a plate, cup, and silverware. Some plates have food such as fish on them, while some cups contain coffee. I placed either a custom procedural vase or a candle at the center of each table. The result is very repetitive, but also very orderly. I suppose it makes up for the randomness of the kitchen object placement.

I hung spherical lights from the ceiling in a grid pattern and placed rotating ceiling fans between some of these lights. The perimeter of the dining room is decorated with a variety of objects such as 1-2 wine racks, potted plants, pictures, an optional TV, and an optional fish tank. I placed rugs on the floor by the exterior doors and a podium with chair next to the main entrance for guests to wait at to be seated. The ceiling uses a white panel texture, and the floor uses one of two marble or granite tile textures.

3DWorld's procedural buildings are full of critters: rats, spiders, snakes, roaches, and flies. Restaurants are no different. It's actually quite fun chasing rats as they run between the tables and chairs. 

I've included some pictures of restaurant dining areas below. 

Restaurant with pink walls and square tables with table cloths.

The upper row of windows looks a bit odd, but I have the same layout in factories and two story retail buildings. This is one limitation of the current window logic. It's run on the exterior of buildings before the interior is generated, so it can't easily be customized by building type.

Restaurant with light green walls and round tables with darker wood.

Restaurant with pink walls and square table with red table cloths.

Restaurant with light blue walls and rectangular tables, viewed from above.
 

After taking the screenshots above, I realized that the ceilings look kind of plain. There's not much contrast between the light ceiling tiles and the bright walls. I decided to add wooden beams crossing the ceiling and hang the lights on these. Here is how this looks in the first restaurant. It's definitely an improvement. I like how all of the wood textures and colors match between the tables, chairs, wine racks, and beams.

First restaurant with wooden beams added to the ceiling that the lights hang from, and people.
 

Restaurants have commercial kitchens that use the same object placement logic as kitchens found in malls, prisons, schools, and hospitals. They have the same walk-in freezers, ceiling ducts/vents, and shiny reflective cooking equipment. The only difference is that the logic for placing hoods and some of the other objects is a bit more complex to handle the windows.

Kitchen from the restaurant in the first screenshot. There are snakes, rats, spiders, and roaches in here! (And the plates are metal?)

Restaurant kitchen, looking out through the door into the dining area.

The bathrooms are quite small with a single toilet, a sink, and urinal in the men's room. I placed gender appropriate signs on the outside of the doors. They look very similar to office building single use bathrooms, so I'm not adding screenshots of them. I included the medicine cabinets found in house bathrooms because this is a source of healing items for the player, and there are no other drawers or doors for the player to open in these buildings. The only major difference is that they have tall ceilings.

This post was much shorter than the last one, mostly because I only had one topic compared to three. I feel like I'm done with food related items for now. The next task on the list is car washes, so I guess it's back to working on commercial cities. I won't be surprised if I find more restaurant related changes to make though.

Saturday, December 20, 2025

Restaurants and Kitchens

I'm continuing my work on 3DWorld's interiors for special building types. This post will cover some additions I've made to procedural buildings: kitchen pantries, walk-in freezers, commercial kitchens, and mall food court restaurants. Each of these features required implementing new object types and placement algorithms. The last three are also related by containment, since restaurants contain commercial kitchens which contain walk-in freezers. I'll discuss these four topics below in the (inside-out) order in which I added them.

Kitchen Pantries

Up to this point, only retail stores contained food items. I put a lot of effort into making some of these objects, so I wanted to add them to houses as well. Many houses have a pantry in the kitchen, which is a small room for storing food related items. It's actually quite similar to a single door bedroom closet, so I decided to reuse that code. Pantries are placed in one of the corners of the room that doesn't block a window. The only real differences are that these "closets" are in kitchens rather than bedrooms, contain shelves instead of hanger rods, and have food items in place of clothing. The walls, door, and ceiling light are identical to closets.

I decided to add three rows of shelves that wrap around three sides of the interior. The side with the door is of course excluded. A random type of object is selected for each side of every shelf, and in some cases are added to the floor under the bottom shelf. This is the same set of food items placed in retail stores: boxes of crackers and cereal, bottles of water, Coke, beer, or wine, and cans of Coke or beer. I thought of adding pizza boxes, but they generally don't fit on these narrow shelves. Here's an example early version of the kitchen pantry.

Kitchen pantry filled with food boxes and drinks.

I later added non-food items that are still food related such as stacks of plates and rolls of paper towels. I'll continue to add more items when I think of them, or when I add new food related items to other room types in the future. Keep in mind that the player can take and use all of these objects.

Kitchen pantry in another house, with the addition of paper towel rolls.
I added one new type of object for pantries: the spice jar. This is a small semi-transparent glass container with a random amount of colored "spice". These are usually placed in a row on a shelf with various types (colors) of spices randomly selected. Sometimes the placement is uneven with gaps. It's a simple addition, but everything helps to improve realism and variety.

Kitchen pantry with a row of jars of spices. And a rat on the floor!

Walk-In Freezers

Next, I added walk-in freezers. And guess what? I reused the closet code yet again! In fact, walk-in freezers were copied from pantries since they have the same shelf system. The major difference is in the materials used. In place of plaster walls there's shiny steel for both the interior and exterior. The hardwood floor and wooden door are replaced with metal flooring and a metal door. Even the shelves are metal, in the form of a horizontal grid of thin bars.

Freezers are placed in a corner of the kitchen. These are always one standard floor spacing tall and don't extend to the tall ceiling of mall stores, which means that the top surface may need to be drawn. I added extra clearance around the door to allow it to open (with a different sound). The door is still recessed and thin because it uses the same geometry and rotation logic as interior building doors.

Walk-in freezer in a commercial kitchen, exterior view. Shiny! In fact  most of the kitchen objects are shiny.

Now I'll show the freezer interior. I placed a freezer fan in the top back of the interior using the same code as house AC units. Shelves are metal racks with some vertical supports at the inside corners and objects placed on or below them. I didn't really have any good frozen object types other than stacks of pizza boxes, so I added closed cardboard boxes that the player can imagine has some type of frozen food in them. They can't be opened because I don't have anything good to draw inside the opened box. I may place additional items in freezers later when I think of them. Maybe frozen fish?

Interior view of a walk-in freezer with shelves full of boxes, a few stacks of frozen pizzas, and an AC unit in the top back.

Commercial Kitchens

Pantries and freezers were relatively easy to add. Now that I had freezers, it was time to start on commercial kitchens. These rooms are placed in buildings that can have cafeterias or other eating areas such as schools, prisons, hospitals, and malls. One easy first step was adding a tile floor over the concrete, carpeting, or whatever base floor material the building was using. The remaining steps proved far more difficult, mostly due to the large number of new object types I needed. At first I attempted to create these various kitchen appliances with procedural geometry. I didn't get very far though before I realized it would take countless hours to write the code for all of these. So, with a heavy heart, I deleted the initial code and went looking for 3D models. At least the freezer is procedurally generated.

I found 12 different commercial kitchen object models on Sketchfab which included refrigerators, ovens, microwaves, deep fryers, stoves, grills, and sinks. Most of these were low poly models that should allow me to add quite a few objects without running into framerate problems. I tried to find models that had plain white textures so that I could more easily change the materials. Combined with the existing refrigerator and walk-in freezer objects, that meant I had a total of 14 item types to place. The goal was to add a system that selected and placed random models like I had done with prison gyms.

I already have some nice functions to place 3D models along walls that checks for blocking windows, doors, stairs, other objects, player/AI paths, etc. It takes a height value and automatically calculates the object width and depth based on the relative model sizes in each dimension. My first attempt to use this approach created a random set of objects scattered around the perimeter of the room with gaps of empty space everywhere. That's a reasonable start on the programming side, but it's an absolute mess visually and looks like a very inefficient kitchen layout.

This needs a number of fixes. First, I need to solve the problem of everything placed along the perimeter that leaves empty space in the center of the room. If the kitchen is large enough, a procedural metal table is added in the center. I can then place a variety of smaller items on the table such as the small deep fryer model, a microwave, a toaster, and cooking items that include pans, plates, cups, and trays. I even found a simple 3D model of a milk carton to add. The center of the kitchen is no longer empty space.

The second part of this fix was placing some random rolling carts in areas of empty space. I reused the "trolley" model I had placed in hospital operating rooms, since it seemed like something that could be found in the kitchen. Then I placed stacked plates on these, and configured them so that the player could push and pull them around. (This is important because these carts can sometimes block the path to the door.) One problem down, several to go.

The next issue is the random gaps between objects. Normally a commercial kitchen is packed with adjacent appliances to fit as much as possible into the limited space. Rather than randomly placing individual objects, I changed it to place a single seed object and then iteratively add new random models to each side until there's no available space left. This produces a dense group of adjacent objects along one wall. It's not always the entire wall, as objects such as doors break up the groups.

It's still a mess of object types though. To make matters worse, some of them have very different aspect ratios that don't fit well together. The solution to this is to group the objects by function, which conveniently also somewhat groups them by size and shape. The three categories I came up with are:

  • Objects needing a vent/hood: grills, fryers, stoves
  • Other cooking related objects: ovens and microwaves
  • Non-cooking objects: fridges, freezers, sinks, and dishwashers

Each of these categories has 4-5 different items/models. The entire contiguous group of objects is assigned the same category. Categories are randomly selected, with a higher weight given to the one with the fewest placed objects so far. The placement system also attempts to place at least one of each unique object when possible. This approach mostly balances out the model distributions and maximizes variety. This did a reasonable job of object placement and created a kitchen that looked much more organized.

The only remaining problem was that the models used different colors, materials, and styles. They didn't all fit well together. So I did the only reasonable thing I could come up with: make everything uniformly shiny. I Set almost every material to reflective metal, which removed almost all of the color and texture. The appliances also now match the metal freezer and center table as well. Even the trolleys are shiny metal. Everything is better when it's shiny, right? I need to take advantage of the cube map reflections I added a few months ago. It's actually less obvious that reflections are incorrect when the room is full of many small objects with surfaces at different angles.

There's still one thing missing: ventilation. Kitchens need good airflow to remove all of the smoke, fumes, and steam from cooking. I began by adding rectangular ducts with vents along the ceilings using the same code I had added for malls. That's a good start for general ventilation, but I needed something more industrial for the fryers and grills. After changing my mind a few times, I eventually decided on rectangular metal hoods with internal fans hanging on the ceiling above the first category of items (grills, fryers, and stoves) and spanning the bounds of the entire row of models. That's another bonus of combining rows by type.

Since hoods have to scale to the size and shape of the objects, I create them procedurally rather than using 3D models. These objects have sloped edges so that the front is higher than the back. I added a repeating fan texture to the interior top surface (the same as an AC unit) and a metal grid texture (street grate) to the back.

With everything combined, here is what we get: 

Commercial kitchen inside the windowless room of a school. Shiny!

Very large commercial kitchen inside a prison, with a central table and appliances lining the walls. An open freezer is in the back.

Stoves and some grills have pans on them. To finish things off, I placed some stains on the floor using common food colors like white, black, dark red, and dark green. I liked the look of those stains, so I added similar stains to some of the trays and plates as well.

Mall restaurant kitchen showing some new features such as fish on plates, objects on trays, and stains on trays.

I'm sure I could add more objects such as pots, pans, hanging utensils, etc. to fill in the remaining empty spaces. I don't want to load or draw too many 3D models just for kitchens though. It may be okay if I can find models that can be added to other room types in the future. We'll see.

Mall restaurant kitchens have counters that run their length and separate them from the public areas. I placed more food related items on these counters.

Mall kitchen with a bowl of apples on a counter.

Mall Food Stores/Restaurants

My final food related addition was mall restaurants. These aren't the fancy sit down restaurants with small tables though. No, they're the type of fast food places typically found at food courts. I felt like this simplified layout was an easier place to start. I actually worked on restaurants and commercial kitchens at the same time as this required several iterations to get right. There are also many similarities between the two, in particular the metal surfaces and the various placed food items. And of course commercial kitchens account for about half of the interior space of the restaurant.

There are two different styles of restaurants. The first type has a simple counter and no public interior space. This is your typical fast food counter full of cash registers where customers order their food and then sit down at the central mall food court tables to eat. These are divided into a smaller space where the cashiers and packagers work and a larger back kitchen area. Here are two examples of this type of restaurant, viewed from both inside and outside.

Mall restaurant shown from inside looking out into the mall concourse. The reverse side of the image above. The cash register model is new. Note that some of the store sign backgrounds are colored now.

Mall restaurant walk-up counter with cash registers. Orders to go only. Note that the name sign is directly above the order counter. I really should be using multiple fonts for these signs.

The second style has a public area with entrance doors and large store front windows. This is the same geometry as non-food stores found in malls. In fact I had to add custom code to remove the doors and windows for the counter-only restaurants described above. Here the counter with the register is further inside and separates the public area from the kitchen. I placed a food and drink vending machine in the public section if they fit.

There are two sub-types of this style of restaurant, chosen depending on the size of the public area. If the space is deep enough, rows of tables are added and this becomes a sit down restaurant. Otherwise, the public space is left mostly empty except for the vending machines. Customers buy their food and then go back to the central food court area to eat it. I may decide to add more small items here later. Below are screenshots of both the empty space and tables cases. 

Mall restaurant with an indoor area for ordering and vending machines, but no seating.

Mall restaurant with indoor seating. Vending machines are off-screen to the sides.

I'll finish this post by showing some of the new detail items that I've added to restaurants. First, I added a bowl type to complement the plate type. The only real difference is the use of a spherical section rather than a conical section when drawing. Bowls can be empty or contain apples or soup. Soup is drawn as a simple circle at a random height, using the same set of food colors as floor stains. I reused the liquid drawing code from cups of coffee and buckets.

Bowls of apples can be seen in the screenshot below and also an earlier commercial kitchen screenshot. I originally wanted to use a sphere packing algorithm to place the apples as densely as possible. Unfortunately, packing spheres into a spherical section is quite a complex problem, and I wasn't able to find a simple mathematical way to do that. It's really not worth spending days working on the solution to such a minor feature. So instead, I placed one apple on the bottom and three more in a second ring/level. The player can take apples and then take the bowl itself when empty.

If bowls can be nonempty, then some plates should be nonempty as well. The only existing object I could find that worked well for a plate was a fish. I can conveniently reuse the same fish model I have for house aquariums, I just have to flip it on its side. I can even take advantage of the stacking/containment logic and place these new nonempty bowls and plates on trays. Now you can find a fish on a bowl on a tray on a table, and the game logic requires the player to pick up these objects in the correct stacking order to avoid having anything become floating in the air. The stack of objects will also move with the table if pushed by the player.

As an added bonus, I can reuse some of these food related objects in house kitchens and cafeterias. 

Closer view of bowl of apples and fish on plate on tray.

Abandoned bowl of soup on a tray on a cafeteria table.

Wow, that was a ton of work! I'm surprised I was able to get all of this done before Christmas. I feel like I'm not 100% done yet. I'll probably spend a few weeks debugging, tweaking, and optimizing kitchens. Maybe I'll go back and add some smaller objects to fill the empty space.