To achieve my grand goal to get my computer to build me a city from scratch, it needs to be able to create buildings from scratch. There are a lot of different ideas on how to do this, and I'll give a couple in
The first method is to rebel against the notion and say, "The computer can't be trusted to make buildings!" You get artists to build a library of houses, buildings and other structures and then distribute copies of these around your city. Of course the limits on your city is based on the limit of work your artists can output. With too few building templates in your library, your town is too monotonous. With too many, the artists might as well build the entire city themselves. You can get a little more mileage out of the templates by allowing the computer to randomly choose colours or textures (perhaps based on acceptable palettes). This gives more visual noise, but functionally, the city is still limited.
Another idea is based on the toy series "Connectables". These were toy cars that were just like normal cars, but the gimmick was that the front and back halves of the car were connected by this standard socket. You could attach the front of a limo to the back of a sports car to make a "fast but classy car", for example. The basis is
modularity where the whole is composed of smaller modules that connect together. To apply this to a house, suppose we have two parts to a house: a main part and a side part, like a garage or a pool area. By carefully creating various modules whose only limit is that they have to logically connect at specific points. Generalizing this you can make high-rise buildings by choosing a bunch of levels where each level is composed of a few modules that fit together to create separate areas on a level. The limitations of this method is that it is really just a finer-grained version of the first method. You need to create these modular pieces and ensure they fit together just right. Then you need to keep an eye on silly combinations like a CEO's office being on the ground floor, or having modules with violently clashing colour palettes. Also, this might be just okay for all the office buildings and houses, but a city requires specialized buildings like libraries, fuel stations and schools. Sure, you can have special libraries of modules for these types of buildings, but it really feels like there's too much work to be done by a human and the computer just throws it together like some city salad.
The next idea is to think of a building as a hierarchy. In a house you have a hierarchy like the following:
We now need two things from the computer: a method to produce these hierarchies, and a method to create a 3d house out of this hierarchy. The nomenclature I want to use is that the hierarchy is the "pattern" and the 3d house is the "expression of the pattern". We can supply the computer with a library of building patterns that we've distilled from our own buildings. If you trust the computer, you give it basic ontology by giving probabilities of a particular room type connecting to another. Ensuites don't connect to dining rooms, for example, but the computer doesn't know any better. With these probabilities, it is pretty easy to code up a method to generate millions of hierarchy patterns (by a Markov model, if you like).
The tricky thing is creating an expression of a given pattern. The modular idea before was this idea but with fixed patterns. The expression of a given room was a choice of rooms from a library of template rooms. The expression of a building was the sum of the expressions of the given rooms. Again there is the difficulty of creating rooms with strong enough structure to ensure the connectors work correctly, and creating enough of them. The reason we are having these problems is that we don't trust the computer to create the structures themselves. Time to take that leap of faith and give them the task.
An expression of a pattern really requires two steps from the pattern to the finished product. First up we need a outline of the pattern, and then an actualization of the outline. For example, take the pattern which is "one-room building". Two buildings that are expressions of this pattern are outhouses and (simplified) service stations. What's the difference? First up, an outhouse is much smaller and usually squarish, whereas a service station is bigger and more rectangular. The outline describes this difference by giving what amounts to a rough architectural sketch of the building. For a house, this would be an overhead drawing of where the walls and doors are. The actualization of an outline makes the difference between an outhouse and a service station much more obvious: by adding in windows, shelves and assorted equipment you get a service station and it's obviously not an outhouse. You can fool the computer and get it to use the outline of a service station but the actualization of an outhouse (a spacious wooden room with a single toilet). To correctly create these things, it's obvious that an actualization needs to be of the same class as the outline. Note that in my nomenclature, it's not strictly correct to say a service station is an actualization of the "one-room building" pattern. It's a neat shortcut for "an actualization of an outline of the one-room building pattern", but you don't actualize patterns directly.
How do we generate outlines, given a pattern? First up, we recognize that in the process of developing a city we'd be at step 4 of the following process:
- Generate terrain
- Draw roads on the terrain
- Take the space surrounded by roads and partition it into blocks (being the area that a building occupies).
- Choose a building to put on each block.
Thus we'd have some envelope of space we're allowed to build on, and some direction on what kind of building we are going to make. One way we can begin to start forming the outline is place down our hierarchy in graph form and then build the outline around that. We'd place our root node (the front entrance) near the road. We then have to place the nodes next in the hierarchy. A method to place these second-level nodes is to arrange them so they're at maximal distance from each other and away from the road. You can assign them bounding boxes with certain weights (and thus certain relative sizes) and give them this space to use for their child nodes. You can also bound this area by another box so that you get things like yard space. You keep iterating this (drop a level and place rooms accordingly) and you get a house. Placement of rooms can be dictated by the placement of doors. If you make your rooms rectangular but of differing sizes, then the outside of your house will most likely be rather irregular. A way around this to clip the house to a reasonable flat-walled shape. This might make rooms too small (or destroy vital doors!). You can also invert the idea and place rooms with no regard to how their walls overlap. Oversize them. Then clip your house to the desired shape, then use constructive solid geometry (
CSG) ideas to clip all the room outlines (if the dining room intersects the living room, chop out the intersecting space and thus make the dining room smaller). You can exploit the hierarchy to make the decisions on who get "differenced" from who. The result will be a house with regular exterior walls but irregular (but not illogical) interior walls. This may still create weird houses (like if certain rooms are really irregular, or have certain weird features like very tight walkways or a bedroom that is thin and U-shaped). By adding "aesthetic constraints" that the computer has to work with can remove these undesirable elements. How you practically achieve this is still on the drawing board.
Now given this outline of a house, how do you get an actualization? Firstly you need to create the geometry - the walls, floors, ceilings, roofs, windows, doors and stairs. Geometry like bookcases, toilets, showers, benches and the like will be treated separately. Creating meshes (arrangements of triangles, which is what computers love) from arbitrary CSG operations is a difficult thing to do in practice, but there are libraries out there for it (for example,
GNU Triangulated Surface Library and
CGAL). This is useful to get the basic walls, floor and ceilings. You can cut out simple windows (just empty rectangles) and then place in more complex objects (sills and frames). All of this is easier said than done and there's a lot of complicated mathematics in the background. And this is quite separate from any aesthetic or performance requirements.
Placing objects is another art in itself. For a given room type you can have a room object pattern that gives (in rough terms) the relation of objects in the room. From this you create an outline of the pattern (where objects of a particular type are placed around the room) and from that you produce the actualization (replace Generic Coffee Table with Coffee Table Type #3674).
Is there anything left? Well you have the texturing and lighting. We assume the placed objects (tables etc) have their own texturing, and so we only have to generate the textures for the ceilings, walls and floors for the interior and the exterior walls, floor, roof and ground for the exterior. I won't go much into this but the basic idea is that you allow it to choose colour palettes for all the features and then choose textures based on that colour choice. For added realism you need to create (or choose from a library) the shaders for textures so paint looks like paint and metal looks like metal.
Lighting you can do in several ways. The light-producing objects (lamps, computers, ceiling lights) can light your scene dynamically if you're hardcore. Typically you get too dark a result, it's quite demanding on performance, and it's hard to realistically add in light from windows. We can create what's called a light map which takes the static lighting in the house and precomputes a realistic, detailed lighting. The shadows and light spots are baked into "light maps" that are textures for your objects that simulate the effect of the lighting without having to compute it every frame. You use only static lights because static lights shining on static geometry never changes so you compute it once and for all time. Dynamic light sources such as lamps that can be knocked over need to be generated in real-time. Their lighting is typically not as detailed. The tricky thing is faking the static lighting for dynamic objects. Imagine a window that shines into a lounge room where there are movable couches. In the light-map the floor will be lit up, but the couch itself won't be, because it is only lit by dynamic lights because it is a dynamic (movable) object. If you place a few fake lights that work only on dynamic objects near the window, then you'll get a rough approximation of the lighting from the window. If it's close enough, then you should keep a fairly consistent visual feel. If you want to get more complicated, you can modulate the light maps from individual lights so that you only get the lighting from a ceiling lamp when it's on. This isn't tough for a computer to worry about, but it has to be weighed up against performance.
The basis for this installment was to show you some ideas on constructing geometry, as an introduction to a central concept I want to use, which is that of patterns, their expressions, outlines and actualizations. I think the vast majority of the game world can be constructed following these ideas. And if you generalize it, you can create meta-patterns, whose actualizations are patterns. These patterns have their own actualizations which are your world objects.