Sunday, May 24, 2020

Procedural City: Adding Content to Building Interiors

Work continues on building interiors for 3DWorld's procedural cities. I had previously added stairs, elevators, lights, tables, chairs, rugs, pictures, and whiteboards. This time I've added trashcans, bookcases, desks, and beds. I'll briefly describe how I place and draw these room objects below, with plenty of images to show what they look like inside buildings.


Trashcans

Trashcans and recycling bins are common in both residential and commercial buildings. They're also simple and easy to draw - at least that's what I originally thought. They required implementing some new features, for example curved surfaces. (Yes, round room lights are also curved cylinders, but they're emissive so I didn't really have to get the normals right for lighting.)

Another difficulty is that I needed to implement two sided lighting so that their interior and exterior surfaces were lit correctly since they have no thickness. I could add a thin rim around the edge to connect the sides and give it some volume, but I don't currently have the code to draw that geometry. It would also take even more triangles. I initially enabled two sided lighting, but it was too much work for the fragment shader and reduced framerate. So I changed the code to add each triangle/quad twice with different normal sign and winding direction. Back face culling was enabled to ensure only the face oriented toward the camera was drawn.

Trashcans are placed in the majority of rooms. They are randomly selected from three different sizes, three different aspect ratios, and several colors (including blue for recycling bins). In addition, some building floors use trashcans with flat sides and others use rounded sides/cylinders. They are always placed near a wall or corner of the room away from doorways and other placed objects. Trashcans have collision detection enabled and cast shadows. Here are two example screenshots.

Flat sided trashcan in the corner of a room of a house.


Small cylindrical recycling bin by the wall in an office.


Adding trashcans to most rooms requires a great deal of total geometry across the set of nearby visible buildings. Some large office buildings have more than a thousand trashcan placements. This was having some effect on framerate, so I had to optimize the drawing code by removing hidden faces, using indexed triangle rendering, disabling shadows when distant, etc. To make it easier to test my optimizations, I temporarily placed up to 20 trashcans in each room. Now a single office building could have more than 10K of them! Here's a wireframe view showing all the trashcans in an office building.

Wireframe model showing a large office building with an excessive number of trashcans and recycling bins.

Most of the cost was in the shadow pass, where a shadow map was created for each of the up to 40 shadow casting lights every frame. Each shadow map had to draw every trashcan in the building because there's no per-building subdivision/acceleration structure for them. I thought about adding one, but I ended up caching shadow maps between frames when they weren't changing (no dynamic shadows from the player or people in the building). This helped a lot. With shadow map caching, my other trashcan drawing optimizations were probably not needed. I'm sure they'll help with non-shadow rendering though.


Bookcases

Next I added bookcases to houses/residential buildings. These can be placed in any room where there's space, as long as they don't block doorways, stairs, or elevators and don't intersect other room objects. I had to update the code that hangs pictures on the walls to avoid placing a picture behind a bookcase. They're relatively narrow and the placer is successful most of the time.

Each one has between three and five shelves, with randomly placed books on most shelves. Books are simple cubes with a variety of colors, sizes, and thicknesses. There are some gaps and the possibility of a fallen over book in the larger gaps. I like the way bookcases and books look, even though the books are simple and untextured. Here are some representative images.

Procedurally generated bookcase with a random selection of colorful books on the shelves. One book on the bottom shelf has fallen over.

Procedural bookcase with random books in a room with a table and rug on the floor.

In the future I might add books placed at angles, leaning on other books, which requires a bit more math. I could add more geometry to show the pages vs. the covers. I did this for books placed on desks below. I might even add pictures and/or words to the covers.


Desks

Desks were next on my list of furniture to add. They're similar to tables, but with a higher aspect ratio and only one chair. These are placed more often in building offices, and in smaller rooms of residential buildings where there's no space for a table. Some offices have two desks, but the rest of the rooms have at most one. They're pushed against a wall in a location that doesn't block any doorways, stairs, or elevators. I reused most of the code from tables to save work.

Here's are screenshots of a residential building desk and an office with two desks.

Home office with desk, chair, bookcase, recycling bin, picture on the wall, and rug on the floor.

Large windowless office with two desks with chairs, large whiteboard, and trashcan in the corner.

I placed a randomly sized and colored book on some of the desks, right in front of the chair. These books actually have separate cover vs. pages geometry. Maybe at some point I'll use these models in bookshelves. I might also put titles and pictures on the covers.

Desk with a red book placed in front of the chair, waiting to be read.

Some desks that are against interior walls (no windows) have taller backs. These may become bookshelves, mirrors, whiteboards, or cork boards in the future. I'll have to think about what I want to hang from their back walls. For now they're extra wooden spaces.

A tall office desk that can be used as a bookcase, mirror, whiteboard, cork board, etc. in the future.

Bedrooms

The logic for selecting bed placement was actually pretty complex. Beds are placed only in bedrooms, compared to other room objects such as chairs, desks, bookcases, trashcans, rugs, and pictures, which can be placed in most room types. There are more rules governing assignments of bedrooms than most other rooms and placed objects. For example:
  • Bedrooms are in houses/residential buildings only, not offices
  • No beds in building parts assigned to garages and sheds 
  • No beds in rooms flagged as offices or hallways
  • No beds in rooms with stairs or an elevator
  • Bedrooms should not have an exterior building door (front door) when on the ground floor
  • Rooms can have either a bed or a table, not both (bookcases are okay to mix in)
  • No beds in rooms that are too small to fit them, or too large to be bedrooms
We also have the usual placement constraints and some placement constraints specific to beds:
  • Beds can't block doorways (same as other furniture)
  • Must be space to at least one side of the bed where a player/AI can walk
  • Must be space to navigate around the bed from one doorway to a doorway on the other side of the room
  • Headboard should be against a wall if possible (soft requirement), but need to leave a bit of extra space if along an exterior wall with a window.
I attempted to implement all of those checks and special cases, which required adding a bit more query functionality for buildings. Since beds are only used in houses, which have a smaller number of floors, this doesn't affect runtime or framerate as much as something like a desk which can have a thousand placements in a single large office building. Bed geometry is simple though, at least compared to bookcases full of books.

Beds have a frame with legs, headboard, foot board, mattress, and pillows. Most of the bed is made of a wood material. The sheets and pillows have fabric textures and some randomly chosen colors applied to them. Large beds have two pillows, while narrower beds have a single pillow. For now, all the parts of the bed are drawn with cubes. Here are some examples of beds with various sheet textures.

Bed with two pillows and plain white sheets placed along a wall in the bedroom.

Another bed with patterned/textured sheets and a single pillow next to a bookcase.

A bed with fancy red sheet texture against a wall with windows.

Those are all the features I've added since the last post. I won't get into the various other optimizations and bug fixes this time. There are many more room items to add. I can think of dressers, couches, TVs, lamps, and kitchen items. Offices need cubicles and computers. Maybe indoor potted plants as well? I'm sure it will be tricky designating a room of the house as the kitchen.

3 comments:

  1. Wow! The furniture really makes the space come alive!
    That round recycle bin looks only large enough a single soda can (which I'm sure you'll put on your list of objects to add).
    I really like the bookshelves! Are you planning on doing LOD rendering? Seems like you could render the bookshelf to a texture and make it a cube in the distance. Could do the same for the books? Cubes when far away, add covers when closer up, and even individual pages when you're really close: http://peripheralarbor.com/gallery/v/CG+Art/scripts/Book.jpg.html

    The idea of parametric bed widths is so funny to me. I'm so used to the standard mattress dimensions! Can you add canopy beds? Then your system could out-do The Great Bed! https://en.wikipedia.org/wiki/Great_Bed_of_Ware

    ReplyDelete
    Replies
    1. Thanks. Yes, I definitely think the furniture improves building interiors, which is why I kept adding different items.

      Recycling bins and trashcans come in various sizes. Maybe that one is too small. Maybe it's already been increased, I don't remember. I do have a very small trashcan in the bathroom of my house.

      I've made the books more 3D and added cover pictures and titles since that post. These are added when the player gets close to the house using simple LOD. I also added tilted books. I haven't rendered bookshelves to textures because they're all unique and there are too many to efficiently store as textures. The vertex data is stored compactly and hidden surfaces are removed, so I suspect the geometry is actually smaller than a texture anyway. I estimate that the average bookshelf with books is only ~30kB of vertex data.

      Yes, in real life there are only a few standard mattress sizes. However, it's easier in code to simply choose a random number from a range, and the player can't really tell anyway. I haven't added canopy beds. Maybe it's something I can add in the future - thanks for the suggestion!

      Delete
    2. I changed beds to use standard mattress sizes. I guess that's more reasonable now. Beds still have some random height variation. I still need to add bedposts and canopies and things like that.

      Delete