Monday, March 14, 2022

Procedural Buildings: Parking Garages

Parking Garages

The past few months I've been mostly working on improving the interiors of houses because I've gotten more feedback from others in this area. I haven't put as much effort into office buildings lately. It's time to go back and work on office buildings once again. I added basements to houses last year, and now I've added underground parking garages to some of the larger office buildings. Smaller buildings have basements similar to houses, with offices and storage rooms. I've even added support for multiple levels of basements and parking garages that extend down under the building.

Parking garages are implemented somewhat differently than above ground building interiors. They're only visible when the player is inside the building because they have no windows, which means I can defer their generation until that point. This means that it makes more sense to add parking garages as interior detail objects rather than regular interior objects generated by the floorplan phase. I added a new drawing system for "interior detail geometry." The benefit here is that I can have much more detailed interiors for parking garages without having to worry about allocating too much memory to store geometry when the buildings are initially generated. This is why I didn't have office building basements enabled by default before now. I also realized that I was accidentally generating garbage basement geometry for non-rectangular buildings, which the player can't enter anyway, so I fixed that as well.

The floorplanner treats the entire parking garage as a single big rectangular room, like this.

Early version of an empty parking garage with only ceiling lights, and elevator, and stairs.

Code to fill in the interior is triggered when the player is close to the building. The first step is to determine how many rows and columns of parking spaces there will be based on the size of the largest car that can be placed. The available space is partitioned into rows of parking spaces separated by walls and pillars, with aisles between them and along the sides for cars to drive in when entering or leaving their parking spaces. I added beams crossing the ceiling in both directions, connected through the support pillars, with lights hanging from them. Then I connected stairs from the ground floor down to the parking garage level and to lower levels, and extended elevators downward into the parking garage. Finally, a ramp is added connecting each level of parking garage to the floor above. The ramp is wide enough and has enough clearance around it for cars to use. Walls, pillars, beams, and parking spaces are clipped or removed to keep the stairs, elevators, and ramps clear for people and cars to use them.

I added new elevator buttons and stairs/elevator signs for these underground levels. Basement levels begin with a "B", while parking levels begin with a "P". I placed railings along stairs and ramps for safety. Lights are added in a 2D grid along the ceiling attached to beams. Any lights overlapping other objects are moved horizontally to nearby free positions, or removed if there's no space for them. Here is what this looks like with cars added.

Parking garage with parking spaces and parked cars, with stairs, and elevator, and a ramp in the back.

Cars are high polygon count objects with many materials, so I had to put extra work into optimizing their drawing. The parking garage walls, ceilings, and floors are merged into maximal occluders for use in occlusion culling. This way cars that are hidden from the player don't need to be drawn. I also skip drawing of the surrounding terrain, city, and buildings when the player is in the basement and away from stairs leading up to a room with a window. These optimizations allow me to to get 70-120 FPS even in a large room filled with cars.

Pipes

[Disclaimer: I know nothing about plumbing or what the correct terms for these things are.]

That looks pretty good, but something is missing. What do parking garages always seem to have? How about some pipes running across the ceiling. I already know where all of the toilets, sinks, urinals, bathtubs, and showers are because these have been placed in the building before the parking garages are filled with objects. I can find these object locations on the floors above, combine their flows vertically, and produce the ends of a drain pipe for each stacked plumbing fixture above the parking garage. I made pipes increase in radius as they're merged so that have mixed sizes. The idea is to then connect the ends of the drains protruding from the ceiling into a network flowing into one main sewer pipe that exits into the wall or floor.

The only problem: Connecting these pipes is extremely complex. I have pipe ends of various sizes randomly scattered all over the ceiling, with some of the large buildings having as many as 80 of them. Then I have all of these pillars, lights, elevators, stairs, and ramps everywhere that I have to route around. I believe what I want here is a rectilinear Steiner minimum tree, with the addition of obstacles. This is an NP-hard problem - meaning, an optimal solution likely requires exponential runtime. And that's not even taking into account the obstacles part! All I can find online that discuss handling obstacles are conference papers in the field of VLSI layout routing. None of these are algorithms that I want to sit down and write from scratch just to connect my pipes together.

Okay, maybe I can implement this with a simpler and less optimal single trunk Steiner tree. I can have the main sewer line running along the longer direction of the parking garage and then add secondary feeder lines branching out in the other direction to connect to the drains. Then I just need to translate and rotate that main line around, maybe add a bend in it, and I can fit that part in. The secondary lines are similar to the main line, but rotated 90 degrees. It would sure help if the pipes coming from the plumbing fixtures were in neat rows and columns so that I could connect them all for a given bathroom with a single feeder line. The toilets from the bathroom stalls are in a nice aligned row, but the sinks and urinals are a slightly different distance from the bathroom wall. I know, I can pick one representative and then try to align the nearby pipes to the same X or Y value as that one, as long as they still fit within the XY bounds of the plumbing fixture and the room itself. (In reality, the pipes would drop down through the walls behind the toilets anyway so that they can pass through multiple levels of floors.)

Armed with this plan, ... countless hours and a dozen special cases later I have it working. The exit point logic was the most difficult because I had to handle the case where the main line exits straight into the side of the building, at a right angle to avoid an obstacle, or drops down to the floor below to exit if there's no other option on the current floor. It's hundreds of lines of source code, but only takes an average of 120us per building to do the pipe routing. I was even able to add fittings around the joints and caps on the pipe ends. I've visited dozens of buildings in-game and I can't find any pipes clipping through geometry, and only minor instances of pipes clipping through each other when the exit pipe is too close to a feeder pipe.

Some of the smaller pipes still pass by or slightly under the lights. It might make sense to move the lights below the pipes, but then they come close to colliding with the player's head and don't provide enough clearance for the cars. Maybe the pipes should cut through holes in the beams rather than hanging under them? I don't know, I guess I don't want to spend hours changing it again.

I've disabled shadows for horizontal pipes because they don't look right when I treat light fixtures as point lights rather than area lights. A pipe that crosses the center of the rectangular light should produce a blurry shadow rather than blocking all of the light. Vertical pipes that go into the floor do cast shadows, and also collide with the player.

Here are some more screenshots showing the network of pipes in the ceiling. Some of the pipes continue through the walls into other areas. Sorry if pipes are difficult to see due to the poor ceiling lighting, but that's typical of parking garages.





Parking garage with pipes in the ceiling but no cars.

After looking at these screenshots, I decided the lights are too bright and blueish. I reduced their color temperature to something of a warm yellow color, which looks more like the lighting you typically see in an underground parking garage. Here are more parking garage examples.

Parking garage with a lower color temperature yellow light.




Note that people (zombies in gameplay mode) and rats are placed in and can navigate in parking garages. There's nothing of value to steal down here, so I'm not sure why the player could come down to this level. Maybe I should hide valuable items in cars? That's one idea I'll consider.

Future Work

One problem I haven't solved is how to connect the ramp from the upper level of the parking garage outside the building. Cars need to enter and exit somehow. I have no easy way to add geometry outside of the building's bounding cube or lower/remove the terrain around the ramp, so the only option is to have it exit somewhere on the ground floor of the building, preferably near a corner or exterior wall. I can cut a hole into the floor above the ramp, but there will be other objects already placed there such as walls, offices, and hallways. (Remember, the entire building interior is generated before the parking garage.) Maybe the ramp has to be placed first, then the rooms assigned, then the parking garage filled in? The problem here is that my office building floorplan templates don't have a way to mark some corner as off-limits for offices and hallways. This would make all buildings with parking garages have an L-shaped floorplan with the corner cut out, which is more difficult to divide into rooms. I could merge all rooms that overlap the ramp and convert them from offices to some other room type, but then how do I remove the walls? I don't have support for a different floorplan on the ground floor compared to the floors above.

On top of this, if I add an exit door/hole, then the parking garage contents will be visible from outside the building. That means I have to generate it before the player enters the building, which ruins all of my plans. Sigh. So far I haven't figured this out, so I let the ramp end at the concrete ceiling under the ground floor for now. I suppose the cars will be stuck down there until I fix this.

What's next, other than solving the ramp problem? I was thinking that maybe I can work on the lighting and electrical system. I can add a circuit breaker panel in the basement or parking garage that controls the room lights for the entire building. Currently I don't even have light switches down there. I think that would be an interesting project, though I'm not sure how it would contribute to gameplay. Another idea is to add some chance of lights flickering, having a dim glow, or being completely out. That's pretty typical of the lower level of maintenance seen in a parking garage. This way the player can at least steal the broken, low value lights.

11 comments:

  1. It's incredible to me that this post has no comments yet. So much to talk about!
    First off, you really seem to have nailed the "parking garage" feel. Aside from needing some kind of GI or luminosity map or something to properly light the ceiling, it hits the ambiance perfectly.

    As I've mentioned before, I'm a professional plumbing engineer, so the pipe routing is especially interesting to me. You got it exactly right with dropping pipes straight down in the walls (we call these "risers"). Though usually all the nearby plumbing will be fed by a single riser instead of having a riser for each fixture. That will solve a lot of the jumbled joints and plentitude of pipes you've got right now. We usually route from the utility site entry (the water meter or sewer hookup or whatever) to the furthest riser, and then tee all the other risers into that main trunk line. The pipe sizing gets a little fiddly, but you seem to have done an admirable job.

    However! If these are supposed to be sewer pipes, then you've missed a critical feature, which is that (where feasible) drain pipes should make a 45 degree joint in the direction of the flow. If that isn't possible, you can use a "sanitary T" which has a long sweep. I know you probably aren't interested in this kind of detail, but it gives drain systems a distinctive look. What you have now looks a lot more like cold water distribution than sewer drains.

    Which brings me to my next point. Now that you have the code in place, it seems like it would be easy for you to have all the major plumbing systems! Sewer you already have (ostensibly). You can add water supply lines just above the sewer lines, and give it a different exit point (though these should all be toward the street, which is nearly always where the utility hookups are). And then there's storm drains, usually just one in each corner of the building, but they are pretty large. Finally, fire protection sprinklers, which are typically arranged in something like a 10' grid.

    ReplyDelete
    Replies
    1. Thanks for your input. I get very few comments here. I seem to get more comments as direct email from the people I know and share these links with.

      I've added handicap parking spots and those yellow concrete curbs at the end of parking spaces, which improves the look. I agree that the lighting doesn't look correct at the ceiling. One of the problems is that the shadow maps point down and there are no upward shadows from the beams and pipes. I experimented with that a bit, but it doesn't really look right when using point light shadows with those big rectangular lights. I think I would need proper area light sources for that to work, and probably for good GI as well.

      The pipe routing was mostly done by looking at parking garage images online. There aren't any parking garages or accessibly basements around my house, and I'm still working from home. Pipes that are too close are merged into a larger riser, but I left the other ones there because I prefer the jumbled look. It helps account for the fact that I don't have water or sprinkler pipes. I'm definitely aware of that. The biggest problem at this point is that I don't have an easy way to keep a second pipe network from intersecting the first one.

      I also routed to the furthest riser and added tee junctions to other points. Pipe radius is a function of accumulated capacity, similar to how rivers work but with a smaller merge exponent. Making pipes 45 degrees is easy, the problem is connecting them in a clean way because the joint isn't something that can be easily formed from spheres, cones, and cylinders.

      Delete
    2. I added cold water pipes above the sewer pipes. Then I tried to add hot water pipes that connect to the sinks, but there's not enough vertical space. I ended up using the cold water pipes as obstacles and having hot water pipes try to route around them. All three types of pipes use the same code but with different sizes, colors, and connection points.

      I need to connect the hot water to some sort of water heater. Do office buildings have water heaters like houses, just bigger? Or multiple smaller water heaters? Are they on the roof or in the basement?

      Delete
    3. Neat!
      Usually, each tenant has its own water heater. That way each pays the electricity/gas bill for their own use. I have seen it done where the whole building is on one hot water loop though. And of course there are those cities that have hot water/steam utilities in the streets. So, it wouldn't be too hard to justify whatever you wanted to do in that respect.

      Delete
    4. Okay, thanks. I like to use the 5 story office building where I work as a reference. It's all owned by my company (we have 6 buildings in this campus). I don't think it has a basement and there are no steam utilities here. I suppose it must have water heater(s) somewhere either on the first floor or on the roof.

      Delete
    5. A lot of times pure office buildings have one water heater that serves the bathrooms. Usually on the ground floor, or second story, in the utility core. Then, if there are sinks or other fixtures that need hot water, they will have their own mini water heater.

      Delete
  2. If you're feeling particularly ambitious, fully sub-terrain parking garages also need ventilation ducts to supply fresh air and remove car exhaust. With all those utilities, you'll probably run into headspace clearance problems even more than you already have. Many times the ground floor or first basement level is taller than the rest of the floors to allow for all of this routing. In addition, risers are often bundled together in a "chase" that runs vertically through the whole building, often right next to the elevator shaft. This forms the "utility core", and the bathrooms are almost always built right next to the utility core. Then each floor of the building is served from the chase, routed above the drop ceiling. This allows each tennant to build walls, install fixtures, etc where they like. This process of building the rooms in a space is called Tennant Improvement, or a TI. Often the primary features (support pillars, utility chase(s), elevator shafts, stairwells, storm drain drops, central bathrooms, sometimes primary egress corridors,) are placed when the building is constructed, and are the same on every floor (except the ground floor) and then each tennant builds out the space according to their needs. So the floor plan of an office building will be somewhat different on each floor.

    As I said, the ground floor is often significantly different from the upper stories as well. That's where all the human amenities go. There will be a mail room in many cases. A larger janitorial area where the powered floor cleaners are kept. Clearance for the ramp to the underground parking garage. Some high traffic tennant space if there's enough room (a bank branch or whatever). and then whatever odd shaped space is left is the "lobby".

    Concerning loading the parking garage, you could always have a roll-up door at the entrance that stays closed to block sight lines. Even if it opened when the player got close enough, that would save you from generating the parking garage until it was needed. You could probably even have the ramp just fade off into black until you walked close enough.

    Gameplay in a parking garage? Stealing those fancy hubcaps off the sports cars comes to mind.

    ReplyDelete
    Replies
    1. I don't have ventilation in any of the buildings. I was planning to attempt an electrical system first, since I'm more familiar on how those work. It's definitely true that I need more ceiling clearance here, especially if I add more levels of pipes. It's not currently possible to have a different spacing between each floor of a single building because the current floor for all objects is calculated from (zval - building_z1)/floor_spacing. This math is used in dozens of places. Changing this would require rewriting hundreds of lines of code. Maybe I could have an entire empty floor of padding, but I feel like that would be too much.

      I already attempt to place bathrooms in the same locations for each floor, and the elevator generally runs through all floors. One constraint I have is that parking garages are generated later in the flow (when the player enters the building), which means I can't easily go back and change anything else in the floorplan of the floors above. I have to make the parking garage (and pipes, etc.) fit with the existing building. But even if this wasn't a constraint, it would be a huge amount of work to reorganize things around the elevators/utility cores.

      However, that's interesting to know. The bathrooms are in fact near the elevators in my real office building. I didn't realize that was the reason why.

      My room assignments are already different for the ground floor. There are more utility and storage rooms that are offices on the floors above. The floorplan is the same though. It could be different, I have an option for this, but it wasn't added until I had this building generation code in place. Instead I use this for things like penthouses added on top of the lower building section.

      It's the same problem again: I don't know where the ramp will be until I generate the parking garage, which is too late to go back and update the ground floor rooms and walls to account for it.

      For the roll up door, that solves the visibility problem. I still have the problem of placing the ramp. If the ramp is inside the building, then the walls have to be removed near the top of the ramp and the room(s) above can't be offices. If the ramp is exterior, then I have to modify the terrain around the building to account for it. I'm not guaranteed to have space around the exterior of the building for an external ramp, and it could be at the side of a mountain or on a cliff. The ground is only guaranteed to be level after the building placement step, which uses the footprint of it's bounding cube. By the time the interior is generated it's too late, the heightmap has already been processed and send to the GPU, and vegetation has been placed.

      For gameplay I might allow the player to break into parked cars and steal things. I'm not sure if I'll be able to have the doors of car models open, or what items will be in cars.

      Delete
  3. Hey frank i've been playing your latest build and the building additions are shaping up nice. I have some suggestions that may or may not be possible for the buildings :)

    This project is very unique to me and in some ways revolutionary as i've never seen a project go to this amount of effort for poc-gen buildings before.

    First is it possible to generate electric cables\water pipes going along basement ceilings in houses? I think this would add a bit of realism. As the basement in my home has exposed water and gas pipes along the ceiling.

    And you know how some homes have the wire cable that goes from light switches to lights actually exposed along the wall and ceiling in their basements. That would be a nice touch.


    Second. On the roofs of some office buildings i believe they have a small storage/maintenance closet for roof workers. This would be a nice little detail.

    Third this one might be really complicated especially for certain roof styles. Attics are something i've wanted to see. Though i'm sure a hard part would be generating the walls correctly. Maybe a first step could be having the floor and the inside ceiling of the roof simply being rendered with a staircase or ladder leading up.

    If this is doable without a ton of hassle then attics could even serve as a major loot area for "some" homes if people have junky/cluttered attics.

    Fourth

    I don't know how feasible this would be. I do have a somewhat high-end pc. I was wondering if you could test having each floor of a house being a seperate floor plan? Just as a stress test as i'm curious if it would diminish performance alot or not. And houses are smaller than offices so it might be an okay start to experiment with.


    That's about all for now. I also noticed that some of the downtown city buildings that are square-like in shape have office interiors now aswell! They're not perfect but it is cool too see as these buildings also have higher variety in terms of shape combination. But your doing great! i don't want to overwork you.

    ReplyDelete
    Replies
    1. Thanks for your feedback. I'm glad to hear that you like what I've done. Yes, my goal is to make something unique. I'm not aware of any other games that procedurally generate that much detail for that many buildings either.

      All of your suggestions should be possible to add, it's only limited by how much time I have to work on this project. I'll add some of them to my TODO list here: https://trello.com/b/a9ox4ML6/3dworld-cities

      Pipes in houses: Yes, it's possible to add this; in fact I already have this for office buildings. I would probably have to change the ceiling type to bare wood to make it look correct. Note that the houses I've lived in generally didn't have exposed pipes in the basement except for one section of my parents' house.

      Wires to light switches: I already have wires going to breaker boxes. This would be easy to add to light switches, but I would probably also need a new switch box that's against the wall rather than recessed into it. Maybe that makes the most sense to add to exterior walls.

      Roofs: Many office buildings have small rooms on the roof where the roof access doors are. I think these mostly serve this purpose. Maybe I could extend these to make them larger. I'm not sure it would add much new content.

      Attics: Houses already have attic spaces, there's just no way to get there. I'm not sure how much it would make sense to add stairs that happen to be down in an upper floor room in the house. Maybe the player can lower the ladder? I'm not sure. Note that I have an attic complete with internal beams in house/config_house.txt. I'm not sure if walls are needed in attics, except of course for the back side of building exterior walls.

      Floorplans: Splitting a single part into multiple stacked parts will give you different floorplans for each floor. I have experimental (disabled) code for enabling this with office buildings on line 221 of building_geom.cpp. The biggest problem is that it complicates the system that connects floors with stairs, places doors, assigns rooms, etc. This results in more frequent failed placements and some odd buildings. Note that house basements already have a different floorplan compared to the above ground floors. This likely won't impact performance very much because it doesn't affect the exterior geometry and won't increase the number of room objects.

      Larger city office buildings can also have interiors, yes. There are various problems generating proper interiors for other building shapes, so it's turned off by default. You can enable this by commenting out the is_cube() check in building_t::interior_enabled() on line 142 of building_floorplan.cpp. I haven't yet figured out how to make these office building windows transparent, so you currently can't see the interiors through the windows. Interior generation works correctly with most shapes composed of cubes as long as there aren't too many overlaps.

      Delete
    2. So far I've added:
      * Sewer, hot water, and cold water pipes in the basements of 50% of houses. I made the ceiling a wood texture to match the underside of the floor above. I'm not sure how to handle plumbing fixtures on the basement floor though (including hot water heaters), so for now they're not connected.

      * Light switches and outlets on exterior basement walls are no longer recessed, since these walls are bare stone/block. Instead they're placed on the wall and stick out, with wire conduits running up into the ceiling.

      * Some larger office buildings now have a rectangular room with a door on the roof. The player can't open this door or enter the room at this time, it's just a decoration. It looks good next to helipads though.

      * I added an access door to the attic on the topmost floor of each house. The player can't enter this yet. I have to figure out how to check if the player is inside the boundary formed from all the roof quads/triangles first. I also plan to add wood on the ceiling and floor of attics, with wooden support beams.

      Delete