I think I'm going to continue with these shorter posts every week or two since they're easier to write in a single night. I'm continuing to work on adding a variety of smaller features to 3DWorld's procedural buildings. It seems there are an infinite number of these changes to make.
One item that's been on my TODO list on Trello for awhile is generating interiors for non-axis aligned cube shaped buildings. This includes buildings formed from rotated cubes, cylinders, cylindrical sections (with a flat side), and N-gon buildings with 3 or 5-8 sides. These shapes are difficult to work with because everything is so much easier when using cubes: Boolean operations, intersection queries, point containment, collision detection. Each of these is a few lines of code when using cubes, but tens to a hundred lines of code for arbitrary polygons and curved shapes. To make things a bit easier, I've diverged from the normal way I do things in 3DWorld and represented cylinders as 36 sided polygons rather than actual mathematical cylinders. This allows me to work with N-sided polygons for all of the possible building shapes, including cubes. Another simplification is to skip buildings composed of intersecting shapes for now and only generate interiors for vertically stacked sections.
I've decided that I want to continue using X-Y axis aligned interior walls for now due to their simplicity. This means I can really only divide the interior up into 2 or 4 pie slices by adding an X oriented and/or Y oriented wall through the center of each building, depending on space. Most buildings are large enough for both walls. This makes rooms bounded on two sides by interior walls, with exterior walls on the remaining side(s). Each room is effectively a cube clipped to the building exterior shape. This allows me to reuse most of the existing room code with an additional outer polygon test for queries such as collision detection, point containment, cube overlap, etc. For example, objects can be placed in rooms like normal with an additional check that they're completely contained inside the building polygon. Since these polygons are always convex, it's sufficient to test that each vertex of the bounding cube of the room object is contained in the polygon.
The difficult part is implementing this for every query, in particular all of the collision and containment tests done for dynamic objects. This includes people inside buildings, balls, rats, spiders, snakes, flies, and, of course, the player. It's not enough to handle collisions with the exterior walls. All of the AI controllers for these must be aware of the valid building/room bounds and avoid walking into walls in the first place.
Here's an example of the interior of a cylindrical building divided into four equal sized rooms. The rooms are rather large. Maybe I should fill some of them with office cubicles?
Interior of a cylindrical building that's divided into four pie slice rooms, one with stairs. |
You can see from this picture that I've added proper handling of stairs, ceiling lights, and even the wall trim along the edges of the floor. Stairs and elevators were particularly difficult for two reasons. First, they must be placed so that they don't intersect the exterior walls on either the floor above or below, and they also have enough space for people to enter them from each end without leaving the building. Second, I had to write the polygon clipping code that cuts a square hole for stairs and elevators into a circular ceiling and floor polygon. This was very math heavy and took me several hours to get right.
Some stacked building sections are probably too small to be practical and don't have enough space for both a wall and stairs. Here is an example of one such building. I'm not quite sure what to do with this one.
Interior of an oddly shaped, narrow, non-cube building with a single room containing stairs. This one is a cube with chamfered edges. |
There's one other glaring issue: This type of building has no windows or exterior doors. Right now I only have support for axis aligned cube windows and doors. The way windows are cut into walls using constructive solid geometry (CSG) on cubes with the stencil buffer doesn't really apply to curved/angled wall sections. I have windows on the exterior textures, but not on the interiors. It looks a bit odd when the player is inside these windowless buildings, though it may matter less in gameplay mode when the player is looking for items and avoiding the zombies.
Doors are interactive as they can be opened and closed by the player, which makes them more difficult to model on non-cube buildings. I probably need to find a way to add doors to one side of at least the non-cylinder N-gon shapes. At the very least I can add them to the axis aligned edges of hexagons and octagons. I added the code for this as an experiment. The doors look fine from the outside of the building and work correctly for letting players in and out, but they don't have their door openings cut into the interior walls. This is because I haven't yet written a CSG subtraction of the door from the angled building sides. So the doors don't actually show the interior or exterior through them when open. This looks wrong, but I suppose it's better than having no doors at all.
Next, I assigned the interior room types to offices so that the larger rooms can be filled with cubicles.
Round office building room filled with cubicles, with indirect lighting enabled. |
The cubicle placement algorithm is smart enough to only add cubicles that are fully contained in the room, and to leave paths on the sides of the cubicles and between the doors. I think this looks much better than mostly empty rooms with a single desk or table. Sometime in the future I might add different room objects that can be placed in this style of building.
Just for reference, here is what some of these buildings look like from the outside. You can see there are cylindrical/oval buildings, some with a number of sides at odd angles, and stacks of building parts.
Exterior of some non-cube shaped office buildings. Sorry, no cars or people in these screenshots. |