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. |
Great work! That's a lot of progress from the last time. I feel like there's not a lot more to go before being able to populate arbitrary building shapes.
ReplyDeleteI think your X-Y axis aligned interior walls are a safe assumption. I have basically never worked on a building with non-ortho-linear walls. I did work on one multi-story condo complex where one wing had a different coordinate system, but all the walls there were ortho-linear aligned with themselves. Getting multiple wall grids to line up might be tricky, but that's certainly a safe way to approach the problem.
It still bothers me that the inter-story distance (from the drop ceiling to the finished floor of the story above) is less than a foot. The small interstory would be normal for residential buildings (but then the ceiling is drywall, not accoustic tiles). For commercial buildings this is almost always at least 2 feet, and often much more (6' of interstory is not uncommon, as it leaves plenty of room for structure and routing plumbing, supply return and exhaust ducts, gas lines, power and network, etc.)
I've been in some buildings with non-right angle walls (both interior and exterior), but I can't remember ever being in a building with curved exterior walls. I think what I have is okay. The only limitation I don't like is that I can't place objects along the inside of the curved exterior walls.
DeleteI do have a system to add different ceiling-floor spacing for office buildings. I set it to something like 1.1x the spacing of houses to test it out. The problem is that in order to make this work, I need to have the spacing between floors be larger in these cases. Right now everything inside the building is calculated from the floor-floor spacing as a sort of base unit of distance. For example, table heights are something like 40% the floor-floor spacing. So if I increase this value, all of the room objects are too large. Stairs are too steep to climb, etc. What I really need to do is change these hundreds of reference calculations to use the ceiling-floor "usable" spacing within a room instead, which is independent of the gap between the hidden gap between the floor above and the ceiling. And things like stairs would need to be longer and have more steps in these cases. I just haven't gotten around to doing this yet.
While you're changing things, you should de-couple the furniture size from the ceiling height entirely. In case you want to put in an atrium, houses with 9' ceilings, etc.
DeleteI can have rooms that are multiple floors high. Some attics and garages are like this. But yes, the furniture size should be decoupled from the building geometry, but what should it be a function of? The doorway width? Road with? Car length? Player height? Player height is a bit questionable because that's also configurable to make the player optionally match the kid model, so maybe it's not a good idea. I'm not using an absolute scale because I want to be able to rescale cities to match particular heightmaps - meaning the actual world units are in whatever units the heightmaps were in. I was originally assuming floor spacing was around 8 feet and calculating the size of other objects from that.
DeleteI'd bite the bullet, make everything absolute scale, add a "furniture scale" or maybe even "inhabitant scale" variable for adjustment, and then scale the heightmap instead of the city.
DeleteCan you populate some of the trees in the wilderness with tiny "borrower" houses?
I think it's too much effort to change this all now. I can't complete it in a single programming session, and I don't want everything broken in the meantime. Maybe some time when I have a week off work and nothing else to do. The only problem I'm aware of that this would solve is the one related to spaces between floors of buildings.
DeleteI'm not sure what you mean by trees with borrower houses. Do you mean houses in the trees?
Tiny little people, like "the borrowers" book series.
Delete