Tuesday, July 21, 2020

Procedural Buildings: Room Assignment

I've definitely made a lot of progress in 3DWorld's procedural cities. I started with placing cities, then I populated them with buildings, then I added building interior walls, floors, and rooms. Next I added room lighting, details, furniture, and people. Now it's finally time to officially assign purposes to rooms and populate them with the correct furniture, appliances, and other objects according to room type.

I added bathrooms and then bedrooms to houses a few weeks ago. This past month I added hallways, offices, kitchens, living rooms, and dining rooms. I also added bathrooms and kitchens to some types of office buildings. Bathrooms previously had toilets, but now they have sinks and tubs as well. Bedrooms continue to have beds, bookcases, and sometimes desks placed in them. Kitchens currently have refrigerators and stoves, while living rooms have couches and TVs added against their walls. Kitchens, dining rooms, and living rooms also have tables and chairs. Residential offices have desks with a chair and sometimes a bookcase, while commercial offices contain up to two desks and a whiteboard. Any house rooms can have pictures, rugs, trashcans, and lights.

Walls, floors, and rooms are generated when each building is created. Interior details are only generated and drawn when the player gets within a specified distance of the building. This distance is relatively large to prevent visual artifacts as furniture and appliances pop in. Smaller and more numerous items such as books and pillows are generated and drawn at a closer distance to reduce their resource usage. Generation time has a minimal overall impact on framerate, except for when the player is moving at maximum speed through a densely populated area of the map.

Before we get into room assignment, let me show off my book/bookcase improvements. If you look at the bookcase below you'll see that some of the books are leaning against other books. This is something new I added since the last post. However, books can only lean to one side within an individual bookcase.

Bookcase with some tilted books.


Now, onto room assignment. I spent quite some time trying to work out all the rules that determine what rooms can be set to what types. The goal is to generate realistic and functional building layouts. I believe my solution meets these goals in the majority of houses. The occasional odd placement/assignment of rooms or objects within a room is usually acceptable. Overall I'm very happy with the resulting floorplans, and I find that they come in an interesting and creative variety. No two buildings are the same!

Here are some screenshots of rooms in the approximate order in which I implemented the room types. Note that most 3D furniture and appliance models were downloaded free from Turbosquid.

Offices

Office building interiors with offices have been shown before, so there's nothing really new here. They continue to contain one or two desks with chairs and an optional whiteboard and/or trashcan. The only real change is that each floor of a large office building will have two offices replaced with bathrooms, one for men and the other for women. These bathrooms are always in the same locations for each floor, which is commonly done in real buildings to reduce plumbing costs.

One office within a large office building containing two desks with chairs and a trashcan.


Bathrooms

Each house and commercial building is guaranteed to have at least one bathroom. Most buildings have one bathroom placed in the same location on each floor. House bathrooms contain a toilet, a sink, and a bathtub, assuming each model can be successfully placed. Office bathrooms only contain the toilet and sink. I'm considering adding more than one toilet and sink for offices along with dividing walls for stalls.

Bathrooms are placed in small rooms on an exterior wall of the house with only one door, when possible. If no such room is available, the best location is chosen based on heuristics to ensure there's a bathroom. (In theory, if there was a single room house, it would be a bathroom.) The single door requirement avoids placing a bathroom that must be crossed to enter a different sub-graph of the house, for example to get from the front door to a bedroom. Bathrooms are currently the only room type with this requirement.

Bathroom with toilet, sink, bathtub, trashcan, and rug.


Bedrooms

Bedrooms are the most common room type for houses, especially for floors above the ground floor. Each one contains a variable sized bed with one or two pillows, and optional bookcase, rug, and pictures hanging on the walls. These are generally used as filler rooms once all the other required rooms have been assigned. Bedrooms never contain stairs or connect directly to an exterior door. I haven't yet added closets, but they're on my list of future additions.

A bedroom with bed, bookcase, and rug.


Hallways

Hallways have existed in large office buildings for a while, but they're new to houses. If a house is large enough it can have a hallway running its entire length. Hallways contain multiple lights, pictures hanging on the walls, and possibly a rug. They don't contain any other furniture. All doors open outward from a hallway into the connected rooms. These hallways may or may not have windows at their ends.

A long hallway in a house with a few pictures hanging on the walls.


Kitchens

Most houses have a kitchen, and some office buildings have a kitchen as well. House kitchens contain a table with chairs, refrigerator, and stove. Trashcans and pictures on walls are sometimes added. Office kitchens have a refrigerator with an optional desk or table with chairs, but no stove. Kitchens are always placed on the ground floor and only placed in a room with an exterior door if no other rooms are available. This is to prevent the front door from opening to a kitchen. I'm considering placing back doors to some houses later, and these can open to kitchens.

Large kitchen with table, chair, refrigerator, stove, and trashcan.


Living Rooms

Every house with more than a few rooms will have a living room placed on the ground floor. This room is often the one connected to the front/exterior door of the house. In some cases, houses can have more than one living room. Living rooms have a table with chairs, plus a couch and TV if they can be fit along the walls. The preference is for the couch and TV to be centered along opposite walls facing each other, or as close as they can be placed to that configuration. Living rooms can also optionally contain bookcases, one or more pictures, and a trashcan. Houses with two living rooms may have the couch and TV in different rooms because they can't both be placed into the same room due to space and clearance requirements.

TVs are turned on 50% of the time. A random image is chosen from the same library of screenshots as pictures hanging on the walls, but here they are emissive so that the TV appears bright even in dark rooms.

Spacious living room with couch, TV (turned on), table, chairs, and bookcase.


The chairs arranged around the central table can sometimes block the view of the TV from the couch. To help with this, I put the TVs on small tables and shortened the heights of chair backs a bit when they're between a couch and TV. Model heights are all set so that the line of sight of a person sitting on the couch while looking a the TV is not obstructed by chairs. This looks better:

Living room with TV placed on a small table and turned off, and chair backs shortened 25%.


Dining Rooms

I've assigned dining rooms to be the leftover ground floor rooms with a table and chairs that haven't been already assigned to a kitchen or living room. These are optional, but do appear in most houses that aren't too small. They can contain a bookcase, trashcan, and pictures on the walls along with the required table and 0-4 chairs. I would say they have to contain at least one chair, but then table-only rooms would be unassigned.

Dining room with table, three chairs, bookcase, and painting on the wall.

There probably should be a constraint that dining rooms are adjacent to kitchens. Sometimes they are, sometimes they could be but aren't, and sometimes that's not possible given the room layout. I would like to add some preference for adjacency, but I'm not sure how to cleanly implement that. It's not currently possible to change a room after it's been assigned. This means the adjacency constraint has to be part of the initial room assignment algorithm.

Studies

I've decided to call "office-like" rooms in houses studies to avoid confusing them with offices. These are the leftover rooms with a desk that haven't been assigned to another room type. They usually occur above the ground floor because ground floor rooms are commonly assigned to other purposes (kitchen, living room, or dining room). Studies are often small rooms that won't fit a bed or table. They can have a bookcase, trashcan, and pictures on the walls.

A study or home office with a desk, chair, and bookcase with some books to read.


There are also detached garages and sheds. I've shown these in previous posts, so I won't include them here. They're not part of the main building floorplans, so they don't really participate in these generation and placement steps. Garages may contain a car if car models are enabled, while sheds are currently empty.

Note that many of these rooms are larger than you would typically see in real houses. I wanted to make sure there's plenty of space to insert objects without blocking the path of the player and AI people in these rooms. I haven't implemented movable furniture yet, so the initial object placement must guarantee all rooms can be navigated. I'm also expecting to place a greater variety of objects into these rooms at a later time.

It's almost there. I have to do a bit more tweaking of parameters to get everything right. At some point I may attempt to add smaller rooms such as laundry rooms, storage rooms, closets, etc. For now, the basic room system is nearing completion.


One other change I made is an option to create an infinite set of buildings rather than a fixed/finite region of them. It works by generating tiles of buildings and populating them when they come within view of the player. This is mostly working, though there are a few minor limitations and it's a bit slower.

I attempt to limit the number of buildings and interior details generated each frame to try and smooth over the framerate when a new block of buildings comes into view. This is particularly important when the player turns around after walking in the same direction for miles and all the buildings behind the player suddenly come into view.

8 comments:

  1. I like that there are leaning books now, though it kinda looks wrong when they are just leaning on a single vertical book. Maybe better to do a short physics sim limited to that shelf, if you have physics rotation working yet?

    None of the doors have frames (yet?), and a lot of them reach all the way to the ceiling, which looks wrong.

    The drywall texture is too large in both scale and intensity. Maybe cut it in 1/4?

    Typo: "looking a the TV"

    The bookshelf in the dining room reminded me of a wine rack! Should be pretty easy to parametrically generate. Add it to the list?

    ReplyDelete
    Replies
    1. Books aren't even separate physics objects. They're created procedurally in the drawing code itself when the vertex buffers are written to. This allows the vertex generation to treat the entire bookcase as a single object and remove hidden faces, etc. The rotation code is actually really complex, and they're all tilted in the same direction because it's streaming and only has the previous book available in the placement logic. I was originally generating thousands of bookcases each frame while the player is moving at max velocity, so it had to be fast.

      I added door frames later. The reason doors extend to the ceiling is because it's a single quad that spans all floors with the same floorplan. When I originally wrote this system I generateed and drew doors for thousands of buildings at once. There were more doors than any other type of object, something like ~20K of them even merged across floors like that. Now that I've optimized the system I can go back and make them into individual shapes, but it's not a high priority. (Note that the building interior/exterior walls, floors, ceilings, and doors are something like 470MB of GPU data for the entire city.)

      Yes the wall textures are scaled too large. Someone commented on that about a month ago and I changed the texture scale. I think I changed it by 2x but it could have been more.

      Yes, wine racks can also be added. They're not very common though, and I would like to add more common items first. Between you, my parents, and my daughter suggesting items to add, I'll be at it forever!

      Delete
    2. Ahh yes, it seems endless. I suppose you'll simply have to make a meta-item generator!

      Delete
    3. Right now on my list I have driveways (in progress), canopy beds (mostly done), showers (in progress), office lobby desks (started), blinds, curtains, and wine racks (maybe?).

      Delete
    4. Add "clutter" to the end of the list. You can probably start with the bookshelf population code. Desk clutter is the obvious first step, but I imagine that all horizontal surfaces could benefit. Should be able to populate the contents of cabinets, fridges, dishwashers, and closets using the same basic system.

      Delete
    5. Yes, I just need to create a few dozen more object types for clutter. I already have books, boxes, and lamps. It's going to end up looking like Hello Neighbor! That was actually one of the things that inspired me to create these buildings. What if the entire city was full of Hello Neighbor houses?

      Delete
    6. Wasn't familiar with Hello Neighbor, but I looked it up and yeah, like that, but more so!

      Delete
    7. I play Hello Neighbor with my daughter. I have UE4 installed and the mod kit SDK and I like to play around with mods. It's interesting to see how the rendering and lighting work. For reference, it takes forever (like tens of minutes) and like 4GB of memory to compile the shaders and rebuild the lighting on those small 2-house scenes on 4 CPU cores. I don't see how that system could scale to a large number of houses or even a ~1000 room office building. My office building furnishings are pretty sparse, but the largest one probably still has more total objects and lights than a Hello Neighbor map with all that crap stuffed into a big house.

      Delete