3DWorld's procedural office buildings already have some special purpose rooms on the ground floor. There are storage rooms with shelves along the walls, utility rooms with furnaces, water heaters and sinks, and server rooms with computer servers. The next room I wanted to add was a security room. And what does that room contain? A desk and walls covered with security monitors, which use the same 3D model as TVs and computer monitors.
But what do we display on the monitors? The most appropriate content is security camera video feeds, which means I also need to add security cameras to the building as well. The best places to add these are the two ends of primary hallways on each floor. This placement covers the building entrances, stairs, elevators, and secondary hallways to the offices and other rooms. These cameras allow the player to watch people and zombies walk around the building in realtime.
I started by adding monitors across all four walls of the room, wherever there was space. They're currently stacked two high. Right now they have the feet/stand attached, which makes them look a bit odd, but I'll fix that later. I also put a breaker box on the wall next to do the door so that the player can turn the power off to blocks of rooms and affect the state of lights, cameras, and monitors. This made debugging the update logic easier as the player had direct control over everything.
After placing the monitors and setting up the screen drawing code, the first test used the same camera for every monitor. Which camera? The one in the player's head that the world is normally drawn from. I was expecting each monitor to show a copy of the player's view, but instead I got the result below. The problem is that I'm reusing the mirror reflection code to draw the monitor images, and this code enables the player model. In addition, the front vs. back face culling was set up incorrectly, so the view on the monitors is the inside of the player model's head. Interesting, but not what I expected.
This is what you see when the "camera" is inside the player model's head and the front vs. back face culling is wrong. There are 36 monitors along the walls of this security room. |
With that fixed, I get the expected recursive view through the player's eyes. Each monitor shows the set of monitors inside it, for a picture inside a picture inside a picture... Except that the top row is backwards because I've inverted the camera direction for cameras at the other end of each hallway. Anyway, so far, so good. It appears to be working. This image is only for debugging purposes.
Recursive camera view where the camera is in the player's head, looking forward in the bottom row and backwards in the top row. |
At this point I have the cameras all set up correctly with the location and view direction of the 3D camera object. Each camera is on the ceiling tilted downward at a 10 degree angle. This gives a relatively good view of the end of the main hallway and, in most cases, the connector hallways, stairs, and elevators. This is typically what is monitored in office buildings as it includes the main public spaces.
Ground floor hallways have the lobby reception desks, but upper floor hallways all look the same. The elevator and stairs floor numbers are only sometimes visible. I needed a way for the player to tell which monitors showed which floors. My solution was to add a system for on-screen text drawn over the main image texture and shifted slightly closer to the camera to be in front of the picture. This uses the same text drawing system I have for signs and book titles. The text string consists of the room name, floor number, and direction ("E", "W", "N", and "S"). Currently all camera rooms are named "Hall" in office buildings. Technically, the ground floor is the lobby.
Camera images are updated by rendering the building interior to a texture each update frame. This is too expensive to perform each frame for dozens of visible monitors. My solution is to update only one image per frame. The camera chosen for update in a given frame is the one with the oldest (least recently updated) image across all monitors visible to the player. This way cameras will be updated round-robin. For example, if there are 10 monitors visible, each one will be updated once every 10 frames. This is good enough to get interactive framerates on the monitors. When the player gets close to a monitor to view the image in higher resolution, there will be fewer monitors visible in their periphery, which will make the visible monitor(s) update more frequently. I also reduced camera resolution from the default screen resolution (I use 1920x1024) to 1024x768 to improve framerate. Monitor images emit light and can be seen in the dark.
This system allows the player to watch people, zombies, and animals move in the hallways in realtime. I expect this to help the player plan to avoid zombies in gameplay mode by determining which floors are safe vs. dangerous. This is important when the player plans to exit the elevator on a particular floor and may become trapped by a nearby zombie. However, the side hallways and room interiors aren't visible to the cameras, so there's always some risk.
Security monitors showing a person walking in the second floor west side hallway (top center). The east side hallway is shown below, and hallways on other floors are to the sides. |
The player has some additional interactions. Monitors can be turned on
and off by clicking on them with the action/interact key. Cameras and monitors can both be stolen by the player. Any monitor showing a camera that's
powered off or stolen displays an animated static texture created from
random white noise. Here's an example where I've removed the two cameras at the ends of the ground floor hallway.
Security monitors show static when their cameras have been stolen by the player or powered off with a circuit breaker. |
These monitors look a bit wrong with the metal legs at the bottom. Stands are generally removed for monitors that are mounted to walls. Fortunately, the stand and logo are drawn with a separate material. I can reuse the material selection system that I implemented for use with rotating fan and helicopter blades to disable drawing of certain materials for hanging monitors. Now it looks like this.
Security monitors with the stand at the bottom removed. The logo is also gone because it's part of the same material. |
Note that these rooms are darker than they should be because the indirect lighting computation was broken at some point, likely when I was working on swimming pools for the previous post. I eventually did realize this and fixed it (after hours of effort). But I didn't want to go back and recreate these screenshots, especially the ones resulting from bugs that had been fixed by now.
Cameras are created from black and gray untextured metal materials. They had low contrast against the mostly grayscale colors used for office building walls and ceilings. This was especially true at the ends of long hallways with the broken indirect lighting, where the ceiling lights didn't reach this far. I added a red light to the front of each camera that flashes on and off once per second. The light is emissive when on and can always be seen, even in complete darkness. This way the player can notice the flashing lights and know they're being watched. I was able to avoid sending new vertex data to the GPU each frame by toggling the material emissive field on and off for all cameras in the building every half second.
Here's a video I recorded where I enter the security room, view people walking on the monitors, and steal some cameras. This was created before I removed the monitor stands and fixed the indirect lighting.
There was one other addition I made. After experimenting with this a bit, I wanted an easy way to test the system that handled offline/unpowered cameras and monitors. It's inconvenient when the player has to walk long distances around the building to remove the cameras. So I added a breaker box on the wall by the door to allow the player easy access to controls that disabled cameras. However, this turned out to not be as useful as I had imagined because all of the primary hallways across floors happened to be connected to the same circuit breaker. This meant I could turn all of the cameras off, but I couldn't control them individually.
Another problem was that the original circuit breaker box generator only added labels for the elevator and parking garage breakers. If I happened to toggle the breaker associated with the security room, this would turn every monitor off. I would then need to manually turn each one back on after flipping the breaker back. This made testing more frustrating. I had to label the security room breaker. But if I was going to write the code to figure this out and generate a custom label, I may as well label every breaker with the room(s) it controls. But what about breakers that affect multiple rooms? My solution was to assign a priority to each room type, and label the breaker with the highest priority room type it controls. For example, the room type "office" is too generic to be shown on every breaker. Obviously, the "security" room should be assigned the highest priority based on the original problem I'm trying to solve.
Breaker panel with all breakers labeled with the rooms/functions they control. Sorry about the shadow on the right side labels! |
That's all for this update. I may go back and add cameras to other rooms, or possibly houses. I'll have to think about this later.