Wednesday, June 14, 2023

Procedural Building Additions, Interior and Exterior

Once again I have a number of procedural building changes that are too small for their own blog post. I'm working on stop signs, which is a larger topic, but they're not done yet. This post will list the various additions I've made to building interiors and exteriors.

Fires

I showed off the spark particle effects that were added for broken TVs and basement lights in a previous post. When I reviewed that video, it made me think that all of those sparks landing on the rug should set it on fire. So this is what I implemented. Now a spark landing on a rug while it's still hot and glowing has a chance of starting a small fire. I haven't worked out how to handle large fires that spread to the rest of the building, so for now the fires will go out after a few seconds. They do, however, leave lasting burn marks on the rug.

Fires also serve a minor gameplay purpose. In the (unlikely) event the player starts a fire and then walks through it in game mode, they take some small amount of burn damage. This provides a minor distraction from other gameplay tasks and forces the player to pay more attention in rooms with broken lights. Other animals such as rats and cockroaches have updated logic that attempts to avoid the fires. I haven't yet updated the building AI and zombie logic to avoid fires. I feel that zombies should be able to walk through small fires to get to the player.

Here's a short video showing fires created from sparks in the same room as the earlier sparks video.


Attic Vents

I wrote about 3DWorld's interior-exterior geometry in a previous post. This is where "room" objects can be added to building exteriors and will be lit from the sun and moon outdoor lighting rather than interior room lights. I used this a few weeks ago to add window frames and window sills. Now that I have this system in place, I can use it for more exterior detail objects.

One object I'm missing is exhaust vents that pass through the attic and its roof. I added these for furnaces, water heaters, and stove hoods. These are simple pipes that are split into two sections with the lower section inside the attic using interior lighting, and the upper section on the roof using exterior lighting. The vent sections inside the attic also participate in player collision detection and act as blockers for attic object placement. Anything I can do to increase attic clutter improves the realism of the scene.

Here is what these look like from both inside and outside the building.

House attic with a vent from the furnace on the left and another larger vent from the stove hood two floors below on the right.

The same two vents protruding through the roof with end caps that use sky/sun/moon lighting.

I may add more details in the future if I get around to it. Maybe I can make some of them have rotating blades like a fan? I might also add vents for the various plumbing fixtures such as sinks and toilets. I'm not sure exactly what needs a vent. My real life house has something like eight different vents on the roof of various sizes, and the roofs of my procedural buildings don't seem to have enough of them.

Parking Garage Sprinklers

I added large vertical fire suppression/sprinkler pipes to office building parking garages over a year ago. Then a few months ago I added smaller horizontal pipes that lead away from the main water pipe across the roof of each parking garage level. I finally got back to working on this sprinkler system by adding secondary horizontal lines that extend from these first lines. These pipes are placed relatively close together in a grid pattern that attempts to cover all reachable areas of the parking garage.

The placement system must check for intersections with objects such as stairs, elevators, and support pillars. I allow sprinkler pipes to pass through parking garage separator walls in a similar way to water, gas, and sewage pipes. I hung these lower than most other pipes so that they touch the bottoms of the ceiling support beams and stay out of the way of many other ceiling objects. They're placed after other types of pipes, so I need to check for pipe intersections as well. I wrote some code that is able to place partial sprinkler pipe sections in incrementally shorter lengths when the full pipe fails to be placed. In some situations, sprinkler pipes can clip through ceiling lights. I fixed this by a combination of moving the lights to the side and shortening the pipes. I would say that about 75% of the total pipe length can be added on average, which is good enough for now.

Next came the sprinklers themselves. I added upward pointing vertical sprinklers at regular intervals along the smallest diameter (last placed) horizontal pipes. Once again, I had to check for overlaps with other objects near the ceiling and omit the sprinklers in those cases. I also shortened pipes to remove extra segments that had no sprinklers or other connecting pipe sections. Short pipes that don't end at walls are attached to the ceiling with small metal loop hangers/brackets.

All sprinkler pipes are drawn as red cylinders with brass fittings, connectors, and end caps. The bright red color makes them stand out and adds contrast to the otherwise gray parking areas. Sprinklers are formed from three cylinders of different lengths, radii, and colors. I considered using real 3D models for each one, but I'm worried that too many will be visible in large parking garages and this will hurt the framerate. In some cases nearly 100 sprinklers can be seen in the player's view.

Here are two screenshots of a parking garage with pipes and sprinklers. The first is without cars, while the second is with cars and indirect lighting enabled.

Parking garage with a network of red pipes and sprinklers attached to the ceiling.

The same parking garage as above, this time with cars and indirect lighting enabled. I feel it's easier to see the pipes with this lighting.

Newsracks

This one was suggested by my mother. I've added newsracks along the sidewalks of some city streets. They come in four different shapes/styles and a number of different colors taken from reference images of real newsracks. These are all drawn with geometry generated from code, mostly cubes of different sizes. I added a fake newspaper image I found online to the transparent doors of each one. As usual, newsracks are collisions objects that block the player and participate in pedestrian path finding. At some point I may decide to make these interactive so that they player can open them up and take a newspaper. Maybe the player will need to find coins in a building to do so.

Here are two example images, again without and with cars.

An example city sidewalk with newsracks of various sizes and colors along the edge of the road.

More "The Fake News" newsracks, this time with cars enabled.

Rooftop Water Towers

A few weeks ago I did a Google search for other people's procedural buildings to see if any of them inspired me to do something new. One YouTube video showed buildings with rooftop water tower models. That seemed like something easy to add to 3DWorld's buildings that would increase the variety of their roof areas and improve city skylines. Water towers are relatively simple to model out of cylinders and cones for the tower and pipes, plus cubes for the support structure. So I decided to generate the geometry rather than using an existing 3D model from somewhere online. I used a metal plate texture for their exteriors and pipes.

Water towers are placed on some buildings above a certain height and a minimum rooftop area. These are skipped for buildings that already have helipads, skylights, antennas, or other previously placed objects. Water towers are placed before smaller objects such as AC units, signs, and roof access doors, so these objects must check for existing water towers before being placed. Each water tower is also connected to the network of water pipes in the basement, if present.

I may as well continue the trend with two images of the water tower and different sun positions. I added a vertical pipe under the tower in the second image. That Ferris wheel in the background is a great landmark for navigation!

Initial metal water tower 3D model created from a texture cylinder, a cone, and five cubes.

The same water tower viewed with a different sun position and a metal cylindrical pipe added to the bottom to carry water.

Pool Decks

At this point I had both in-ground and above ground swimming pools in the back yards of some houses in my residential neighborhoods. The above ground pools had ladders, but the in-ground pools were simply surrounded by grass. This isn't realistic. All of the in-ground pools I've seen, including the one in my own back yard, have decks around them. So I placed a randomly selected concrete or wooden deck on the ground between the pool and the house. In rare occasions there was some other object between the pool and house, so the deck is omitted in that case. I added some additional random variation that extends the deck to the length of either the house, the pool, or both rather than only inserting it between the shared edges of the two objects. Sometimes the deck will line up with the back yard fence, which I think is a nice touch. This was a minor change that was easy to add.

As expected, two images of concrete and wood pool decks. I think I need to add more details around these pools to make them look interesting.

Simple concrete pool deck placed between the house and a rectangular in-ground swimming pool, enclosed by a fence.

Another swimming pool with a long wooden deck connecting it to the house.

House Balconies

Some of the other procedural building posts and videos I looked at included balconies in their residential buildings. I decided to use the exterior geometry system yet again to add balconies to upper floor rooms of some houses. There are a variety of different balcony styles with wood slats, metal railings, and 45-degree rotated railings, possibly with metal trim of different colors.

Next, I added potted plants to some balconies. These initially didn't work well because the plant leaves aren't drawn as they're on the wrong side of the transparent windows. It took me awhile to rearrange the transparent and alpha mask drawing code to make this work properly. I plan to add small tables and chairs to balconies, but I haven't gotten around to doing that yet.

Balconies are somewhat incomplete at this point and have some issues. First, they're not actually connected to the houses with a door, so the player can't walk out on them. Adding this type of door appears to be complex and difficult. I have the same problem with fire escapes. It may require significant changes to the building creation control flow because currently the balconies (and fire escapes) are added after the doors and windows.

Second, the lighting and shadows aren't quite right. Since balconies are between the exterior and interior, they should have interior light shining through the windows onto them. At this point they don't. Balconies receive shadows from the house but don't self shadow because room objects don't contribute to the sun and moon shadow pass. This also means they don't shadow the rest of the house or the ground below them. I don't have a good fix for this, so I'm hoping the player doesn't notice. I actually didn't notice the lack of shadows at first.

I'll add several screenshots this time since balconies come in so many varieties. I also changed some settings and fixed a few things (like the missing plant leaves) in the process of taking these.

A house with a small balcony with white metal railings and an empty flower pot. The edge (non-corner) railings are rotated 45 degrees just to show I can add shapes other than axis aligned cubes!

Balcony with wooden slat sides and black metal railing and edges.

A longer railing along the side of a house, this time with a black metal railing and bars. This one has two "empty" flower pots.

A balcony with wooden sides and a brown railing, with two flower pots. These ones have actual plants because I fixed the alpha mask material drawing to work outdoors.

I should probably add vertical posts to support the corners of some of the larger balconies. That means I do have to figure out how to enable collision detection for what are supposed to be indoor room objects that happen to be placed outside the house. The lack of shadows may also be more obvious when I add the posts. I'll have to experiment with this later.

I think this post is long enough now. The next post will probably be on the topic of stop signs.

Monday, June 5, 2023

Cockroaches in Buildings!

I can't resist adding another "animal" type to 3DWorld's procedural buildings. It was a lot of fun (and also a lot of work) to add rats, spiders, snakes, and flies. Now that I have all of the framework in place for animal drawing, animation, physics, collision detection, behavior, etc., it should be easy to add more animal or insect types. Cockroaches are somewhat of a cross between rats and flies. (Well, assuming you only have the four animals/insects mentioned above to work with.) They walk on the floor and run away when scared like rats do. Their placement and drawing code is closest to that used for flies. I was able to reuse enough code from existing animals that it took me less than a week to add cockroaches, compared to several weeks for rats and spiders.

Cockroaches have some unique behavior characteristics. They only spawn in dark rooms away from the player, building AI people, and zombies. They have a random walk => stop => turn cycle similar to rats with some degree of random speed variation. When they're startled by a light, a sound, the player, or another person, they immediately run toward the closest wall in a direction away from whatever scared them. When reaching a wall or other object flagged as a hiding spot, cockroaches disappear inside and are respawned somewhere else in the building. Their new location will be somewhere dark and out of view of the player. If they instead hit an object they can't hide under, they turn away from the object, suspend their fear state for a few seconds, and walk in a random path.

So far I haven't assigned any gameplay purpose for cockroaches. They don't affect the player or zombies. The player can't pick them up, but they can be squished by dropping objects such as books on them the same way as spiders. However, it's quite challenging to squish cockroaches due to their fast speed, small size, and ability to hide under objects. Maybe I should track kill counts for both spiders and cockroaches. As a placeholder for this, I add $10 damage for each squished bug for building cleaning costs. (For reference, cleaning the blood stains from a player death is $100.)

I originally drew cockroaches as simple stretched brown hemispheres: long and flat. I didn't bother to add legs because it was difficult to get close enough to see them. Later, I decided they looked too plain, so I found a 3D model online that looks much better. So far I haven't felt the need to animate their legs because they're so small and move so quickly. The 3D model rendering code is almost identical to that used for rats, in particular because they're both always oriented in the XY plane on the ground.

Here's a video showing a building with 1,000 cockroaches. They scatter when I turn on the light and approach them. Note that these are drawn at an incorrect height and their legs are under the surface of the floor. I've fixed that in the other screenshot and video below.

And here's a screenshot showing the 3D cockroach model I used. Yeah, it's pretty small and hard to see.

Cockroach on the floor, drawn with a 3D model.

Here is a video showing me attempting to drop books on cockroaches to squish them. It's challenging and took me a number of tries to get the first one. They have yellow blood!

Do you have a suggestion for what animal or insect I should add next? If so, please leave me a comment.

Wednesday, May 31, 2023

Procedural Buildings: Breakable Objects and Particle Effects

I have a long list of smaller additions and improvements to show, so I'll split them up by category. This post will show some of the breakable and broken objects I've added to buildings, and the particle system I implemented to add glowing spark effects to broken electrical objects. Some of these have been around for a while, while others were recently added.

Broken Car Windows

I added the ability for the player to break into parked cars in office building parking garages to steal items. This was done a year or so ago, but I don't remember posting a screenshot or explaining it on this blog. Each car window can individually be broken once by using the player action key on the car. Some cars happen to be unlocked and can be looted without breaking the window. I can't easily modify each instance of the car's 3D model to remove a window, but I can draw a pile of broken glass on the ground at the player's feet. As you might expect, each pile of glass is unique. This glass will remain in the building forever to help players keep track of which cars they've already broken into. This was an easy change to make. I may decide to go back later and make the glass shards dynamic physics objects, or possibly allow the player to pick them up for some gameplay purpose.

A car in a parking garage with broken glass from the window on the ground.

Broken Mirrors

Throwing an object at the center of a building mirror will break it and add a crack decal texture over the reflective surface. One of two crack textures is randomly selected for each mirror. This works with dresser mirrors, office bathroom wall mirrors, and house medicine cabinet mirrors. While the player can drop various types of inventory items, the only object types that can be thrown are basketballs and soccer balls. Therefore, these are the only objects that can be used to break mirrors and other glass surfaces.

Breaking mirrors plays a loud glass shattering sound, which of course is guaranteed to attract zombies. Breaking a mirror also unlocks the "7 Years of Bad Luck" achievement.

Mirrors can be broken by throwing balls at them. Broken mirrors are cracked but still reflective.


I've considered making windows breakable, but so far haven't figured out how to do this. Windows aren't individual objects but are instead drawn along the entire side of the building, and are visible through cutouts in the walls. I would need to split these up into individual window panes somehow, then add the crack texture to each broken one. Some of the house windows are already divided vertically or horizontally into 2-4 panes, which further complicates things. A second challenge is adding a transparent overlay to an object that's already transparent in a way that makes the alpha blending correct. Of course, writing about it here will increase the likelihood that I actually complete this feature later.

Broken TVs and Computer Monitors

The player has been able to throw balls at TV and computer monitor screens to break them for a while now. The new feature to showcase is the particle system I've added that will spawn glowing sparks around the area where the ball and screen meet, as long as the device was powered by electricity. These sparks are physics objects affected by gravity with collision detection enabled for all room objects. I was able to reuse most of the basketball and soccer ball physics and collision code for particles, with some adjustments to physical constants to make their paths more pleasing. For example, sparks use lower gravity so that they remain in the air for longer.

Each broken object spawns a new group of particles that will disappear after their lifetime expires, which is currently set to a few seconds. This way only a small number of particles will be active at any given time and won't affect performance much. Sparks are drawn with an emissive colored material stretched out along the length of their velocity vector. Their color follows the normal black body light emission profile as their temperature decreases over their lifetime: white => yellow => orange => red => black. Light emission decreases over time, and transparency increases.

Later I decided to make these particles act as small light sources to illuminate the walls, ceiling, floor, and other nearby objects. The screenshot shows light sources, while the (older) video was taken before this was added.

Still screenshot of a TV screen that's just been broken with a basketball, with sparks flying around the room and producing light.

 
 

Broken Lights

There are two types of broken lights. A while back I added flickering lights with a random chance to occur in basements and parking garages. These lights are mostly on but turn off for a few frames every few seconds.

The new type of light I added is even more broken: normally off, with an occasional flash of light and a continuous shower of sparks. This was a convenient way to reuse the particle system I developed for TVs in a setting where the sparks are constantly visible, rather than only being seen briefly for a few seconds. These types of lights are only added to house extended basements rooms, giving them a dark and creepy atmosphere. Broken lights are always initialized to the off state and must be turned on by the player to make them active. This increases the amount of surprise when the player encounters a shower of sparks rather than a lit room. So far I haven't decided if I want the building AI people to turn these lights on as well.

Still screenshot of a broken light emitting glowing sparks that fall to the floor. Maybe they should catch the rug on fire?


It's possible to have a large number of broken lights in a building due to the way occlusion culling works. Since they're conveniently only added to basement rooms, I don't have to worry about them being visible through windows. The player can only see the lights and the sparks when the clipped light volume is visible. This means I can reuse the existing light bounding cube occlusion queries to skip generating, updating, and drawing the particles when the light is blocked from view by a wall, ceiling, or floor of the building. As soon as the player turns to leave the room or walks around the corner, these lights will become inactive and won't take any resources to draw or update.

Future Work

Broken lights don't really affect gameplay, except for reducing zombie (and player) visibility due to the dark room. Maybe I should have sparks catch rugs on fire? It sure seems like that rug should be bursting into flames in the screenshot and video above. That could damage the player and also either distract or kill zombies. Okay, I'm adding that to my TODO list.

I have plenty of other ideas for breakable objects. I could add a tool such as a crowbar, hammer, or bat that can break objects. I could allow some inventory items such as cups and vases to be dropped or thrown on the floor to break. I could provide a way for the player to create holes in the walls, ceilings,  floors, or doors. There are so many possibilities. I need to take some time to think about how gameplay will work and the various ways in which breaking/destroying objects would benefit the player.

Monday, May 8, 2023

Procedural Buildings: Connecting Basements

Some of the houses in 3DWorld have extended basements consisting of a maze-like tree of underground hallways and rooms. These can run under the house and nearby buildings, as long as no other buildings are intersected. I like these mazes. I like anything involving underground networks to explore where the player can get lost, in particular in a horror game setting. The current limited size of each house's extended basement prevents me from adding larger mazes. It's not just a problem with available space, it's also a problem with reduced performance when adding too many rooms to a house or making it's bounding cube too large. The various building view culling methods I'm using are less effective when many buildings overlap in 3D space.

One workaround for this is to allow basements to connect between multiple houses. In fact, they can connect together in a massive dungeon maze that runs under the entire residential neighborhood. This case is made easier because all houses are at the same elevation, so I don't even need to add stairs to connect rooms at different levels. I decided to start by grouping houses by city, and attempting to connect each house in the city to every other house placed after it. This is quadratic in runtime, though only for a few hundred houses at a time since they don't all have extended basements. The final runtime for this step was only 19ms for all four residential cities combined. I didn't even have to make the code multi-threaded.

If two nearby rooms that project in X or Y can be found for each of these houses, a new hallway room is added to connect them. I cut a hole in one of each of the room's walls to insert a door. I placed a red light on the ceiling of this room to make it stand out more. This way I can find and debug connector rooms by disabling collision detection and flying below the ground looking upward for the red lights. I'm glad I added this for debugging because I certainly found a lot of problems with this system! Every room had some new bug. I'm sure I haven't found and fixed them all yet.

The only downside is that this was very complex and difficult to get right. Not only does it need to look correct, but the AI and physics must work as well. On the visuals side, I had to make sure the occlusion culling didn't flag the other house as invisible as it normally does with other buildings when the player is underground. Then I had to work out the lighting and shadows so that the connector room could cast and receive both light and shadows from the rooms of the two houses that connected on either end. These had to be updated when the user toggled the lights or opened/closed the door from either side. In addition, the ambient lighting system had to consider light coming through the open connector door.

Physics was also quite challenging. I had to update the player collision detection to allow walking between buildings without being blocked by the basement bounding cube, and without the player being considered outside a building for one frame and popping out of the building on the ground above. This last problem took me many attempts to fix! In fact, I think it can still happen in rare occasions when a building person or zombie pushes the player into a wall near the connector room.

Players had to be able to open or close the connector room doors from either side, which means I had to support interacting with a door belonging to a different building from the one the player was inside. Next, I had to allow the player to carry inventory items between buildings without them being deposited in the player's permanent loot collection as would normally happen when exiting a building. Building animals and people AI were updated to handle these connector rooms. I didn't quite figure out how to have them cross between buildings, but at least they don't get stuck there. Zombies will follow the player right up to the connecting door and wait for a few seconds before walking off. This provides the player with an escape route. I think that's fair because it's far too easy to get cornered or lost while being chased in a basement maze. However, chances are some zombie in the other building heard you and is on the way to find you.

Probably the most difficult feature was adding support for basketballs and soccer balls that could be rolled, kicked, or thrown through the doorway into the next building. These objects have physics state owned by their contained building. I had to transfer this state from one building to another in a way that preserved the properties such as position, velocity, and momentum. There were various special cases to handle. For example, the player can stand in one building while holding the ball through the doorway into the other building. The physics must be seamless across the boundary.

Here are some examples of extended basement connector rooms.

Extended basement connector hallway with red light, a picture on the wall, and a rug on the floor.

Hallway connecting one house basement to an underground storage room in a different house.

Room connecting two house basements. You can tell that the connector room belongs to the building the player is in because the carpet matches.

They look very similar, especially with the red lights. At the moment this is a somewhat intentional way to let the player know they're passing between buildings. There's also a "Welcome to <NAME> Residence" text to let the player know whose house they're entering. Maybe I should select a random light color from a list of colors? I'm not sure. I experimented with different colors and I definitely like red the best because it produces a sense of danger and has a good contrast with the off-white color of other ceiling lights.

What's next? Maybe I'll figure out how to have people and animals cross between buildings. Maybe I'll connect office building basements and parking garages in a similar way. There are so many possibilities...

Sunday, April 30, 2023

Procedural Buildings: Improvements to Exterior Detailing

I've been working on various aspects of 3DWorld's procedural cities during the past month or so since my last blog post. I don't have a single topic that's large enough to write an entire post on. Just recently I did add a system for connecting the extended basements of houses together into huge underground mazes, but I don't have any good screenshots to show of this yet. So instead I'll review some of the improvements I've made to building exterior geometry. These are not in chronological order.

Scrolling Signs

First up we have scrolling company name signs. Signs were initially discussed in my February post. I did eventually get back to improving them, which was partially inspired by scrolling text I saw on some of the buildings in a video of someone else's project. Their effect looked very different from what I wanted to achieve, though it was the same high level idea. I applied the scrolling effect to the illuminated night time signs on the roofs of tall city office buildings, since these are the most visible to the player.

This took a surprising amount of work to get right. It was relatively easy to make the text move one character at a time to the right and wrap characters from the end back to the front. Smooth scrolling was much more difficult because it required updating my text drawing system to handle partial characters so that I could have the last character split across the last and first position as it wrapped around. This worked by duplicating one of the characters so that it was at both the beginning and the end, and then clipping the outer edges of each to the correct final size.

Then came the even more difficult task of making this work with my non-fixed width font. Some of the characters (such as 'i') are much narrower than others (such as 'M'). This means that the scrolling rate is different for each character, and narrow characters spend less time split across the ends than wide characters. I had to first render each character to a temporary buffer to determine the start and end positions within the sign display area. Then I was able to calculate a mapping from each character to the point in time where its left edge passes the scrolling point. From this I could take the game time, calculate the fractional component of the scrolling position from the period, and look up the time value to get the first character to draw. The delta time between the character appearing and the current time value was used to determine how far along that character the movement was, or the split position in the case of the last character.

This still doesn't work perfectly, but it's much better than my previous two attempts (not shown). Here's a video showing several scrolling signs. YouTube seems to have made this blurry and hard to see. I'll add a screenshot after the video, but you'll have to imagine how the text looks like when scrolling and just trust me that it works. Unless it's just me and others don't see a blurry video?


Still image of some scrolling neon company signs attached high up on tall office towers. Shown at night, with a bloom postprocessing effect applied.

 

Exterior Trim

Houses were looking too plain, in particular the windows. What had previously been limiting my ability to add exterior details was the way in which building geometry is generated and drawn. I'm creating the exteriors of every building ahead of time and drawing them at large distances of over a mile because they're actually visible that far away. Even the tiny windows can be seen in the distance! This is especially true of glowing windows at night. I can get away with adding a ton of interior detail to buildings because both their generation and drawing can be deferred until the player is close enough to see these details through the windows. The difference in drawn distances for exterior vs. interior is user-configurable but generally as much as 5-10x.

The reason I can't draw exterior geometry as interior objects is because they use different lighting models and shaders. Exterior lighting consists of directional sun and/or moon light, hemispherical ambient lighting from the sky and ground, and a 2D grid of point lights from sources such as streetlights and headlights that are mostly active at night. Interior lighting is a combination of room-based point lights in a 3D grid, combined with optional indirect lighting computed in the background when entering buildings. If I were to draw building exterior objects as interior geometry, they would appear too dark because sun and moon light is not enabled and building interior room lights are on the other sides of the walls. You can actually see this problem in some of the earlier "Welcome" signs I placed above doors. These looked gray but were actually a bright white color with only a small amount of ambient lighting.

Wait, but what about other exterior objects? For example, I have some screenshots with house fire escapes. I cheated! Fire escapes are black, and the player can't tell that the lighting is wrong. Okay, what about those house number signs such as the one shown here? They're not black. And neither are the flags I added to houses. Well, these are actually objects that belong to the city itself, not the house they're attached to. They're drawn by the same system that draws street signs and manhole covers. This is why you only see them in cities and not in the randomly placed secondary buildings I have scattered around my world. Right, then what about gutters on houses? I don't remember ever discussing them in my blog, but maybe some of you noticed them on my recent house screenshots. Well, these are part of the exterior and are generated and batch drawn for the entire city at once. Their geometry is simple enough that they don't add much overhead compared to the exterior walls, roof, doors, etc. And skylights? My skylight drawing solution cheated as well by using an invisible room light above/outside the building pointing in the direction of the sun to light the top surface. No, up until now I didn't have a system to make detailed exterior lit objects work properly.

The underside and edges of gutters can be see on the house and garage. They're simple quads for the bottoms and triangles for the ends. Sorry, I don't have any good screenshots of the old gray Welcome signs because I tried to hide their poor lighting from everyone in previous posts. Oh, and yes, some of the house roofs have overhangs now.

It's time to change that. Now the building drawing has an additional rendering pass for per-building objects that are placed on the exterior and drawn with sun/moon lighting. Yes, this adds some frame time overhead, but it's not very significant. The real cost was the complexity required in the control flow and a system to swap shaders while drawing spatial blocks of buildings. My solution is a bit ... odd, though, because these objects are still part of the building "interior" and are generated at the same time as the interior. Which means they don't have the same long draw distance as exteriors, which means they can't be too large, or they'll obviously pop in and out as the player's distance to the building changes.

The first step was to change the "Welcome" signs and other small items to use the new system. Then I realized the exterior faces of some of the windowing coverings had the same problem. I fixed blinds and bathroom glass block windows to draw their exterior surfaces as what I suppose I have to call "exterior interior geometry." I didn't realize how broken that looked until I fixed it! Finally, it's time to add new content. This includes proper 3D window frames, window pane separators for houses (apparently called muntins and mullions), window sills, and exterior wall trim. Window frames and sills were added to some styles of office buildings as well. Window style varies per wall/floor of each house.

I definitely needed to improve the look of windows because their exteriors were too plain and flat. The lighter window border I had was drawn with a low resolution alpha mask texture originally designed to be viewed from a distance. This didn't match with the detailed trim shown on the interior of the window. I did brighten the window border in the texture and doubled the resolution; that helped, but wasn't enough. Now the new windows with physical geometry look more 3D, detailed, and brighter:

Exterior of a large house with properly lit window frames, pane dividers, window sills, blinds, and signs.

Next, I wanted to add some separation between the ground floor and upper floors of houses. Many houses use different materials for these, for example, brick or stone on the bottom and wood, siding, or stucco on the top. It's easier to start with a simple band around the perimeter of the house than jumping into a whole new system of combining multiple exterior wall materials on a single building. (I did in fact experiment with siding, though I haven't enabled it and I'm not ready to get into that topic yet.) A thin white band to match the windows is an easy place to start. Remember, I can't make anything too large because it's only visible when the player is close by. I'll also only enable this for 20% of buildings to make it a somewhat rare decoration. Well, rare may be too strong a term because it's not nearly as rare as houses that look like duplexes, triangular office buildings, and office buildings with overhangs. So I'll go with "uncommon" instead.

House with window trim and exterior wall trim at the top of the first floor that wraps all the way around.

House trim is always white because I feel it makes them look clean and bright. Office buildings have multiple shades of trim from gray to black that are designed to improve contrast with the average brightness of their exterior walls. Here's an office building with dark glay-black trim.

"Dark Mode" office building.

I'm still thinking of what else I can add to buildings. I can potentially include significant object detail since it's only drawn for nearby buildings. Drawing cubes around every window may seem like a lot of geometry, but it's far, far less than what's drawn for the building interiors.


Ceiling Fans

Did I say I was going to discuss exterior geometry? I thought I had a third topic, but I suppose I forgot the last topic in the process of writing that long section above. Having only two topics isn't enough, and I just realized that I haven't shown my ceiling fans yet.

The more animated and interactive objects in buildings the better, right? So how about one that's both: a ceiling fan that can spin and is controlled by the player. I even put a light on it. However, it did take a surprising amount of time to find a suitable 3D model, and I'm still not very happy with it. I had to have a model that satisfied the following constraints:

  • Free. Because my goal with the 3DWorld project is to not spend any money on it, so that I can make it free and open source without "losing money."
  • Not too high poly, so that I can spam these into every room if I want to.
  • Mostly white in color so that I can potentially repaint it, though so far I haven't done this.
  • Relatively wide and short so that it fits in the limited ceiling space of my houses without clipping through the player's or AI's heads.
  • Two separate objects/meshes for the blade vs. base so that I can animate it to make it spin. Or, in the case of the model I ended up using, completely symmetric so that I can spin the entire model and the player doesn't know the base is also spinning. (Though in my case it's not perfectly symmetric and you can see the base rotating).
  • Something that allows a light to be easily attached to the bottom and that can be set as emissive when on. This rules out any fans that come with fancy light fixtures or multiple lights.
  • A model that loads properly in Assimp or my own OBJ reader. In particular, I had to rule out a few with missing embedded textures.

Out of the ~100 models I found online, only one really fit all requirements, and not very well at that. But it is what it is, a crappy ceiling fan is better than no fan at all. It's not that it's a bad model, it's just very simple and plain. Behold, we have the bedroom ceiling fan:

Ceiling fan in the center of a bedroom. Trust me, it's currently spinning. I don't know why I didn't include a YouTube video of this. Certainly not because it would look just as blurry as the scrolling neon signs in the video above.
 

I guess this works? The room is a bit darker than I would like because the light is lower than the ceiling and the upward light is blocked by the fan itself. I'm sure it would look better with indirect lighting. What's that? You demand to see that screenshot as well? Fine, I'll go create another one. Here it is:

Room with ceiling fan, with indirect lighting!

Yes, this definitely looks better. If only it didn't come with a framerate cost. I'm not sure why the base of the fan is black though. Maybe it's because it's halfway buried in the ceiling, or its lighting is blocked by an occluder from the fan that's too large, or the fact that it's spinning makes the lighting computation wrong. Ah, wait, I think it's because the normals are backwards on that top part of the fan.

Anyway, it's properly interactive. The player can switch the fan and light on and off together with that light switch on the left. And it's also gated by some breaker in the breaker box in the basement, if there is one. Maybe sometime in the future I can include these in gameplay somehow. Are they zombie distractions? A fun, crazy way to expand ball or duct tape physics? I guess you'll have to wait and see.

Monday, March 20, 2023

Procedural Buildings: Interiors for Non-Cube Buildings

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.

 

Saturday, March 11, 2023

Procedural Buildings: Flies

I've made some new additions to 3DWorld's procedural buildings: bugs. No, not that type of bug! I'm not talking about software bugs, I'm talking about insects. Flies, in particular. I've already added walking animals (rats), animals that crawl on walls (spiders ... which technically aren't animals), and animals that slide on the floor (snakes). I'm missing something that flies. I do have butterflies flying around outdoors, but they're not inside buildings.

I initially drew flies as black spheres. This looked fine initially because they were so small, but when I added logic for them to fly around the player the simple sphere model broke down. So I started by copying and pasting the code to generate the geometry for spiders, since flies have a similar look. They're both black, have bodies that can be formed from transformed spheres, have multiple eyes, and have thin legs that can be made with cylinders and cones. The differences are minor. For example, flies have only six legs rather than eight. The biggest difference is that flies have wings, and it's the wings rather than the legs that are animated. Wing animation is a simple sine wave transition between horizontal and mostly vertical, similar to how I animated butterfly wings. Wings are small and partially transparent, though the alpha blending doesn't work very well due to a lack of proper depth sorting.

Flies will fly around randomly with smooth direction changes and will avoid colliding with walls and room objects. They follow zombies around when a target gets close to them. They'll also follow the player if a trashcan, toilet, urinal, or dead animal is picked up and stored in their inventory. (Note that the player can't actually carry a urinal.) They don't do any damage or have any other gameplay effect other than getting in the player's view, buzzing constantly, and generally being annoying. Here is what it looks like to be swarmed by flies:

Flies follow the player inside a house when the player picks up a trashcan.

I recorded a video of a swarm of flies following the player around. Aren't they annoying? I'm hoping they distract the player from watching and avoiding the zombies.

At this point I have all of the components in place for adding other insect and animal types to 3DWorld's buildings. I have support for walking on the floor, climbing walls and objects, and flying through rooms. It's fun to add new creatures!