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.

11 comments:

  1. Paradoxically, those lady's stiletto heels are going to give her problems on the catwalk.

    The pipes extending down into the basement parking garage is very sensible. In semiconductor fabs, there is both a sub-fab under the floor (where all the plumbing goes) and a plenum above the ceiling (where ducts and electrical are routed).

    You really should move the flashlight a couple feet lower instead of putting it directly in line with the camera. Maybe add some motion bob when you walk? Have a key you can press to bring the flashlight up next to your head?

    The dark night inside the factory makes me wonder if you are doing lighting by the city lights. You could do a point source for each building, with intensity scaled based on the number of windows that are lit? It would also be amazing if you had some random cube structure sculptures on some of the buildings. They could be a dull grey during the day and a bright neon glow at night.

    I love the procedural machines. I feel like the pipes and cables should be more numerous and thicker, but maybe there are framerate constraints?

    I would also remove all but the uppermost windows in factories. Maybe the windows remain in the office spaces?

    The pipes need random gauges and valves. The tanks need big chemical warning labels. I'm sure you could procedurally generate these, or you can just screenshot a few: https://www.mcmaster.com/products/chemical-signs/

    The random boxes in the corners are a nice touch. What if the machines make boxes of stuff? You could have NPCs pick up boxes from the factories and deliver them to the stores, buy things from the stores and take them home, and go from home to work at the factories. Not sure how much simulation you want to do here, but there's a lot of potential there.

    It also occurs to me that, since you have put so much work into structurally and mechanically sensible buildings, you could generate the buildings in any state of completion, from bare un-leveled ground, to a level site, to a poured foundation (and basement if applicable), to the structural frame, to the curtain wall and completed envelope, to the finished interior, to the furnished interior, to the fully populated building (which you have now for everything), to a dilapidated and abandoned building, to one that is collapsing, to a pile of rubble, to rubble overgrown with trees and plants, all the way back to bare un-leveled ground. Once all of these stages are done, you could do some really fun stuff like watching the whole city being constructed at the same time, or doing a timelapse fast-forward of an individual building while the rest of the city operates at normal speed.

    Power plants seem like low-hanging fruit as well big generators and turbines and stuff are easy to procgen, and the same system can be used at a smaller scale for pumps and motors for the building utility "Machine Rooms".

    Looking forward to seeing the next progress, whatever it is you choose to work on. This project is really progressing nicely!

    ReplyDelete
    Replies
    1. Thanks for all the feedback!

      Right now people can't climb ladders and get onto catwalks. Maybe I can make zombies do this eventually.

      Moving the flashlight down and drawing it is a good idea. But I may need to add shadows since it's no longer aligned with the player's view. That's one reason I put the flashlight at the player's eye level. I do have an option for motion bob, but I found it annoying and disabled it.

      Right now interior and exterior lights are handled by completely different systems. The exterior has no effect on the interior. I could potentially add lights outside the building shining in (like I already do with skylights), but it may be difficult to do efficiently. Plus windows aren't real geometry but are added in shaders, so I would need to find a way to shadow the non-window areas. Lit sculptures is an interesting idea. I was starting to work on something like that by adding red "+" signs on top of hospitals. The current system supports this.

      Pipe count and thickness is limited because the placer can fail to add many thick pipes. It attempts to check for intersections with other objects, but it's pretty conservative because it uses bounding boxes for everything.

      I believe I can remove lower level windows from any building by splitting the exterior vertically and setting the lower part to not have windows. But I'm not sure if that would work if the interior wall spans the entire height. I think I would need to split the interior vertically as well. And I'm not sure how to add windows to only the office and bathroom area since it's part of the same room/cube as the main factory.

      I added a few pipe valves. They really increase polygon count. I have warning labels for some other things like water heaters that I can add to tanks.

      The section about building AI interactions and buildings in various states is definitely interesting, but is probably more than a year's worth of effort part time.

      I've been wanting to add power plants connected to the transmission lines that run between cities. Maybe now I can do this. I can have a specific factory designated as "power plant" with some differences such as big transformers on the roof.

      Delete
    2. I was able to do some of this. I moved the flashlight down, added a flashlight model that the player can hold, added flashlight shadows, and added head bob. I added chemical warning labels, more pipes, thicker pipes, and valves to some pipes.

      I removed the lower floor windows from factories except for offices, and added glass block windows to the bathroom.

      Delete
    3. Very neat! Glad some of that was helpful. I wish I had time to contribute to the project myself. Some day...

      Delete


  2. Hi i have a few Suggestions/Ideas i would like to give considering your recent progress.

    First.

    Since you now have factories i would jave to suggest procedural warehouses, I actually work in a warehouse so having a structure like that with the rafters, clutter, boxes, crates, Could be incredible. They should also have an office area, these usually tend to be the main entrances that lead into the warehouse section.

    You might be able to use some of the new fancy procgen stuff from your factories too.


    Second.

    Small shops and local groceries. Honestly your not far from doing this. These types of buildings would mix very well in residential cities. Maybe even creating a new plot type specifically for these structures so they fit.



    Third.

    I really am liking these new building features and content. Though what would be cool is if you added a new city "type" for office buildings and factories. Instead of them only being spawned randomly all around the terrain. Having a city type with those structures in proper plotting would be immersive for sure.


    Fourth.

    This one might be complicated but considering you added escalators for malls. I wonder if you could add stairs for houses that have indoor balconies and such using a similar method. This "might" allow you to have houses with 2 floors with each floor being a different floorplan.


    And that's about it for now. I've been following your project for years now and it's cool to see you're still adding things to it. I do have to ask if you could pre-compile a new 64-bit release as my visual studio is outdated.

    ReplyDelete
    Replies
    1. 1. Warehouses do seem similar to factories. I'll add them to the list and maybe get to them after hospitals.

      2. Shops and grocery stores often have custom exteriors that are difficult to generate with enough variety. I do currently have stores in the ground floors of some office buildings and in underground malls. Maybe I'll get back to this later sometime.

      3. There are already city areas with only office buildings. I don't think factories are placed there because they don't meet the minimum height requirement. Maybe I can add industrial-type cities with factories and similar shorter buildings.

      4. I already have L-shaped stairs with interior landings in houses. And houses can now have different floorplans for lower vs. upper floors. So maybe I've already done what you're suggesting.

      I need to do more testing before I can create a release build. I have a new PC and a newer Visual Studio as well, so I'm not sure what VC redisributable and DLLs are needed. I should also update the assets package in my Google Drive. I'll post an update when this is done.

      Thanks.

      Delete
    2. Okay, try this release: https://github.com/fegennari/3DWorld/releases/tag/v1.4-release

      Delete
    3. Thanks for the Reply! That compiled build you posted lacks a few dlls i have not seen before. poly2tri.dll minizip.dll and pugixml.dll, It wont launch because of these

      Delete
    4. I’ve seen that error myself and rebuilding usually fixes it. As far as I can tell I don’t actually have those three DLLs either. I have no idea what needs them or how to work around that problem. I guess I can do a Google search or post something on stackoverflow.

      Delete
    5. I found those three DLLs. They're part of the latest Assimp package, which I installed with vcpkg. Apparently the way this works is that the vcpkg DLLs are copied into the build directory at compile/link time. I added them to the release and will add them to the git repo as well since they're small.

      Delete
    6. Ah nice! glad you found a solution.

      Delete