Sunday, October 18, 2020

Adding Content to Procedural Buildings

Now that mirrors have been completed, it's time to get back to adding content to the interior and exterior of buildings. Maybe after I've added enough object variety these will start looking like real buildings.

First up, I've added fences around the yards of some houses. These are very simple wooden fences with vertical posts and two horizontal slats. Some go around only one side of the house, and others enclose a section of the yard with a gap for a gate. Fences are only added to L-shaped houses that have an area of yard interior to their bounding cubes.

House with a simple wooden fence around the front yard, and an opening where a gate should be.

That's it for exteriors. Moving onto interiors, some first floor windowless rooms of office buildings have been made into storage rooms containing stacks of crates and boxes. I would like to add some sort of shelves on the walls, but I haven't gotten to that yet.

Storage room with no windows and two different types of crates stacked up along the walls and back.

While writing this post I decided that shelves should be easy to add, so here they are. Some walls have 2-4 shelves stacked vertically and held up by regularly spaced metal brackets. Here is an example of a storage room with 4 stacked shelves along three walls. That looks much more like a storage room to me. Now I just need to figure out what objects to add to the shelves. More crates/boxes?

Storage room containing various crates and empty shelves along three walls.

I've updated office swivel chairs to a model that has textures and is more interesting than the uniform black color of the previous chair model. In addition, I replaced some of the simple cube chairs with these chair models for desks that have computer monitors in houses.

A cubicle with the new office chair 3D model, complete with textures.

Office chair at an office desk and a computer monitor that's turned on.

I went back and made a second attempt at potted plants. The pots had looked good, but I wasn't able to get the alpha blending to work on the leaves. This time I switch to a second (more expensive) shader that has alpha testing and alpha blending enabled. Now the plant leaves are drawn properly. Pots come in a variety of different colors, and there are five different plant/leaf textures. One or two potted plants can be added to a living room, and one plant can be added to some other room types such as dining rooms.

A potted plant in the corner of a room. Plants come in various sizes, aspect ratios, pot colors, and leaf textures.

Now that bedrooms have dressers and nightstands, I can place smaller objects on top of these. What objects should I add? Well, I have lamps on some of the dressers and nightstands in the bedrooms of my real life house. Lamps are a good place to start.

A lamp has been placed on the nightstand to the left in this bedroom.

I haven't made the lamp a light source yet. Light should be partially transmitted through the lampshade, which isn't something I can currently do. I suppose if I wanted to attempt this, I would need two shadow maps, one pointed up and the other pointed down. ... Okay, I can't resist. I added those two light sources for lamps. There's no indirect lighting, and no transmission through the lampshade, but the shadows on the ceiling look too good not to enable this. I also managed to get the light to cast a faint upward unshadowed area to sort of simulate light passing through the lampshade.

A lamp placed in an otherwise dark room at night, with shadow maps, shining on the ceiling and floor.

Two lamps can be see turned on in adjacent rooms at night.

I think it would look better if the lampshade was lit, but I'm not sure how to actually do that. Use two different lamp models, one with an emissive lampshade for the lamps that are turned on? How about just setting the emissive color before drawing the lamp if it's turned on, and reset it after the draw? Yes, that last one seems to work. Here is a new lamp screenshot with an approximation to diffuse light transmission through the lampshade.

Now the lampshade is emissive when the lamp is turned on.

Monday, October 5, 2020

Mirror Reflections and Player Models Gone Wrong

This is just a short post to show off some of the interesting and amusing mistakes I made while working on the previous mirror reflection post. Well, they're not all mistakes, a few were just experiments I decided to do.

Here is a screenshot that's similar to what I saw when disabling (or, um, incorrectly implementing) the reflection operation. The mirror is an image of the player's view of the mirror itself. Since it's updated in realtime, each frame takes another image of the previous image, zoomed out a bit based on the camera distance from the mirror. This stacks up some number of reflection images on top of each other, which will converge to something like this when the player stops moving.

The original bug looked a bit different from this where the mirror was a smaller recursive zoomed in copy of the mirror itself where the mirror-in-mirror converged to a tiny point in the middle of the screen. Unfortunately, I never saved a screenshot of the original problem and I can't seem to get the code back into a state that looks like that. Like this.

Here is what happens when I make the same "mistake" but also draw the player model in the reflection image. Rather than the mirror, we see the inside of the player model's head, since that's where the "camera" is. It looks like someone stretched the skin from a man's head over a canvas and hung it on the wall like a picture. I have no idea what's up with the eyes.

Did you ever try to look at something on your face very closely in a mirror, and you lean in so close that the front of your face goes through the mirror's surface and you're looking through your head? Yeah, I hate it when that happens to me.

Yeah, I know, that's not realistic. You can't see through your face when looking closely into a mirror! In the real world, ... there's no back face culling. You'll see inside your head instead, like this:

If I move a bit closer so that my entire face is through the mirror plane, all I can see is the back of my head. Yeah, that's right. That's the inside surface of my hat. No brain in there!

Okay, what if I draw the player model even when reflections aren't enabled? Did you ever wonder what it would look like if you had only one eye? And it was inside the center of your head rather than on the surface? And your head was empty? Well, wonder no more, here is what it would look like:

That kind of looks like the inside view of an oversized rubber Halloween mask. Except there are no eye holes cut out. Is that how people feel when inside those big mascot costumes? I tried to remove the eyes so that you can see through the eye holes, but unfortunately the face model is a single mesh using a single texture. That's a shame, it could have made a fun gameplay mode to only allow the player to see through tiny eye holes. Who needs peripheral vision, right?

Friday, October 2, 2020

Building Mirror Reflections

This time my post is not about objects I've added to building interiors. Well, technically that's not true. I have added mirrors to office and house bathrooms, but most of the content isn't about mirror placement because that was a trivial task. This post is about how I implemented mirror reflections, which also required me to finally add a player model.

I started by copying parts of my existing water plane reflection code. This was all oriented in the Z (up) direction, while I needed mirrors oriented in X or Y to place on walls. That required changing all of my code for reflection matrices and the camera frustum to work with different reflection directions, but fortunately I only had to handle the axis aligned cases.

Then I had to deal with the mirror changing the winding direction of all polygons in the scene, which affects the front vs. back face culling tests. I had to hunt down various face direction tests in the building drawing code and invert them in the mirror reflection case. I also had to fix problems with polygon bias direction in some of the passes. At first I didn't quite understand what was going on and fixed it using trial-and-error to flip signs.

The next task was to avoid drawing the other side of the wall behind the mirror. Mirror reflections work by moving the camera to the other side of the mirror and negating the view direction. This effectively puts the reflection camera outside the bathroom looking in through the back side of the mirror. But there's a wall behind the mirror, so the camera will be looking at the other side of the wall! I had to add a custom clip plane at the mirror surface to remove everything behind it, which would have been in front of the back of the mirror for the reflected camera.

Finally, I had to handle the case where multiple mirrors were visible in the same office building bathroom. This produced a reflection of the opposite mirror, which didn't work correctly because the opposite mirror wasn't drawn as it was outside of the player's view frustum. After various failed attempts, I decided to simply limit bathrooms to having a single mirror when reflections were enabled. That's good enough for now.

After all these steps (and more), I finally had it working:

Realtime reflection in a mirror in the men's room.

Unfortunately, it was pretty slow. My first implementation nearly doubled the frame time when a mirror was visible. Fixing this required some combination of selective drawing, object occlusion culling, screen space stencil testing, and visible surface determination. At first I drew the reflection at half screen resolution, which helped. That's why you can see a bit of blurriness if you fullscreen these images.

One of the easiest optimizations was to check if the mirror was in a windowless room, and if so, only draw the building the player is in. None of the other buildings can be seen (unless a window is visible across the hallway, in the reflection of the doorway). Some of the other outdoor scene content can similarly be ignored. This was easy to do, but didn't help very much because I was limited by the fragment shader lighting calculations rather than the vertex shader or OpenGL driver overhead.

Next, I had to determine when a mirror was visible to the player. If it's not visible then there's no reason to create the reflection image. First, it must be within the camera's view frustum. Then I added a check if the player was actually inside the room containing the mirror. That almost worked, except for the case where the player was in the adjacent hallway looking in through an open door. So I included the connected hallway in the set of rooms for which the mirror needs to be drawn. But the hallway could run the entire length of the building, while the mirror is only visible for a small subset of the hall. I added a check for distance to the room/doorway based on the room size and hallway width. That mostly worked, but there were still a few situations when it either drew the mirror unnecessarily, or failed to draw it when some part was visible. My final solution was to trace a number of horizontal rays from the camera to points on the mirror's surface and skip drawing it only if all rays hit a building interior wall. That solution worked pretty well, so I left it at that.

The last optimization was to render only the interior part of the mirror rather than the entire screen. When the player is relatively far from the mirror, this makes a considerable difference. The mirror only occupies a small fraction of the pixels in the images above and below. I used a stencil test for this. The mirror was drawn in the stencil buffer, and the downstream room draw calls all tested the stencil buffer for each pixel/fragment. That optimization was surprisingly simple and effective compared to the ray intersection optimization. With that change in place, I was able to go back to rendering the reflection at full screen resolution.

I also finally added a model for the player. I used whatever human person model is specified first in the config text file. It happens to be the model of an old man. If you look closely, he (we the player?) even casts a shadow on the wall behind him. The player now always casts a proper shadow, even if not in a room with a mirror. The legs of the shadows are even animated when the player walks.

A reflection of the player model in a bathroom mirror that also casts a shadow. Oops, I think this is the women's room because there are no urinals!

But really the player model can be anything specified in the config file. For example, it can be a car. Here I had to fly up toward the ceiling to show off my new "player" model because it's so low to the ground.

The player as a car, reflected in the bathroom mirror. Who says a car can't use the bathroom?

What other fun model can I use? Let me see. How about this one. Can you guess what it is from only its shadow cast on the bathroom floor?

The player's shadow. What do you suppose the player is?

I'm sure you guessed it was a toilet. What else were you expecting, right? After all, we are in a bathroom.

That's okay, I'm beautiful on the inside ... as long as you flush me first.

Next, I added mirrors to bathrooms in houses. This was more difficult because these bathrooms usually have windows that can be seen in the mirror. That means I have to draw the outdoor part of the scene with terrain, vegetation, exteriors of other buildings, etc. This was challenging because I was creating the reflection texture from within the building drawing code by clearing the depth and color buffers before drawing buildings. Some of the outdoor objects that had previously been drawn into the frame buffer were cleared in the process. It wasn't as easy as drawing the reflection to a different buffer (FBO or PBO) because I needed a color buffer, depth buffer, and stencil buffer. I also couldn't easily move the reflection creation to somewhere else in the drawing control flow because it depended on the room lights setup code at the top of the draw function. So far I haven't come up with a good solution to this problem.

In addition, my logic to swap front vs. back faces interfered with the multiple rendering passes used to cut windows and doors into exterior walls, so I had to go back and rework that. Eventually I was able to get some of this to work. Here is a screenshot of a small mirror above the sink in a house bathroom. This one was drawn at full screen resolution.

Small mirror above the bathroom sink. It's on a medicine cabinet and spaced somewhat away from the wall, though it's hard to tell from this angle.

I have 3DWorld drawing window cutouts of the current building so that the exteriors and windows of other buildings can be seen through them in mirror reflections. I don't have the interiors of other buildings or terrain, vegetation, or roads working yet. I'm not sure how to do that in a clean and efficient way. Moving the reflection texture creation out of the building drawing loop and higher in the control flow would partially fix this, but it may be more complexity than I'm willing to add at this time. For now we'll have to avoid looking into the mirror in such a way that an exterior window can be seen.

Also note that bathroom mirrors are only added to interior walls to avoid having them overlap windows cut into exterior walls. I could check for window intersections like I do with some other room objects, but I believe most of them would intersect. This probably wouldn't be worth the trouble. Maybe I should also avoid putting mirrors on walls opposite exterior walls to work around the other problems.