Tuesday, June 23, 2026

Procedural Data Centers

Once again I was thinking about what new type of building to add to 3DWorld's procedural cities. Data centers are probably the most popular (and controversial) building type in 2026, so that was a good candidate to add. Some people love them because they're needed for AI, which is supposedly "the future." Some people hate them due to environmental impacts of their high electricity and water usage. Maybe years from now we'll all find out if they were a good investment. I'm not here to present my opinion on data centers, I'm only here to add them to my procedural world. With that out of the way, let's begin.


Exterior 

Let's start with building selection. I've never visited a data center in person, even though they've existed in some form for a long time. I can tell from the various photos online that they're usually very large, flat, and rectangular. That's convenient for me because simple rectangular buildings are easier to subdivide into rooms anyway. I do want to find buildings that have a large footprint but aren't very tall. Now this is unfortunate, because those types of buildings are already assigned as factories, parking structures, warehouses, and power plants.

Wait, I haven't shown power plants yet. Part of the reason is because they're technically not completed, at least not as completed as data centers currently are. The other reason is that they're very similar to factories. They have the same machines, tanks, ladders, catwalks, tall ceilings, etc. The floorplan is the same. The only major differences are that they have generators in place of conveyor belts and more smoke stacks. I can't be distracted by power plants here. Maybe I'll write a post on them later.

Anyway, back to data centers. The other building types I mentioned are limited to 4 floors tall, so I can at least make the ones that are 5-6 floors and a large enough footprint into data centers. That gives me around 50 of them in my city of ~10K houses and ~5K buildings. These only appear in my secondary city areas since the city centers with their grids of roads almost always have buildings taller than 6 floors. I think it's possible to get a data center in those cities, but so far I haven't seen one.

Data centers have walls using one of several concrete block or brick textures, and windows only around the office sections and ends of the building. I've had the ability to customize window placement per-side and per-floor since adding factories a few posts ago. I removed the windows from the server rooms because they seem unnecessary and block valuable sever space. Plus, they don't alpha blend properly with the interior windows I added. (More on that below.) I also removed the windows from the sides of utility rooms so that I don't have to worry about blocking them with machines and pipes. Fewer windows are more efficient and also make object placement easier - win/win! I did have to add various air intake and exhaust vents where the windows would normally go to break up the empty wall space and make the layout a bit more functional.

I changed the roof type to always be flat so that I can cover the rooftop with cooling goodness. The building exterior geometry generator was already adding skylights to the roofs of some of these buildings. Skylights don't seem to cause any problems since they're over the central hallway, so I left them in. Data centers are massive energy hogs and need a ton of cooling, so I absolutely littered the roof as well as the sides of the buildings with AC units. But those normal office building sized units don't do it for me. They're too small. No, I later went back and added 2-4 of these huge house sized cooling towers on the roof with two circular fans on the top of each one. I couldn't find a suitable free 3D model and instead created them with textured cubes and cylinders. It's a good fit since everything else on the roof is made of simple shapes as well.

I wanted to fill these buildings with pipes and ducts, since I feel oddly satisfied by writing thousands of lines of pipe routing code. It's very time consuming though, which is why I've only added a minimal amount of water, gas, and coolant pipes so far. I made the coolant lines (both outgoing and return) a light blue to get some more colors in an otherwise grayscale building. I did see some reference images with blue pipes on the roof. The system of pipes and ducts is fully connected to everything and extends from the utility inputs in the basement, all the way through the floors to the cooling towers on the building roof. Here's a screenshot of a typical data center rooftop view.

Data center exterior view showing rooftop cooling towers, AC units, skylight, windows, vents, and pipes.

And here's another angle of the roof on a different data center where you can see the end and sides of the building. The back end with the vents and utility rooms is facing the camera, while the other end with the offices is facing away. The smaller AC units along the sides of the building can be for the office spaces and non-server rooms.

Rooftop view of another data center without a skylight. A row of smaller AC units can be seen on the ground along the side of the building.

Here's a smaller data center with only two cooling towers and a brick texture. This one has some right angle turns in the rooftop coolant pipes. Pipe routing is quite difficult because of the way the building is generated in stages: exterior, roof objects, interior floorplan, interior objects. The cooling towers are placed before the building knows where the interior air handlers are! I had to shuffle the machinery around to make everything fit and find a way to route the pipes around obstacles. This took me many hours to get right.

Smaller data center viewed from above. This one has a company sign.

I assigned one data center the name "Skynet" as an Easter egg for the player to find. It happens to be near the edge of my island where the ocean water is visible in the background.

Skynet. Surely you get the reference.

Interior

Now we'll move to data center interiors. These are generally well lit and open spaces, with very little dirt and wear. I've replaced some of the rusty and dirty textures and objects found in industrial buildings with shiny versions to reflect how new these buildings are. I did leave the basement and parking garage dirt though. Maybe the building was something else that got repurposed as a data center? On second thought, I set water and crack damage to zero for data center basements.

The main floorplan is shared across the 5-6 above ground floors and starts with a wide hallway that runs the entire length of the building in the long direction. Sometimes this hallway is centered, and other times it's offset a bit to the side to make an asymmetric interior. This happens when there are an odd number of windows on the short dimension. The wider side of the hallway contains stairs and an elevator together at the end with the front entrance door. I put them both on the side of the hallway rather than the center because someone thought the center stairs looked odd. This uses a different variant of my U-shaped stairs that has an open wall with a window visible in the side. I changed parking structures to use a similar type of stairs shape with the missing wall and window at the back to make it look more open.

Here is what this area of the building looks like. Note that the elevator floor display is now using digital numbers. I made the code used to create digital clocks more general so that it can be used to add 7-segment numbers and letters to other types of building objects.

Interior of a data center showing the stairs and elevator to the side of the main hallway and the door to the operations center on the right.

I'll continue walking down this hallway. The main office area, which I'm referring to as the operations center, is placed next to the elevator. This room typically occupies three windows worth of the building length, though it can only be two windows for short data centers. The room itself is an odd non-rectangular shape because it has the stairs and elevator footprints cut out of it. This is sort of a mix of an office and a conference room that I had to write custom placement logic for. There are rows of desks with office chairs and computers placed along the walls, with a long conference table and chairs in the center of the room. I put a digital clock on one wall and some smaller objects such as filing cabinets and trash cans against walls. Some buildings have a door connecting the operations center to the server room. There's quite a bit of unused space in the larger rooms. I'm still thinking about what else I can place there.

This is what I call the "operations center". It's full of desks with computers and a big conference table with chairs in the center. The elevator wall is just barely visible on the left.

The next room we encounter along the hallway is the server room. There's actually one on each side of the hallway in a symmetric configuration. I thought it would look neat if I added glass windows between the server rooms and the hallway to improve visibility and make the hallway more interesting. Normally glass windows don't alpha (transparency) blend correctly with exterior building windows. But fortunately, there are no windows in these server rooms. That's actually one of the reasons I removed server room windows. I should probably have the server room doors start out as closed and locked, though for now they're sometimes left open.

View of the server room through glass windows in the main hallway.

The interior of the server room is exactly what you would expect: rows of groups of server racks. I started with office building server rooms that had server racks along the walls and added more of them in the center of the room. I combined racks into groups of 8 because that's a convenient power of 2 (8 bits = 1 byte). These groups are repeated in rows and columns with aisles in between, similar to the approach I used to place store shelf racks. Server rooms use a new metal floor tile texture based on what I remember seeing in the server room at the company where I work. I added plenty of vents in both the ceiling and floor for air flow to cool the servers.

I'm not all that happy with the same repeating gray texture used for each rack. I would prefer more variety, though in reality data centers probably do have thousands of exactly the same server rack in rows like this. I did want to avoid any brand names here. The servers along the walls are bit different because they have conduits running from the top of the rack into the ceiling. It was too difficult adding these to the rows of servers in a way that avoided the ceiling lights, so I omitted them for interior rows. We can say the racks along the walls are for networking rather than compute and that's why they have extra cabling. Maybe I'll connect these with wire harnesses at some point in the future when I get back to working on this area of the building. 

Inside the server room itself. Row after row of groups of 8 servers, with plenty of ceiling lights and air vents everywhere.

The other side of the hallway across from the stairs, elevator, and operations center is split into various smaller rooms that differ across floors. There are men's and women's restrooms on the lower two floors. I put a security room with security monitors on the ground floor. The rest are individual offices, a kitchen/break room, and other standard rooms found in office buildings.

 

Utility Rooms

If we keep walking we'll find ourselves at the other end of the hallway, in the back of the data center. This is the opposite side of the server room from the operations center, where the utility room was added to provide power and cooling for the servers. I want to create a whole new blog section for data center utility rooms because I have a lot to say about them. This single room type was probably at least a third of the total effort of creating data centers. It has three new object types as well as a variety of ducts and pipes that took several iterations to get right. It was quite a lot of effort - but I did enjoy working on this part.

The utility room typically accounts for two windows of length of the building, though the side windows themselves aren't drawn. They're not needed and only block the objects and pipes. The floor is bare concrete. Equipment is added in rows starting at the wall shared with the server room and working toward the back wall of the building until there's no space left. I added enough of a gap between rows of equipment for the player and building people to walk.

Placement starts with UPS backup batteries along the server room wall. I used the commercial refrigerator 3D model that I also use for commercial kitchens because it looked like a good battery cabinet to me. It's made of shiny metal with access doors on the front and some lights with digital displays. Surely no one will notice that it's also used as a fridge, right? I added a fan - no, pair of fans - to the top to make it look more like a battery. This is a free 3D model I found when looking for models to add to factories a few months ago. I think it's supposed to be a GPU cooler, but it's good enough for this application. And to finish off the battery, I placed a black power conduit running into the ceiling. Maybe this connects to the row of batteries on the floor above or the conduits at the top of the servers along the walls.

Oh, here I'm assuming that the power connections run through the floors/ceilings to connect everything together. I may go back and add proper power cables across the bottom of the ceiling at some point. I also intend for the ducts providing air flow to the vents in the sever room to run though the ceiling, even though there technically isn't enough space between the ceiling and floor for ducts. I suppose my buildings have too little space for this purpose. However, it's not obvious to the player since the floor/ceiling cross section isn't really visible anywhere.

Next from the server wall are the row of air handlers/heat exchangers for cooling the server racks. These are gray painted metal rectangles with those same GPU fan pairs added to each side. I'm not quite sure what purpose these side fans serve, but they do make these objects look more like air handlers. Maybe thet provide cooling for the utility room itself? Each unit is connected to a large duct at the the top as air intake. These are joined together across all units in the room and meet with a vertical duct at the far side of the room along the exterior wall of the building. This duct runs the entire height of the building and connects the utility room ventilation systems together across stacked floors. There are air intake vents on the side of the building, the roof, and down in the parking garage if one is present. The air exits each air handler through the floor.

Air handlers also have four pipes connected to them: coolant in, coolant out, water in, and waste water out. Coolant pipes are light blue to add some brighter colors. Water pipes are copper with brass fittings and drain pipes are white PVC plastic. I couldn't quite decide if I wanted to make the data center AC system water or air cooled, so I made it a combination of both so that I could add more pipes. I suppose the waste water pipe would be needed as a condenser drain even if there was no water cooling. The water and drain lines run vertically through the floors connecting to each stacked air handler, and are merged together with horizontal pipes in the basement.

Utility room with UPS/batteries, AC air handlers/heat exchangers, power transformers, and backup generators.

In contrast, all coolant pipes merge horizontally across the air handlers in each utility room. This produces a pair of pipes on each side of the air intake duct for each side of the building on each floor. These pipes run vertically up the inside of the exterior wall in a tight group all the way up to the roof where they turn and enter the sides of the cooling towers. Half of these pipes continue through the cooling tower and connect to the second row of cooling towers if there is a second row. Routing these pipes took quite a bit of effort and many attempts to avoid having them intersect each other or anything else in the room. Moving the ceiling lights around to avoid everything was particularly troublesome. Keep in mind that both the rooms and objects themselves are randomly different sizes, with some variations in configurations, so the placement logic has to work with all variants. The screenshot below shows how the coolant pipes are routed.

Close-up of utility room pipes and ducts used for server cooling.

I'm not entirely sure this cooling system is correct for data centers. I originally thought it worked like my house's air conditioner with a single closed loop of refrigerant, an outdoor compressor + fan, and an indoor fan. In that case the rooftop cooling towers would have both the compressor and the exterior fan. Then later I read more about it and it seems like most data centers have two separate closed loop liquid cooling systems with a chiller between them. I didn't initially add the chiller, and now there's no space for it. Maybe it can be inside the cooling tower and not visible? There certainly should be enough space for it in there.

Household AC systems have a narrow high pressure refrigerant line and a larger width lower pressure line. I made both of my coolant lines the same radius because that's what I saw in most of the diagrams and reference images I found online. I also found it odd that these don't appear to be insulated to reduce heat transfer with the surrounding air. Maybe the pipes in my reference image are in fact insulated with a thinner metal pipe at the core?

The next row of equipment consists of step down power transformers that convert higher power line voltages to the lower voltages used by individual server racks. They also power the coolant compressors and all of the various fans. I used the same substation model that I have next to office buildings along city streets and in factories, power plants, and office building utility rooms. These transformers already have power conduits running downward into the floor.

The forth and final row consists of a line of generators that provide backup power when needed. I found a nice 3D model of what I believe is a diesel generator online. I added these generator models to power plants and some of the underground extended basement machine rooms as well. There's a part on the top that looks like it could be an exhaust vent, so I connected a duct to this point. The duct makes a right angle turn, runs along the ceiling, and exits to a vent on the back wall of the building above the window. That's probably good enough, considering the generators are only meant to run for short times during power outages.

I added a fuel line connecting to the side of each generator. I used a yellow color to get a good contrast with the blue generator color and blue cooling pipes. I know this is supposed to be a diesel generator and yellow is usually used for natural gas pipes, but I don't care. These fuel lines run vertically through each floor to connect the stack of generators, and are connected together horizontally in the basement just like the water pipes. This works because the equipment layout is the same for utility rooms on each floor. The utility rooms on each side of the hallway can be slightly different though.

Utility room viewed from the side with the generator models.

Sometimes there's extra space for the player to walk between the generators and the back wall, and other times there isn't. I added space between adjacent generators for the player to walk instead. Some shorter length utility rooms don't have enough space to place generators in the long dimension, so I add them sideways. The exhaust vents and pipes are adjusted for this orientation. I have a screenshot of this configuration shown below.

Utility room with lengthwise generator placement. Only 4 generators will fit.

Occasionally the utility room is so short that generators don't even fit when rotated. In this situation, I split the third row into two roughly equal sections of transformers and generators. Generator orientation is selected to get the best fit and pack them as tightly as possible within the available space. Here's an example of a mixed transformer/generator row.

Utility room with split generators and transformers in the third row.

This is as far as I've gotten before my summer trip. I'll most likely go back and work on some of these data center areas before my next blog post. Writing all of this up gives me new ideas, and sometimes I even get useful feedback and suggestions from others who read my posts.

I suppose I need to add this in today's world:

Disclaimer: No AI/LLM was used for this work except for minor line completion with GitHub Copilot in Visual Studio, which doesn't understand the 3D code very well and isn't very helpful. 

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.