Thursday, March 20, 2025

Procedural Warehouses

My last blog post showed the progress I've made on procedural factories. In this post, I'll show how I've generalized factories to industrial buildings and added warehouses as an industrial building sub-type. I have plans to add other building types such as power plants in the future. These buildings share many elements with factories such as overall floorplan, sub-rooms, wall and ceiling beams, sprinkler pipes, HVAC units, ducts, and fans. They also use many of the same textures such as slotted and rusty metals. Reuse of interior elements allows me to create these variants more quickly with less added code complexity.

Warehouses have some significant differences though, most notably the replacement of machines and tanks with rows of shelves. These are similar to shelves found in existing houses, storage rooms, and basements. One main difference is that they're constructed of plywood and metal frames, rather than wood boards mounted to walls. This gives them a sturdier and more industrial look. A second difference is in the types of objects placed on and around these shelves. There are boxes, crates, and pallets everywhere, both on shelves and on the floor. Ladders have been moved against the exterior walls by the entrance door, and the catwalk has been replaced with a forklift 3D model.

Warehouse viewed from the front near the office and entrance, with people and a forklift nearby. The floor has bottles and stains on it.

The placement system supports stacking of pallets on top of each other, stacking of boxes and crates, and placing boxes and crates on pallets. Most of this was done by extending the existing item stacking and player interaction system to be more general. The player can take all of these objects, but only from the top of the stack. Boxes on top can be opened, and the contained items can be removed. The player and building AI people can walk or step over low objects such as individual pallets, which means the placement system doesn't need to worry about them blocking access to areas of the warehouse.

Warehouses have the same office and bathroom sub-rooms as factories. I placed extra rows of high shelves on the roofs of these rooms to make better use of the open space. These shelves aren't against a supporting structure such as other shelves or an exterior wall, so I added a narrow horizontal I-beam connecting them to the exterior side walls. The player can climb ladders to get behind these shelves.

Warehouse showing a stack of pallets on the floor, the front office with entrance door, and additional shelves stacked on top of the sub-rooms.

Warehouse boxes contain a different selection of items compared to boxes found in houses and office buildings. I reworked the shelf and boxes system to allow a different collection of contained objects depending on building and room type. Warehouse boxes contain some of the common items found in earlier boxes such as bottles of water/coke/beer/wine, toilet paper, and cans of spray paint. But they also have new items, including cases of coke and beer cans, boxes of food, and electronic items such as computers, laptops, and microwaves. I even added boxes containing tiny machines which use the same generation and drawing code as machines found in extended basements and factories.

Items are selected based on a combination of randomness and matching the size and shape of the item to the size and shape of the box. For example, tall and narrow boxes may have computer towers, short boxes can contain laptops, and large wide boxes contain microwaves. The goal of the player should be to find the boxes containing more valuable items such as laptops, while avoiding zombies, snakes, spiders, etc.

A stack of boxes and crates next to shelves placed along an exterior wall. Some boxes have been opened, showing items inside.

Warehouses have several entrances. There's a front entrance that opens into the main office, rather than between the office and bathroom as in factories. This means that I had to modify building door and window logic to allow doors to be placed into sub-rooms that already have custom windows that don't match the upper level windows of the main warehouse area. There's a back garage door that would serve as a loading dock, currently using the house garage door texture. I may continue to work on loading docks if I add warehouses to cities in the future or connect the secondary buildings with roads. For now, it only has a connecting driveway, similar to those added to houses. And there's also one or more optional side entrance doors inserted in gaps between rows of shelves.

Warehouse loading door near the back, using the garage door texture.

Warehouses can be quite large. I originally only assigned industrial buildings to smaller brick structures of three to four floors in height. Now I've modified the config file to create some short and wide concrete block buildings that can serve as factories and warehouses. These look more realistic for this type of building. They also make industrial buildings common and easier to find.

I modified overhead map mode to color code buildings based on category/function. This allows the user to select a building and teleport to that location, which definitely helps to accelerate testing of custom types. It's important to visit both large and small buildings to make sure the interior elements scale properly and look reasonable for the interior areas. I spent quite a while fixing problems like this, in particular cases where basement or parking garage stairs were blocked by or intersecting other objects placed at the ground floor.

Large warehouse viewed by standing on top of the upper shelf over the office room. This vantage point is needed to see the size of the space. The forklift is along the back wall on the left.

What's next? I currently have hospitals and schools on my list. I already started working on hospitals, but I decided to go back and add warehouses first because they were a more natural continuation of my work on factories. I've been working a bit on schools as well. It's still early though, so I have no idea how these will turn out.

Saturday, February 22, 2025

Procedural Factories

Factories were next on my list after malls. When I say "factory" I really mean a more general industrial style of building that also includes chemical plants, storage facilities, and that sort of thing. The factories I've created are collections of machines, tanks, pipes, fans, etc. They technically don't manufacture anything at the moment. Their interiors are very different from office buildings and residential buildings.

The first step was to select an appropriate set of buildings to make into factories. I decided on simple rectangular office-style buildings with a single geometry level and no more than four floors tall. Since I currently have the min height of office buildings set to four floors, this means that factories are always four floors in height. (They don't actually have four floors and ceilings inside.) At least having a fixed height simplifies the object placement logic. The set of buildings meeting the requirements of a factory area somewhat rare, and I was only able to find five of them in the area where the player starts. I even had to add debug markers to locate them since it was hard to tell factories apart from office buildings in the early stages of development. However, there are probably around a hundred factories among the 18K total placed buildings in the default city scene.

Factory interiors are similar to malls in that they have tall ceilings that span the entire height of the building "part" cube. I added smaller sub-rooms for an office and a bathroom inside this larger room, with doors connecting them to the open part of the factory. This makes the factory floor a sort of fat T-shape with smaller rooms in two of the corners, and the front door between those rooms. The sub-rooms are a single floor tall, which means the factory ceiling extends to cover them. This allows me to place additional objects on the roofs of those rooms.

This is the first time I've added proper rooms-within-rooms. Technically bedrooms closest are inside rooms, but they're represented as "room objects" rather than rooms in the code. Plus, building AI people don't enter closets like they enter normal rooms. My underground basement "backrooms" areas also have sub-rooms, though these are handled in yet a different way.

Nested rooms caused many problems with object placement, lighting, occlusion culling, and building AI navigation. One issue is that any spatial query such as point-in-room can potentially return both rooms, so I need to make sure the sub-rooms are added before the main factory so that they're returned by the queries. This was enough to fix lighting and occlusion culling, but AI path finding required quite a bit more work. For example, handling passing through doorways was messy because the door actually connects from the factory itself, so I had to treat it as a sort of portal from one area to another overlapping area. Then I had to handle problems with the T-shaped factory area where the shortest path from one point in the factory to another sometimes crossed through a sub-room. I won't get into the details here.

I don't want to have too much text without a screenshot, so here's a view of the entrance area of a factory. You'll have to read the text below to understand what everything is supposed to be.

Area near the entrance of a factory, between the office and the bathroom.

Now that I had the rooms and doorways worked out, it was time to add the walls and roof. I decided on selecting between one of two concrete block textures for the interior side of exterior walls. I reused the corrugated metal texture I had been using for some of the metal objects in cities for the ceiling. Next, rusty steel I-beams were added on the interior side. Vertical beams are placed between windows along the walls, while an X/Y grid of horizontal beams are placed along the ceiling. Beams are shifted to the sides to avoid blocking exterior doors. Round ceiling lights are hung from alternating beams along one direction.

One of my goals with factory object placement was to use as much existing code and as many existing objects as possible, to speed up the process. I first placed either cylindrical or rectangular metal ducts with vents along the upper walls on each side, using the same code I had used for mall store ducts. I later added an HVAC unit with a fan somewhere along each duct, with pipes extending up into the ceiling and down into the floor.

Next it was time to work on pipes. I modified the code that placed fire sprinklers and their network of pipes in parking garages so that it would work with factories. This allowed me to add red pipes up the wall and across the ceiling, with sprinklers, hanging brackets, and the various required pipe fittings. These pipes, along with some of the other types of factory pipes, extend down into the basement parking garage below. I continued to tweak this code at least a dozen times because almost every other object I added intersected those pipes in some factory I encountered.

I had the idea of adding catwalks and ladders to factories from the very beginning. I started by adding vertical ladders to the sides of the office and bathroom and wrote the code to allow the player to climb up and down them. Initially, I wasn't sure how the ladder controls would work. I wanted to allow the player to intentionally fall/jump off a ladder, so I couldn't use the forward and backward movement keys for up and down movement. Instead, I made the direction of the player's view control movement. If the player looks up they will ascend the ladder, and if they look down they'll descend. Then I placed a catwalk connecting the roofs of the two sub-rooms so that the player could walk between them. The catwalk railings are a bright yellow painted metal, which has good contrast against the shades of gray used for most of the other factory objects.

The floor of the catwalk is a metal grid pattern selected from one of two textures with round vs. square holes. These have alpha masks that allow the player to see between the holes in the grid. Light can pass through these holes as well, leaving interesting shadow patterns on objects below. I liked these textures so much that I created special metal stairs that reused them, and also reused the I-beam texture to create rusty metal railings. These stairs can be found in factory basements, where the degree of rust depends on the water damage variable for each building. Here is an example.

New metal mesh stairs with rusty railing in the factory basement. It's darker down here, so I need to use a flashlight.

I added a second catwalk along the length of the factory near the ceiling, supported by bolts into the ceiling beams above. This is randomly shifted around so that it's not over a doorway or directly under a pipe or row of lights. I placed a vertical ladder along the wall that reaches from the floor to the end of the catwalk at either one or both ends. Then I added an additional ladder to the side of the catwalk somewhere along the factory floor. The player can climb up and down all of these ladders and walk along the catwalk. Here is a screenshot taken from the roof of a sub-room where both catwalks and the top end of a ladder are visible.

Factory interior viewed from the roof of the bathroom. The top of the ladder can be seen in the center of the image and the catwalk to the roof of the office is on the right.

Note that all of these screenshots have indirect lighting enabled. I've made some improvements to indirect lighting, in particular for open areas such as malls and factories. I've also optimized the path tracing/ray intersection code used for building interiors. Now it can calculate indirect lighting for the 100-150 light sources from factory lights and windows in only 6-8 seconds of (background) runtime.

I originally wanted to make factories appear dark and dirty, but all of the windows produce quite a bit of natural light, even when the lights are off. However, it's quite dark inside factories at night.

Factory at night with the lights on. There's still a lot of light, though there are definitely more shadows.

Okay, it's still pretty bright. Maybe I should turn down the intensity of the lights? Then I would lose some of those nice detailed shadows from all the small objects. Things get really dark if I also turn off the ceiling lights. Only the red warning lights are visible.

Dark factory at night with the lights off. Only the glow of the red warning lights is visible.

Here is another view from the upper catwalk. The bright yellow colors of the catwalk railings and the red sprinkler pipes really stand out. The player can get a good view of the machines below from up here. It's also safe from zombies, rats, and snakes. Spiders can climb up to catwalks, though I can't remember ever seeing one on the upper catwalk. Fall damage is significantly more of a risk since it's pretty easy to accidentally fall from a ladder. The railings of catwalks make them relatively safe from falls.

View from the factory catwalk, with machines and pipes below, and sprinkler pipes and beams above.

The factory floor itself is mostly covered by three types of objects. There are machines of various shapes and sizes placed along the exterior walls where there's space, with care taken not to block doorways, the entrance area, or basement stairs. This uses the same code I wrote to add objects to extended basement machine rooms. Each machine is composed of a random collection of axis aligned cubes and cylinders using a random set of metal textures. A few additional objects are thrown in such as a transformer and a water fountain attached to a wall. I did change some of the factory machines to have metal rather than concrete base plates for additional variety.

The center area of the factory consists of a 2D grid of machines and a row of chemical tanks along a random edge. That grid and row may be broken up by other objects such as basement stairs and ladders to create an irregular pattern. Both the tanks and machines are connected by groups of pipes, as well as additional pipes going into the floor. Chemical tanks are capsule shapes with one of several textures applied to make them appear scratched, rusty, or dirty.

Factory chemical tanks, pipes, and red warning lights on the corners of machines.

All machines use the same geometry, which allows me to connect them together with pipes and coils of wire in a correct way. Keep in mind that these machines are stored as only a bounding box and some state flags. The detailed geometry and pipes are only generated at draw time and never actually stored in memory on the CPU side. This means that pipe and coil generation can only use information about the current machine to connect the various parts together. But if we know the neighboring machines are identical and at fixed distances from the current machine, we can determine the placement of every machine part for the neighbors by copying the current machine to the adjacent row and column. This also means that the pipes can be different for each row and column, even though the machines are the same, since the pipes for each machine are drawn independently. Any machine with an object blocking the gap between its neighbor is flagged so that no pipes are added on that side.

So far the floor and ceiling are pretty well covered with objects, but the walls are somewhat bare. I added vertical brown drain pipes to the walls along some of the supporting I-beams. I later added ventilation fan 3D models to alternating windows at the ends of the building. These extend outside the window somewhat. The viewer should imagine the window glass has been replaced with a fine mesh screen. While the set of objects added to each building is the same, I added randomness to their size, position, orientation, count, color, and texture to get sufficient variation to make each factory look unique.

A different, smaller factory viewed from above.

I wanted to add fans to the ceilings, but I only had those residential ceiling fan models from earlier posts. I suppose that's better than nothing. I made 75% of the fans rotate and emit a hum sound if the player is nearby. I then added something for the fans to do: collect the smoke and steam rising from machines. Each machine has a small probability of emitting smoke from it's top center, which will rise and expand until it reaches the ceiling. This reuses the particle system I added for interior building fires.

I liked these dynamic objects that make the scene feel more alive. What else can be added? How about flashing red warning lights? The best place to add these seemed like the corners of the machines on end rows, so that the lights were visible when looking along the edges of the machine grid. These lights look especially nice in the dark, though I didn't make them cast shadows.

As a final touch, I scattered various smaller detail objects around on the floors. There are piles of stacked boxes and crates between machines and in the corners. Some random buckets, paint cans, piles of broken glass, and groups of empty bottles are littered around in the open areas. I also added random balls of paper trash and stains to the floor. Most of this reuses existing functionality that I had added to basements in previous work.

A pile of boxes and crates stacked in the corner of a factory near the fire sprinkler riser.

Factory floor with scattered buckets, bottles, and stains. There are more bottles in the far back.

And don't forget the sub-rooms! The office room has a table and one or two desks, usually with computer monitors. I added either an analog or digital clock to the wall, an optional filing cabinet, and some random crates and boxes. The placement algorithm attempts to leave enough space for the player and AI people to walk around the room and between the two doorways. The bathroom has the usual toilet, sink, and possibly a mirror. The area between those two rooms has a fire extinguisher by the door, a breaker box, and a water fountain on the outside wall. All of the interior walls and floors are the same gray concrete material used for basements. Sub-room ceilings use the office building particle board panels texture.

Factory office sub-room with table, desks, chairs, wall clock, and many crates and boxes.

I put extra effort into making the interior structurally sound. There should be beams supporting all of the interior wall and ceiling areas. Everything is attached to or hung from beams as well, including all of the pipes, the central catwalk, the ducts,  HVAC units, lights, ceiling fans, and window fans. None of the objects should be floating or intersecting any other objects. It shouldn't be possible for the player or building AI people to clip through or get stuck in any objects either. Most of the pipes and smaller items are above head level or have collision enabled.

Finally, it was time to work on the factory exterior. The only major difference is the addition of one or two smoke stacks on the building roof. These use the same brick or stone texture as the exterior. They're not yet connected to anything inside the factory though, but they do emit occasional puffs of smoke. I placed some additional AC units, ducts, and pipes on the roof as well. The ventilation fans sticking out of the windows are also a sign that this is a factory. Oh, and the building name and signs now contain the word "factory" in most cases.

Factory exterior with two smoke stacks on the roof. Fans (well, their motors) can be seen protruding from the windows on the left.

Here is a video showing me exploring a factory using ladders and catwalks. I have people enabled in this video, though they don't do much other than walk around the factory floor area. Note that zombies can chase the player quite well in factories as the path finding does a reasonable job. It helps to ensure enough open space between rows of machines and chemical tanks for people to walk.


What's next? I'm sure I'll continue to add details to factories, just like I continued working on malls for weeks after my big mall post. At some point I'll move onto other building types, possibly hospitals and above ground parking garages. I already have some ideas for them.

Monday, February 3, 2025

Procedural Malls Update

When I got back from my winter trip in the beginning of January, I was expecting to start on new building types. But every day of 3DWorld development involves a third new features, a third going back and reworking the previous feature, and a third fixing random bugs unrelated to either feature set. Sigh. This time was no different. I was sort of in a rush to get malls done before Christmas and left some parts unfinished and broken. I spent the first two-ish weeks of January finishing up malls. This post will cover some of the new additions and improvements I made.

Pet Store Animals and Cages

I showed pet stores with fish tanks and rats in tanks in the last post. Since then I've added spiders, snakes, and birds. I've also added cages constructed from rectangular metal bars.

Spider tanks either have one large spider or several smaller ones. They can climb on the glass inside the tank, as well as the bottom of the lid. If the player steals the tank or removes the lid, this will set the spiders free to roam around the pet store and out into the mall. This is not a wise move in gameplay mode as spiders can bite and poison the player. Spiders are the only animal type that use the same update logic when in a container vs. free. The other animals are removed when the player takes their tank or cage.

Snakes are placed alone in tanks with a half cylinder log to hide under. They're not interactive or animated in any way yet. I don't believe the existing snake animation and movement code would produce acceptable results inside a small enclosure like this.

Rats are now sometimes placed in cages, which is the correct way to house them. Both rat tanks and cages have a wood chips texture on the bottom. Rats walk around inside their enclosures and avoid colliding each other using a simplified version of the update logic I have for regular building rats. These are typically smaller than the rats found out in the open on floors, and I had to adjust their leg animations appropriately.

Interior view of a mall pet store with tanks and cages full of spiders, rats, fish, and birds.

Here is a closeup of some rat cages. They're formed from narrow rectangular shapes, which use fewer vertices/triangles than cylindrical bars. It's still more expensive than drawing cages with an alpha tested texture, so they're only drawn when the player is close to the building.

Rat cages in a mall pet store.

Birds are always placed in cages, which vary in color from white to black to gold. The birds themselves are a random shade of gray that varies from near white to near black. I placed a single stick through the bars of the cage for them to stand on. This is the same animated pigeon 3D model that you can see flying around the city, except that it only uses the idle/standing animation. I should probably add a food bowl at some point.

Bird cages in a mall pet store.


Shoe Stores

Two different people asked me about adding shoe stores. I originally didn't want to add multiple shoe 3D models due to the time required to find and set them up, plus the cost of loading and drawing them. Eventually I caved in and added shoe stores. Yes, the models do add about another second to the load time, and they somewhat reduce framerate. The worst part is that this introduces a bit of lag when the first mall is generated and it needs to load all of the shoe models to calculate their bounds. Is it worth the cost? Probably - I do like the look of these shoe stores.

I placed rows and columns of short walls with shelves in the central area of the store, and more shelves against the side walls. This is similar to the layout of clothing stores and pet stores, so I can reuse that code. I did make the walls a wood texture rather than white plaster for improved color variety. In the fist pass, I added rows of individual shoes in a line along the shelves, all pointing in the same direction. The shoes were intentionally somewhat sparse to avoid dragging down the framerate with too many models.

Initial attempt at a mall shoe store. Note that I've also added cylindrical ducts to some store ceilings. A few of the shoe models seem to have emissive materials for some reason.

That's nice, but shoes do tend to come in pairs. It was quite a bit of work to properly mirror one shoe to get the opposite one. This inverted the normals and triangle winding order, so I had to add special code to reverse back face culling when drawing a mirrored shoe. I also had to annotate each of the eight shoe models with left vs. right shoe so that the opposite could be properly oriented. I continued to place individual shoes on the wall shelves as these are the display items.

I added shoe boxes to some of the lower shelves. This increases variety, and also improves framerate as these boxes have fewer polygons than shoes, and only a single texture. I only wish I had multiple shoe brand textures to use here. The model is animated to open, but I haven't added support for this yet. Here is an updated screenshot of another shoe store with these changes.

Updated shoe store with shoe boxes on lower shelves and pairs of shoes on upper shelves.


Clothing Store Mirrors

It's always fun to add mirror reflections to scenes. I do have a few mirrors in the current malls, specifically in restrooms and in bedrooms sets of furniture stores. Mirrors definitely increase frame time since the scene must be drawn twice. However, if I make them small and narrow, I can cull out most of the scene geometry which isn't visible in the reflection.

I added person height mirrors to the back walls of some clothing stores, at the end of an aisle. I suppose this may reduce the chance of a zombie sneaking up on the player. Maybe at some point later I'll add proper changing rooms. Here is an example mirror.

Clothing store mirror where the player is visible. No, you can't try on clothes (yet).


Furniture and Appliance Store Additions

I got some feedback on furniture and appliance stores, which led me to add more items. Furniture stores now have lamps and potted plants. In addition, I changed some of the placement rules to avoid blocking doors and clipping through walls. Here is an updated view of a furniture store.

Furniture store, now with plants added to living room sets.

Appliance stores now have furnaces and water heaters. I'm not sure these actually belong in a mall appliance store, but it was easy to add these existing items. I also changed the object movement logic to allow the player to push and pull these appliances and plumbing fixtures. This was needed because I found it was occasionally possible to get stuck between objects. It would be fun to add some sort of player object pushing maze/puzzle to these rooms!

 

Round Support Pillars

I saw a post made by another developer that included a modeled shopping mall. This one had round/cylindrical pillars rather than my square/rectangular pillars, which seemed like a good addition to make. Now 50% of malls have round pillars holding up the walkways. I actually prefer these over the square pillars, so maybe I should add them more than 50% of the time. Here is an example.

Some malls, like this one, now have round/cylindrical support pillars. Shiny!


Food Court Recycling Bins

Someone suggested adding food court recycling bins, so I did this. Now some of the trashcans near food courts are blue recycling bins rather than silver or brown trashcans. This applies to both the round and square variants. I had to place some of them next to stairs and escalators so that I had enough placement spots for both trashcans and recycling bins.


Interactive Store Gates

It's no fun when stores are closed. I changed the store gates to be dynamic and player controlled with up/down buttons next to the gate on the inside of the store. If the gate starts closed, the player can usually still access the store through the back hallway and enter to raise the gate. This is a good way to escape from a pursuing zombie, since they can't use these buttons. And if you're fast enough, the button can be pressed with enough time to get under the door before it closes, locking a zombie inside. This is only a temporary solution though, because zombies can also use the back hallway to escape the store. It just takes them a long time to walk around and get back into the main mall concourse.


 

Mall Skylights

Malls seem disconnected from the rest of the world because there are no windows. So far I haven't found a way to make windows work correctly and efficiently, in particular due to the alpha blending problems when looking through multiple layers of glass. So all of the malls have been placed underground. I did eventually add skylights in the mall ceilings in cities though. I haven't yet found a way to extend this to non-city buildings, where the ground may be uneven or far above the mall ceiling.

Skylights are cut into both the mall ceiling and the city pavement above, similar to how mall access elevators were added. This can only be done when the area above is open rather than a building or road. Then when the smaller city objects such as benches are placed, areas over skylights are marked as blocked. The player can see through them in both directions. The city, terrain, and sky above are visible from the mall below. I did disable drawing of cars and pedestrians in this case for performance reasons, though they're usually not visible from such a steep angle anyway.

Mall skylight, viewed from inside the mall looking up into the city above.

The player can look into the mall from the city above as well, and even walk over the skylight. It's not perfect. Some of the smaller objects (including people) aren't drawn, and shadows may not be correct. If you look closely you can also see that there are some trees in the city above, but their roots don't extend into the mall below. I attempted to mitigate this problem by moving trees away from skylights, since they're placed later in the control flow.

Standing on the city sidewalk and looking down though the skylight at a mall below.


Building AI Navigation

Finally, I fixed several problems with AI navigation/path finding in malls. In particular, they can now enter and exit malls through the adjacent parking garage door. However, this only works when the mall and parking garage are at the same floor levels. This was previously never the case, but now the placement code will attempt to adjust the depth of the mall so that it can align with the floor of parking garages that are at least two levels tall (since mall levels are 2x normal building levels). AI people can't pass when the parking garage and mall are at different heights because I haven't gotten path finding to work on the odd fan-shaped stairs that lead up to the door on the mall side.

Building AIs can also now use the back hallway stairs and elevators. These were more difficult to handle because they span/connect alternating floors rather than tightly packed adjacent floors that normal stairs and elevators connect to. (Remember, mall floors are spaced two normal floors apart, while back hallways are only one normal floor height tall.) The stairs require walking back and forth four times total within the rectangular enclosed space to move one floor up or down. This logic is hard-coded into the AI path finding system.

The third addition was to allow zombies to use escalators when chasing the player in malls. The escalator code had originally only been made to work with retail escalators that connected the ground floor to an upper glass floor. Now escalators can be arbitrary lengths and the AI path finding code can handle this. The path length estimate code isn't very accurate when stairs and escalators are involved, so they may not take the shortest path. I think this is acceptable because it makes zombies less predictable, and they will often converge on the player along different paths.

Future Work

The next type of building I'm working on is a factory, or possibly something like a warehouse or chemical plant. I'm pretty far along in development already. I've added some basic machines, ladders, catwalks, fire sprinklers, and assorted floor clutter items. I'll have more of an update on this later. I'm sure it will take a long time to complete, though probably less than half the time it took me to implement malls. Every new feature can reuse more of the existing code...

Wednesday, December 18, 2024

Procedural Malls

I started working on adding procedural malls to 3DWorld about two months ago. I actually had the item on my todo list for a while longer, but I didn't feel like I had all of the components for malls until recently. I finally got those last features from retail areas (escalators and glass floors), conference rooms (glass walls/interior windows), and exterior city elevators.

I can tell already that this will be a very long post. It should be, considering I haven't posted anything on Blogger in two months. I'm actually not completely finished with mall interiors either. I do feel like I have to post something now before my trip to PA for Christmas and New Years, because I may be too busy in January to have much time to work on this. I'm going to do things a bit different in this post by writing the text before adding the images. I'll be sure to scatter images around to break up the big blocks of text, once I'm done with the drawing code.

Has anyone attempted to generate procedural malls before? I can't find any online projects or articles on that topic. When I say "mall," what I really mean here is indoor malls rather than strip malls. And specifically in my case they're underground malls. Putting them under the ground makes for an easier starting point for both generation and rendering. I don't need to worry about windows, which means the mall interior can be drawn without having to display anything other than the mall, and only when the player is inside the mall. This allows me to pack more items in before I need to worry about memory usage and draw performance.

That doesn't mean the task was easy. These malls are massive, at least compared to the rest of the buildings and underground areas. They extend far outside the terrain tile the building was placed on, far enough that I had to reduce the fog effect of the scene to make the interiors look brighter. The largest mall is a significant fraction of the length of a city center.

 

Mall Room Layout

The base of the mall is the concourse, which is a long rectangular room that extends from the parent building's connection as far out as there's space. I did add a length cap (of around 1000 feet) to keep it reasonable, though there's no hard limit based on the buildings or terrain systems. The connecting point is to the building's parking garage, which is the only other underground room/part. This isn't ideal, but at least it means visitors can find parking. I added an additional elevator that reaches the ground above the mall for buildings placed in cities. I'll describe this in more detail below.

All parts of the mall must fit into unoccupied underground area. The concourse is incrementally extended first, and then slightly widened. At each point the terrain above the ceiling is tested to make sure it completely covers the new section. Then I check that the room doesn't intersect any previously placed building basements, extended basements, in-ground pools, bodies of water, or sewage tunnels. Since the room is incrementally expanded on three sides, it may not remain centered on the parent building. Once the base floorplan has been set, the mall concourse is extended downward one floor at a time until either the selected number of floors is reached or an obstacle is encountered.


A large mall stretching out about a thousand feet into the distance with some 50 stores on two levels. I just had to add a palm tree.
The mall concourse is multiple stories tall with vertical pillars supporting the upper levels. I finally had to make the floor to ceiling distance higher than normal buildings. I used a value of around 2x the normal floor spacing, or 16 feet. The max number of floors is technically limited to 255, but I start running into performance problems at more than 5 floors. I set the max to 3 for now, though I've tested up to 10 floors without crashing. I think 3 floors is plenty as it adds space for up to about 100 stores. The upper floors have open cutouts so that players can look down at lower floors, and walkways with railings along the open areas. Each adjacent level is connected with several sets of stairs and up/down escalator pairs.

I placed a single elevator near the center that spans all floors. Then I added a digital or analog clock to the front and back of the elevator on each floor so that patrons would know the time. These are the same clocks I added a year ago, and they dynamically update to show the current real time. I often looked at these clocks myself while writing the code and wondered why I was up so late working on these malls!

A 7 level mall, just to show that it's possible. Something this large may not run well on low end or old computers, but it's functional.

Stairs and escalators reaching the lowest level can end on the large open surface of the floor. Those ending at middle levels would be floating in the air, so I added small landings connecting these exit points to the upper floor walkways at the sides of the concourse. Metal and glass railings are placed around all openings to keep the player and AI people from falling. The mix of low railings and transparent glass is mean to avoid obstructing the player's view.

Stores are placed to either side of the mall concourse on each floor, but only if there's space. Stores have random sizes so that there's a good mix of large and small spaces in each mall. Any store that clips through the terrain or intersects another building or tunnel is excluded, and the space is left empty. I also added stores to the two ends of the concourse if they fit, except for the place where the mall connects to the parking garage. All stores connect to the mall through an opening that may be gated, plus transparent glass interior windows between the store and the mall. In the future I may give the player control over store gates during gameplay mode.

Some floors have a pair of men's and women's restrooms near the center on one side and a water fountain between them. If there is a back hallway, it also connects to the other ends of the restrooms for employee access. These are the same restrooms that appear in office buildings with sinks, stalls with toilets, and a row of urinals in the men's room. I finally added support for door signs that rotate with doors, and used this to add male and female icons to the doors. I may go back and use this feature to add signs on office doors rather than next to them.

A pair of mall restrooms with a water fountain in between. The doors automatically close and the restroom lights are motion activated with a timer.

I also added back hallways connecting the sides of stores opposite their public entrances. These may eventually be expanded into storage rooms and other utility areas. The hallways wrap all the way around the mall if there's space, connecting into a ring. Lights are placed sparsely on the ceilings, which gives these areas a darker appearance with more shadows. Each completed end has an elevator next to a U-shaped stairwell that connects all floors that have hallways, assuming there's more than one. These hallways allow access to some stores even when the entrance gates are closed. Building AI people can use the elevator, but I haven't yet added AI logic for these new style multi-level wraparound stairs.

Back hallway stairs and elevator for the above 7 floor mall. I had to add a new type of wraparound stairwell that has a railing at the top floor.

Mall floors select a random marble or granite tile pattern, and ceilings use the same ceiling tile texture as office buildings. I chose brighter colors for mall interior walls to provide more of a contrast from the whites and grays used in office buildings and parking garages. This includes light blue, light green, and various shades of light yellow-orange-brown. Back hallways were textured with gray concrete similar to most of the other basement rooms.


Object Placement

The mall concourse is filled with a variety of objects. I added two types of trashcans along the walls. One is light brown and rectangular with a lid and opening, while the other is a metal cylinder with an open top formed from a black torus. I placed benches randomly along the walls, added pictures between stores, and put a water fountain between the bathrooms. These are a new style of mall bench with a molded colored plastic back + seat and black metal legs. I added plants to the sides of the stairs, escalators, and support pillars. Some pillars also have fire extinguishers on them.

The lowest level has extra space for placing objects because there are no open cutouts. I filled the open spaces under the cutouts with one of several large items or item groups. First, there is a fountain near the center of the mall with benches placed to either side. Next, I assigned an area as a food court and filled it with tables of various sizes and chairs. Some of these tables have additional small items placed on them, in particular food-related objects such as pizza boxes, bananas, water bottles, and cups. I haven't yet added actual restaurants, but they will likely be included sometime in the future.

The remaining open spaces are filled with either large potted palm trees or groups of vases/sculptures. Palm trees may look odd inside a mall, but I did want to try and use every type of object I had available. In fact I even tried to add a pine tree that I could maybe turn into a Christmas tree, but I couldn't get the alpha blending of the leaves to look good when mixed with the transparent store windows. It's nice to have some green spaces indoors, and the trees fit well with the potted plants. These sculptures use the same shapes formed from procedurally generated rotated profiles as the smaller vases and urns that can be found in houses.

Mall food court with tables and chairs, but no actual restaurants (yet).

Finally, it was time to populate the stores with items. Since malls can have as many as a hundred stores, I had to take extra care not to place too many individual objects in total. Grouped objects such as shelf racks, bookcases, shelves, etc. work much better because they can expand to their individual contained objects dynamically as the player interacts with them. This is a huge advantage of my virtual object system, which I feel is unique to my specific game engine.

Some objects are common to most of the store types. These include checkout counters with cash registers, security gates created with a grid of metal bars, tall support pillars, ceiling ducts with vents, and anti-theft sensors. The theft sensors in particular were a fun addition because they're interactive. The player inventory system now keeps track of which room/store objects are taken from, and the sensors can detect that the player is leaving the store with stolen items. I added an alarm sound and flashing light to these devices. The easiest way to shut them up? Steal the sensors as well!


 

Store Names

Before I describe how I've generated store interiors, I need to mention store names. What's one thing that malls are full of? Signs, right? Big, bright signs enticing visitors to enter the stores. Now I'm pretty limited here, considering I only have one font to work with at the moment. I can't add fancy signs - yet.

At least I can try to come up with decent store names. My first attempt was to use the Markov chain based name generator I used for planets, street names, last/family names of people, etc. I found that some of these names work, while others are difficult to even pronounce. I could do something closer to my company name generator that works be selecting random permutations of words from a list. The problem is that this tends to create names for a particular type of business chosen randomly, while I want the name to match a specific type of store. I needed the classification before the name, compared to how I handled buildings here. I also don't want to run into registered trademark trouble by selecting names randomly from a list of existing, real world store names.

After that I turned to searching for store names online. The search turned up mostly AI-generated name lists divided into specific categories. In the end I found a free online AI name generator and gave it prompts for the various types of stores I wanted, then manually reviewed, copied, and pasted the names I liked into a ~300 line text file. Here it is, complete with the sources I used. 3DWorld parses this line-based text file and creates a map from keyword to an array of names. Take a look at all the signs in the screenshots of this post for examples of what these names look like.

 

Store Types

Next, I'll go over the various types of stores currently found in 3DWorld's malls. There are retail stores, clothing stores, bookstores, furniture stores, food stores, and pet stores. I have appliance and plumbing stores in the list as well, but they're not yet selected/enabled because I haven't added any objects to them. Retail stores are further broken into a number of categories: food, electronics, household goods, kitchen, and boxed goods. Each type and category of store has a unique set of objects that it can randomly choose from per-shelf. Most of these are one of the existing ~180 room objects I've added to buildings so far. Some of these stores are more complete than others at the time of writing this post. I don't want to get into all of the details as this would make my post a huge wall of text and a beast to load with so many images. I'll add some brief descriptions of each store category that I've added below.

Retail Stores

Retail stores consist mostly of rows of what I call "shelf racks", which are the same objects I added to the ground floor retail areas of some office buildings almost a year ago. The only changes I had to make to shelf racks was to add control over object types so that they would match the theme of the store. These objects are covered pretty well in last year's post, so I won't go into the details again here.

Retail food store with rows of shelves containing food and drink items. Retail kitchen, electronics, and boxed goods have the same shelves but with different types of items.

Clothing Stores

To me, clothing stores look like huge closets. Therefore, I started by filling them with the contents of closets. In other words, clothes on clothes hangers that hang from horizontal bars. This isn't the first time I've reused closets. I actually used them to add clothes lines to residential yards, but I'm not going to get into that topic right now. The point is, this was fresh in my mind from the clothes lines. The more ways I can find to abuse and reuse code, the less new code I have to write, and the faster I can make progress. This is the key to implementing malls in a few months rather than a year. Ah, I'm getting distracted.

That handles the center areas of the store, but I still need to place objects along the walls. Maybe shelves with folded shirts and anything else similar that I happen to have? I would add shoes if I could find suitable low poly models of them. I definitely need to be careful with the model count though if I expect people to play this game without a fancy gaming PC. With this in mind, I mixed some flat rectangular images of shirts and pants in with the folded T-shirt models on wall shelves.

Clothing store containing rows of metal racks with shirts and pants on hangers. Shelves on the sides of the room hold folded shirt models and images of T-shirts and jeans.

Bookstores

Bookstores are pretty simple. They mostly consist of bookcases stretched out short and very wide and placed back-to-back in rows, with additional bookcases along the walls. It's easy enough to hack the bookcase creation code to form these. The only problem is that the performance is terrible. I attempted to create an entire large mall full of bookstores, and it takes nearly a second to generate and 600MB of additional GPU memory. There are something like 200K total books with millions of characters of text in all the author and title strings. Hopefully the performance is acceptable if I limit bookstores to only 10% of the total. I'll have to go back and optimize this eventually.

An example bookstore with dozens of bookcases arranged in rows containing thousands of individual unique books. Each book is unique and can be taken by the player.

Furniture Stores

Furniture stores are full of ... furniture, which I already have quite a bit of. I can reuse the various objects currently placed in houses and office buildings: tables, chairs, beds, dressers, nightstands, couches, and desks. I divided the store into a 2D grid of square sub-rooms which are classified as bedrooms, living rooms, dining rooms, kitchens, bathrooms, or offices. I added enough empty space between these sub-rooms for people to walk. The difficult part is organizing these into a coherent placement where rooms of the same types are grouped together. I'm not quite sure how to do this incrementally (one sub-room at a time), so I'll leave it for future work. I then added walls next to beds in interior sub-rooms with pictures on them that simulate background room walls. There are many areas for future improvement.

Furniture store with a mix of bedroom, living room, dining room, and office furniture. This is one of the larger stores at the end of the mall concourse.

Food Stores

Food stores are difficult. I already have retail areas with shelves full of food products. However, with this category I was thinking more about restaurants, coffee shops, and other places you would find around the food court. The problem is that I don't have many food related objects for buildings. All I really have are pizzas and bananas, and nothing really store related. Stoves and pans are about all there is. Food items, or rather anything organic, are quite difficult to generate procedurally. I can't get away with making them from cubes the same way I created much of my furniture. I suppose some fruits aren't that hard. After all, an orange is really just an orange sphere, right? For now I guess these stores will be mostly empty. Well, I suppose I can at least add some wine racks.

Sorry, food stores don't exist yet, so there's no screenshot for me to share.

Pet Stores

I have a limited selection for animals that I can add to pet stores. At this point I don't have 3D models of the usual pets such as dogs and cats. What I do have are rats, snakes, spiders, fish, birds, butterflies, cockroaches, and flies. I guess I'm going to stick to the first four or five though, since most pet stores don't carry insects.

I already have fish tanks that I can add - one down. I can reuse the tanks without water for snakes and maybe spiders. It would be pretty awesome if I could make spiders climb the inside glass of the terrariums! I'm sure I can either find or generate some sort of cage models for rats and birds. But in the meantime, I'll put rats in glass tanks as well. I know that's not good practice as the lack of ventilation is bad for their health, but I do see this done at some pet stores. Don't expect me to be filling these with toys for the animals any time soon though. It might be interesting to set some animals free and allow them to wander around the store since I already have the logic for this. I can possibly allow the player to pick animals up and put them back down.

An example pet store, with a closed gate. Currently pet stores contain only fish in fish tanks and empty glass tanks that will hold rats, snakes, and spiders in the future.


City Elevator Access

I wanted to add mall entrances other than that single door from the parking garage. What if pedestrians who aren't in cars want street access to these new malls? The problem is that the mall is underground and adjacent to the parent building, which means that there's no other place where I can add a door between them. The building system doesn't support secondary buildings connecting across terrain tile boundaries, while malls generally span multiple tiles. Cities have flat terrain above underground rooms, but areas outside the city have procedurally generated terrain with erosion that I can't easily add a building entrance to. This leaves only street level city building entrances to work with.

The mall entrance from the underground parking garage has fan-shaped stairs that descend to the floor of the upper level of the mall. I haven't added support for non-axis aligned railings, so I can only add railings along the back wall.

The obvious solution is to extend the existing elevator in the center of the mall up another floor to ground level. The placement system needs to check for intersections with above ground city objects such as buildings, roads, parking lots, trees, etc. If an intersection is found, either the intersecting object or the mall entrance must be moved. I chose to move the mall entrance since there are typically multiple candidates for mall elevator locations. They can be connected to either side of any available opening in the upper floor walkways. One limitation is that single floor malls have no need for an interior elevator, so there's nothing to extend up to street level. However, these rarely occur in cities because the flat terrain doesn't allow for the basement rooms of buildings at different elevations to block the area under mall concourses.

Malls are always connected to two floor parking garages since the upper mall concourse level is two floors tall and parking garages are at most two floors. This means that street level is always exactly one floor up. The difficulty here is that the elevator may still be far from the parent building, so the entrance can't be made part of the building. It must be a separate city structure. Fortunately, I can borrow parts of the earlier walkway and city elevator system to create a new city object that sits on top of the elevator shaft to form the exterior surface.

An above ground mall entrance elevator inside a city next to a building. Lighting is not working properly yet. People can walk by but not enter these elevators.

This gives me a drawn elevator, but it's not yet functional. The elevator buttons can't be pressed by the player because this logic is only run when the player is inside buildings. The best fix I could find was to add an invisible rectangular area over and in front of the elevator's entrance that's considered to be part of the building so that the player can call the elevator to that ground floor. It was quite messy to implement, though I did eventually get it working. I slapped a "Mall" sign above the entrance, added a "G" button label for "ground floor", and considered this part done.


Zombie/People AI

I didn't originally plan to write the AI logic for mall navigation because I assumed it would be a huge time sink to handle all of these stairs and escalators, gated doorways, and larger spacing between floors. In the end I did put some effort into this, scattered between the various other additions. Regular building people weren't that difficult to handle. I had to change some 20-30 places in the AI navigation code to support stairs, escalators, and elevators of variable heights. I added logic to the navigation graph to include non-gated doorways between rooms. And I had to put extra effort into handling those mall back hallway elevators that were outside of any interior room bounds.

A three level mall where the levels are connected by stairs, escalators, and an elevator. The stairs and escalators of the middle level connect to small landings. Building AI people can use all three of these.

I didn't complete everything. For example, people don't currently walk on those fan-shaped stairs that connect the parking garage to the mall concourse because they're not in a standard shape and have an odd height difference between the two floor levels. People don't use back hallway stairs either as I haven't written the AI logic to use stairs that wrap around in a cube-shaped spiral. Zombies sort of work, though they don't follow the player in all areas of the mall. In particular, places around stairs and escalators give them trouble since the collision boxes that cover those objects are too conservative. I'm sure I can fix all of these in the future with more effort.

Debug view showing the exterior of a mall that's under the terrain. The gray strips along the outside are the back hallways that wrap around the mall stores. There's a 7 level mall in the back right.


Summary and Future Work

I've added quite a bit of new content for malls. Some of these objects have been reused in other building and room types. For example, the plastic tables and chairs I used in mall food courts are now also used in offices. The mall style trashcans are used in office building lobbies and hallways. I have some ideas on other objects to add as well, but I can't add too many. I'm already at 185 unique room object types. The current limit is 256 unique types because the type field is stored in an 8-bit integer, which only has 256 possible values. I put a lot of effort into packing the room object class into 64 bytes, which should be a multiple or exact fraction of the cache line size.

Many of the store types are incomplete. Notably, this includes food stores, appliance stores, and pet store animal containers. This leaves plenty of room for later additions and improvements. Expect to see more mall-related posts in the future as I continue to add content. In particular, there may be an update post on pet stores once I have all of the animals added to their containers.

As always, the source code for all of this is publicly available on GitHub. The mall code in specifically can be found here.