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.

Friday, October 25, 2024

Procedural Buildings: Sewer Tunnels

I was watching some YouTube videos of urban exploration where people were exploring storm drains under a city, and this gave me something else to add to 3DWorld's procedural cities. I've improved basements in the past few posts by adding interrogation rooms and machine rooms. Now it's time to add underground tunnels. I originally thought of connecting these to the water (ocean), but none of the cities are close to water. Also, the water is far from the player spawn point near the center of the island. So instead I decided to connect tunnels to basement rooms instead.

I started by iterating over all of the locked ("false") doors I had added at the end of extended basement hallways and long rooms to make them appear larger. Any door that was far enough underground and had empty space surrounding it on three sides was a candidate for placing a sewer tunnel. I added a vault-style heavy metal door with a wheel handle connecting the room to the tunnel that was open to the player. Tunnels run perpendicular to the room and door in both directions and may have right angle bends in their paths. I added metal grates in the form of vertical bars near the ends of the tunnels and made the very ends black. This, combined with dark fog, made the tunnels appear to continue past the grates.

Here is a view of a sewer tunnel system under the ground with the terrain and grass drawing disabled. This network runs around the perimeter of the extended basement of an office building, but in general it can go anywhere there's available space. I may even connect tunnels between multiple buildings in the future like I already did with extended basement hallways.

View from outside a tunnel system that runs under the ground. The terrain and grass drawing has been disabled. The dark rectangle on the bottom right is the sewage quad drawn under the bend.

Tunnels have dark brown sewage flowing inside them with a randomly chosen level and flow rate. They also have smaller pipes connecting to them on the sides and thin metal pipes passing through them along the top. I added rats on the ground in some segments that squeak and run to the nearest grate when the player approaches. I also added spiders that walk back and forth upside down along tunnel ceilings. Spiders don't currently interact with the player.

Tunnels are drawn as cylinders, with quarter torus sections for bends. It actually took me quite a bit of experimentation to figure out what the correct bend geometry was. Fortunately, I had already added half torus drawing for bucket handles, so a quarter torus was simple to add. I used a concrete texture for the walls and applied the wet effect to these to give them streaks of darker color. Speaking of darkness, there's no light inside these tunnels, so the player must bring their own flashlight or candle to see anything. See how dark this is? It's completely disorienting to walk through here without a light.

Flashlight view of a sewer tunnel near the place where it connects to a basement room, with a spider visible on the ceiling.

I did add logic for zombies to follow the player into the tunnels with a recursive path finding algorithm that forms a path between the connected cylinder and quarter torus sections. These are currently dead-end death traps for the player. Maybe I should add some reward at the end of the tunnel? I'm not sure what to place here. A vertical shaft leading back up to the surface that serves as an escape path? That could work in cities where the ground above is flat.

I'm considering adding T-junctions to sewer systems. I haven't yet figured out the mathematical function needed to join cylinders into a T-junction in a smooth and clean way. I do have a T-junction where the tunnel meets the room doorway, but this is square on the doorway side. It's easier to cut a square hole into a cylinder (remove half/180 degrees of the cylinder) than a circular hole. 3DWorld has CSG support for cubes, some types of cube + axis aligned cylinder operations, and a few others, but no cylinder vs. cylinder operations. This would be a problem for vertical escape shafts as well. It would be so much easier if I used rectangular tunnels. The problem is that I already have extended basements, which aren't much different from rectangular tunnels. The main difference is the lack of sewage on the floor!

Here is an earlier video where I explore a sewer tunnel with a flashlight and candle as light sources.

The player can find both light sources in buildings. Flashlights shine further with a narrow beam. Candles light only nearby objects, but in all directions. There are no ceiling lights, shadows, or indirect lighting.

Here's another video where I added spiders to the ceilings.

I think I'm done with basements for now. I may add underground shopping malls sometime in the future if I can figure out how to do it efficiently. The next item on my task list is writing the logic for cars to navigate city parking lots. I'm sure that will be challenging, considering how difficult cars have been to work with in the past.

Friday, October 11, 2024

Procedural Buildings: Machine Rooms

I've been adding new room types to 3DWorld's procedural buildings lately. I wrote a blog post on conference rooms, then a short post on interrogation rooms. The topic of this post is machine rooms. I've been wanting to add procedurally generated industrial type machines/devices to basements for a while, ever since I revisited basement pipes. I've also wanted to add more variety to extended basement rooms.

I've been working on adding code to route basement and parking garage pipes down the extended basement hallways and into leaf rooms. But it only makes sense if there are objects in these rooms to connect the pipes to. I do have bathrooms with sinks and toilets down in the basement, though not every building has these. Another option is to add more water heaters and furnaces similar to the ones placed in house basements and office building utility rooms. The appliances I've created are more residential sized and look out of place in a large open basement room though.

I added a new type of building room object called a "machine" that's represented as a bounding box placed on the floor and against a wall of the room. All placement and collision detection handles this as a box. However, the drawing code is free to add any details it wants when the vertex data is generated and sent to the GPU. None of this geometry is stored CPU side, it's all created as temporary data that's drawn later. An added benefit of machines being placed in basements is that the vertex data doesn't need to be generated until the player enters the building. This allows me to create very detailed geometry without the need to worry about optimizing for memory or generation time, since these are only found in one building at a time. I do technically create machines for multiple buildings ahead of time to help with visualization and debugging, but I don't think it makes much of a performance difference.

Each machine consists of a concrete slab base and one or two main components, which can either be rectangular/cube shaped or vertical cylinders (such as storage tanks). These larger components have smaller boxes and cylinders attached to their exterior surfaces with different colors and textures. I then added some special decoration objects that are already used in other places in buildings. These include AC units, vents, valve/wheel handles, and breaker boxes. Some breaker boxes are open to expose the interior. To finish things off, I added a variety of pipes and ducts connecting the components together and going into the walls, ceilings, and floors around the machines. These use multiple materials including plastics and metals (copper, brass, bronze, steel, and rusted). I used special checks to make sure these added detail objects don't intersect each other or clip through adjacent walls or machines in incorrect ways.

I found ten free textures online to use with these machines. Most are some type of metal panel or plate texture, some of them with rust and scratches. Only one of them has a matching normal map. I may look for better textures with normal maps later, but these are fine for now. I haven't put any effort into aligning textures to geometry because it's too difficult to automate this for this many different textures.

Here is an example of a long and narrow machine room.

Machine room with random machines lined up against the walls. Each one is unique.

 

Note that these rooms are somewhat brighter than they normally appear to make them easier to see. I prefer to have these deep basement rooms be darker. Here I have indirect lighting enabled, though it doesn't work very well due to the way rooms are randomly and sparsely placed, compared to the dense rectangular floorplan of above-ground building interiors. At least the shadows on the lower walls and floors are correct.

Machines are placed along the sides in a way that allows space for the player and building AI people to cross the room between them. I added extra clearance for doors so that they're not blocked. The rooms in these screenshots have up to 10 machines for testing purposes, though for normal buildings I'll probably set the max count to 4.

A different machine room with different machines and many cracks on the walls, ceilings, and floors.

I definitely like the way the cracks and water damage fit with the scratched and rusty metal textures I'm using with machines. The crack effect only applies to the walls, ceilings and floors though. I don't think cracks go well with metal surfaces. I did apply the wet/water damage texture effect to machines. This give the surfaces a darker but more shiny appearance. Here's another machine room with water damage and stains but no cracks.

A machine room in the basement of a house, with plaster walls.

I think I'm done with new room types for now. I plan to continue to work on extended basements in the near future. Next up is underground tunnels/pipes that the player can walk through. I'll likely have a blog post on that topic within the next few weeks.

Tuesday, October 1, 2024

Procedural Buildings: Interrogation Rooms

The interrogation room can be found deep inside the extended basement, after a long walk down dark and narrow passageways. A single empty chair sits in the center of the room under the light, facing the door.  Buckets of unknown colored liquids are placed around the chair. Bottles and bits of trash are strewn across the dirty floor. The walls, ceiling, and floor are wet, stained, and cracked. A ladder with an unclear purpose leans against a wall.

An interrogation room with cracked walls. It's not very bright in here, so I lit it up with my flashlight.

Interrogation rooms are relatively rare and are only placed in extended basements of buildings with water damage. They can appear in both houses and office buildings. Sometimes the chair has fallen over backwards, and sometimes the light doesn't work. Broken lights shower sparks over the chair. The ladder is optional. This is the only room that currently contains the new bucket-with-liquid object.

These rooms don't serve a purpose yet. They're mostly just there to be creepy, though I didn't go so far as to add blood, tools of torture, or anything like that. I might not add this at all, since it's not supposed to be that type of game.

Also, take a look at my new basement cracked surfaces effect in the screenshot above. I replaced the old shader code with new code that uses a Voronoi grid and an intensity mask to apply cracks to selected areas. It's based off of this Shadertoy shader. Cracks are added as a layer that modifies the material properties of the surface it's applied to.


Monday, September 30, 2024

Procedural Building Conference Rooms

I'm pretty happy with the look of glass upper retail floors added in my earlier post. Maybe they're not very practical for public spaces, but they make the room look larger while also allowing for increased usable space. I need more glass in these buildings. It would be interesting to have glass walls as well. Maybe for conference rooms? We have some real conference rooms with glass walls/windows at my work office.

The first step is to choose which rooms will be conference rooms. Since most of the buildings in 3DWorld share the same vertical floorplan across many floors, it makes the most sense to have one or more dedicated conference room on each floor. The ground floors of office buildings do have some special rooms such as storage rooms, security rooms, and utility rooms, so I can have the floorplanner overwrite the conference room with a special room type on the first floor.

Since I want to add glass walls to conference rooms, it makes the most sense to place them adjacent to hallways. A glass wall between two conference rooms, or a conference room and an office, would be odd. And I don't even want to think about what a glass wall shared with a bathroom would be like! I also have a constraint that the conference room can't have an exterior wall, since the interior window won't alpha blend properly with the exterior windows. (I spent a long time trying to solve this with glass floors and never found a solution I was happy with.) Fortunately, this means I don't need to worry about walkways connecting between buildings that end at conference rooms. The candidates are all rooms next to an interior hallway that have doors that either open into a secondary hallway that meets the other hallway at a 90 degree angle, or to another parallel hallway one row over. Another requirement is that conference rooms don't have any overlapping stairs or elevators. This rules out some rooms that have notches cut out where elevators are placed along the sides of the main hallway.

There is also a size preference. I want to add large conference room tables and many chairs to these rooms, with space around the sides for people to walk. The conference room should be the largest room that meets the placement requirements. I gather a list of all legal room candidates, find the largest one, and select all rooms within 90% of the largest room's area as possible conference rooms. Then one or more of these rooms are selected. Any room that has a conflict (such as intersecting stairs) on one floor is changed to a different room type such as an office for that floor. This sometimes happens with conference rooms at the top or bottom of a building stacked partition where stairs extend above or below.

Each conference room has a single large table that runs most of the length of the room, with as many rolling office chairs as will fit along each side. One of the walls at an end of the table has a large TV hanging from it, and another wall has a large whiteboard. Neither of these can be placed over the window or door(s). I found a conference room phone 3D model that I placed on most of the tables in a random position and orientation. Then I added some random items on top of the tables such as laptops, pizza boxes, books, cups, and water bottles. Some rooms have trash cans, recycling bins, and/or potted plants. Maybe I should add pens, pencils, and papers as well.

Here is what an example conference room looks like. There are actually two adjacent conference rooms with glass windows on this hallway. The doors open into the next hallway over, toward the back.

Two conference rooms in an office building, viewed from the hallway through glass windows.

I added proper collision detection for these glass panels that works with the player, building people, zombies, rats, snakes, insects, thrown objects, etc. Spiders can climb on the surface. I had to fix a number of problems related to lighting and occlusion culling so that objects on the other side of the glass were lit and visible even though there was no doorway between the rooms. I was originally worried that the AI would have path finding problems if a zombie saw the player on the other side of the glass but couldn't pass through it. But no, the existing system worked fine and the zombie walked out the door and around the corner to reach me. They target the last known location of the player when the player isn't visible.

Lighting isn't perfect for these rooms. Light will pass through the glass from the adjacent room, but the sides of the glass are only lit by lights on the same side. This means that the glass on the inside of a room will appear dark when the room lights are off but the adjacent room lights are on. This is one reason why I turned all the lights on for these screenshots. I did make sure to flag conference room lights with motion detection logic so that they automatically come on when the player enters, which helps to hide this problem. The player can manually switch them off though.

Conference room in an office building, viewed from inside.

Sometimes the window is on the shorter wall of the room. The conference room below has a long whiteboard and short glass window. This room is large enough that it needs two ceiling lights, rather than the more common (and efficient) one light per room. I believe there were 7 chairs on each side of the table.

Larger conference room with a long table that has a phone and a laptop on it. There are 14 chairs.

I haven't made these windows reflective yet. That's a complex process that reduces framerate significantly as some parts of the building interior must be drawn twice. Most indoor windows are designed to be anti-reflective anyway, so the reflections are only visible at sharp angles. I don't feel that the benefit of adding reflections justifies their cost.

While writing this post I though that it would be interesting if the player could break, or at least crack, these windows. Maybe throwing a large enough object at the window will create a crack, similar to throwing a ball at a mirror. The problem is that the largest object the player can actually throw is a ball. I don't think a basketball or soccer ball would normally crack a window. Maybe I should add some new object that can be thrown, where the only purpose is to crack windows. Should the player be able to throw a fire extinguisher? That would do it. Currently fire extinguishers can only be dropped. Or maybe the player can throw a laptop left on the conference room table, or the phone? Should I allow zombies to break through windows to get to the player?

Thursday, September 19, 2024

City Walkway Elevators

I added elevated walkways and skyways to 3DWorld's procedural cities earlier this year. The skyway with its moving belts on the floor provides the player with a transportation system that's several times faster than walking, assuming they're not setting the movement speed higher like I often do when debugging. The problem is that the skyway is very high up in the air, and it takes a long time to get to it by taking the stairs or elevator from inside a building. This means that it's not a very effective transportation system, considering the skyway is also limited to a single city.

I need to add a faster way for the player to gain elevation without passing through a building. One idea I had was to add elevators that start at ground level in an open area of the city near the sidewalk and extend upward to connect to the side of a walkway. I had this idea around the same time as my escalators, which I showed in the previous post. I decided to make these elevators have transparent glass walls similar to the upper glass floors I added to retail areas. However, I haven't made these glass elevators reflective, so the process has been easier. People don't use these elevators (yet) either. All they have to do is avoid walking into the elevator shaft.

Elevators are placed at the same position as the support pillar under the walkway, off to one side. This is typically around the midpoint of the walkway span. The pillar region has already been chosen to be in an open area free of other objects, which makes it likely that the elevator shaft can fit there as well. The elevator is omitted if there's a collision with another object such as a building. This includes objects that block the entrance to the elevator on the lower level.

Here is an example of an elevator connected to a relatively low walkway between two buildings that's two floors tall. There are doors at both the top and bottom that open and close to prevent the player from falling into the elevator shaft or being crushed by the elevator at the bottom. The upper floor doors open to the sides like normal elevator doors. I couldn't find a good way to add side opening doors at the bottom because of the way the elevator shaft is narrow and vertical, so I added a door that slides upward instead. It's really more of a gate - a grid of black metal bars that doesn't block the player's view through the glass walls of the elevator.

City walkway elevator viewed from the outside. Elevators have glass walls, a metal frame and platform, and a gate with bars guarding the bottom entrance.

These elevators have no player controls. They're fully automatic and will anticipate the player's movement so that they're open and waiting on whatever floor the player is currently on. They will change floors as the player changes elevation inside buildings or by flying in debug/noclip mode. They're also pretty safe as the glass walls and doors prevent the player from falling into or out of the elevator shaft. I did add gameplay fall damage as a "reward" just in case the player can find a way around this system.

I cut a hole in the exterior wall on one side of the walkway to add the elevator entrance. This had to be done for both sides of the walkway wall since the exterior wall is "owned" by the city while the interior is owned by one of the connected buildings. The entrance on each floor has typical dark window/door trim added around it to cover up the edges of the walls. I set up buildings so that the walkway interior is drawn when the player is in the elevator shaft. It's typically blocked by closed doors when the player is outside of the elevator. Elevators use outdoor city lighting with sun and moon light + shadows since the majority of their surfaces are outside the walkway.

City walkway elevator with doors open, seen from inside the walkway

These elevators use the same door opening/closing and bell sounds as interior building elevators. In fact a lot of the ideas and code were copied from indoor elevators. Once I've worked out the logic for these types of objects it's much easier to reuse in other places.

Here is a short video where I travel up and down an elevator leading to a high walkway that connects to the skyway.