I added skyways to 3DWorld's procedural cities a few posts ago. These included horizontal moving walkways that the player could use to get around more quickly. This got me thinking that I should add escalators, since I already had stairs and elevators. At first I considered using escalators to replace the short sets of stairs that lead from walkways to skyways above them, but these are uncommon and don't have much space to work with.
Escalators
The first question was, where do I put escalators? I want them to be placed inside procedural buildings somewhere. I already have stairs and elevators connecting the floors of my buildings together. Escalators need more space, and are ideal for rooms more than one floor tall. How about placing them in tall retail areas? There's plenty of open space, both horizontally and vertically. I decided to add a pair of escalators going in opposite directions next to each other along the center line of the long dimension of the room. I start by placing them in the center of the room and then shift them alternately to either side until I find an open place between existing stairs, elevators, and exterior doors.
Originally, the escalator placement failed some of the time because the
stairs and elevators were spaced out in the center of the primary
hallway in the office building floors above the retail room. But now
I've moved some of the elevators to the sides of the hallway, which
frees up more space for escalators in the smaller buildings. You can see
one of these side elevators in the screenshot below.
Here's an early version of a working escalator prototype. The bottom floor/steps part is animated in my attempt to recreate the movement pattern of escalator stairs. The player can ride it up and down, though there's no floor connected at the top. All you can do is fall off the high end. Walking up and down is much faster than standing and letting the escalator move you. Objects such as balls and animals collide with escalators as well, though they can't actually move with the escalator.
Glass Floors
The next question to decide was what to put at the top of escalators. I wanted to add another level to the retail section, something different than standard tile floor. I like working with reflections, so I added a transparent glass floor. Maybe this isn't very realistic for multi-level public interior spaces where one person can look up at someone above them. But I had already added this before someone pointed out this problem. Each floor is currently a single rectangle. In the future, I may add a second shape to form an "L". As I expected, the combination of transparency and reflectivity made this extra challenging.
First, the transparency: In OpenGL (and other graphics APIs), transparent objects must be drawn after the opaque objects for them to properly alpha blend with geometry drawn behind them. The problem is that the glass floor is next to windows that lead outside the building. This means that exterior objects such as the terrain, grass, trees, roads, etc. must be drawn before the glass floor. This is a problem because buildings are drawn first, and interiors use a different lighting system from exteriors. I had to draw the glass floors in a final pass after everything else in the scene was drawn. I didn't want the overhead of setting up the interior lighting pipeline a second time in one frame, so I changed the lighting system to use a custom ambient value for each face of the glass. This technically works because it allows the glass to be lit from both the interior lights and the outside sun, from either the top or the bottom side. It avoids the unrealistic dark surface on the bottom "unlit" side of the glass. The only downside is that the floor doesn't receive shadows from other objects. I think this looks acceptable, especially when reflections are added.
Reflections were the next challenge. I only needed to make the top surface reflective, so that the reflection was only enabled when the player was standing on top of the glass floor. 3DWorld doesn't write a buffer that contains normals that can be used for screen space reflections, so I had to render the scene a second time from a reflected camera. This works the same way as bathroom mirrors and swimming pool water surfaces, except it's an entire floor of a large room filled with tons of objects. Compare this to swimming pool rooms and flooded basements that have sparse object placement, and mirrors that have a small reflected region. On top of this, the exterior is visible through windows and must be drawn as well. It was quite difficult to get fast reflections that didn't halve the framerate. (Keep in mind that I'm targeting older computers for 3DWorld, so my goal is 120+ FPS on my gaming PC.) I had to rewrite parts of the object occlusion culling system and implement horizontal clipping planes for drawing.
Finally, it was time to add objects to the upper glass floor. I started by adding railings along the open end to keep the player and AI people from falling off. Then I added additional rows of "shelf rack" objects on the upper floor above the rows on the lower floor where there was space. Any shelf racks that partially fit were cut to shorter lengths as long as the clipped rack was above a certain minimum length. I made sure to add extra padding around the end of the escalator and any openings of stairs and elevators that reached the second floor. This works, though the spaces can be tight in some cases.
Here is what the escalators and glass floor looked like after these changes.
A pair of moving escalators in the retail area of a building leading up to a glass partial floor. |
The escalator has upper and lower straight ends and a 45 degree polygon in the middle. I didn't have the patience to try and write the code to create proper curved sides like I see in most real world escalators. These shapes are much easier to write collision checks for anyway. Each escalator has a vertical pillar at the high end to help support it and the glass floor attached to it. I thought this would give them a more interesting look than filling in the area under the escalator with material.
Side view of the same pair of escalators. Maybe they need more depth to the sloped part? From this angle they look like a pair of high heeled shoes! |
Here you can see some building AI people managed to make it up the escalator to this empty glass floor. It's easier to test reflections of dynamic objects without the shelf racks in the way. (Well, that's true, but in reality I've added these screenshots out of order.) I actually started by removing the transparency effect and setting the Fresnel term to 1.0 to turn these floors into a perfect mirror. That made it more obvious when something was missing or otherwise wrong with the reflection.
A glass floor at the top of the escalators with a railing and not much else to do. The reflections of the people and the interior of this room are visible in the glass. |
It looks questionable when the escalator is in the center of a large building and half the building footprint is a single unsupported glass floor. That must be some pretty strong glass! So for the larger areas, I added vertical columns that pass from the floor below, through the glass, and into the ceiling. Technically these already existed on the floor below. I then added horizontal steel beams under the glass connecting the pillars with the exterior walls and each other. I suppose it looks more structurally stable this way. Here is what this looks like before objects were added to the upper floor.
A larger reflective glass floor area with an elevator through it, plus vertical support columns and horizontal metal support beams. |
Note that this floor has an elevator going through it. Two elevators in fact, though the one on the left doesn't have enough clearance from the escalator to have a door on that side. Only the right side elevator can access the glass floor. The glass is clipped out in the elevator shaft so that you don't pass through it when riding in the elevator. It should be possible for enclosed stairs to pass through the glass floor, though I've never seen this happen in a building I've visited. I believe the reason is that stairs are placed in the center of the hallway, the escalator is placed next to them, and the glass floor is always the smaller half of the room area (which excludes the stairs).
And here is the same area with shelf racks added. You can see the reflections of the racks and their contained objects on the floor.
The same reflective glass floor as above, but with racks of shelves added on top to give people a reason to come up here. |
AI People
Did I say the glass floor transparency and reflections were challenging?
They were easy compared to updating the AI logic. It actually wasn't that bad to
make the normal building people use escalators. They work like stairs,
except they must select the correct "up" or "down" escalator based on
the direction they're headed. People walk up and down escalators rather
than standing and riding them because it was easier than trying to blend
in an idle animation. I might attempt the standing/idle version of escalators sometime later.
Now that I have people getting to these floors, I have to give them a destination so that they don't simply stand there at the top of the escalator. Some random spot between the racks should work. I just need to make sure they stay over the glass area and don't walk out over the rest of the retail area where they float in the air. The problem with the existing logic is that it assumes each floor covers the entire horizontal extents of the room. I had to add logic to clip the walkable area to the bounds of the glass floor to many places. But then I realized the real bug was that people didn't consider the railing a collider, and making them avoid the railing fixed most of the remaining problems.
The final step was to get the zombie AI to behave itself while chasing the player around the escalators and glass floors. Two of the more difficult primary objectives were to (a) chase the player to any reachable area, and (b) not get stuck around the escalators. This took me many, many iterations over the course of more than a week. There were just so many special cases and rare failures to deal with:
- What if the player goes up the down escalator? Do we follow them going the wrong direction, or take the correct escalator and try to catch them up top? And if the player stops on the escalator, do we go up to the glass floor on the up escalator, then go down on the down escalator after them? Or wait at the bottom for them instead?
- What if another zombie is going the wrong way on the escalator we're on? What if a zombie is stopped at the top or bottom of our escalator? Do we stay (walk in place) on the escalator waiting for them to move? Push them to the side? Clip through them?
- What if the player no-clips/flies (aka cheats) to a spot above the retail area that's not over the glass floor? Do we go to the lower floor and stand under them? Clip through the railing and walk on air to get to them? Go to the closest reachable point to them on the upper floor? Ignore them and go about our business of selecting random destinations?
- What if there are stairs through or adjacent to the glass floor that don't connect to it, or we don't have a path to them, we're on the stairs, and the player is on the glass floor? Zombies really wanted to clip through the stairs walls in that case. (Technically, if the stairs pass through the floor, then they can be on the floor while also on the stairs.)
- What if someone pushed a zombie onto an escalator that it wasn't planning to use? Or off of an escalator? For stairs I just snap the person to the nearest point outside the stairs, but for escalators that point may not be over the glass floor.
In the end I just had to keep adding special cases to handle situations like this, test, and iterate until everything was working. Every time I fixed one problem I encountered another. In the process I had to add missing error checks, convert fatal errors to debug printouts, add more debug visualizations, and things like that. I suppose those changes are generally useful. It mostly works now, though it's not perfect. There are two minor issues that I haven't solved and have flagged as accepted behavior.
Sometimes a zombie will get pushed by another zombie into that spot exactly between the two escalators. In this case the zombie effectively gets trapped because it intersects both escalators at the same time and can't leave that spot without clipping through at least one escalator. So it just stands there and looks at the player. I think this is acceptable though because it can still attack the player when using either escalator. They're effectively camping the escalators. It's actually worse for the player because it makes the escalators unusable and may trap the player on the upper floor if there is no other exit. On the plus side, I don't believe it's possible for more than one zombie to be stuck in this location at the same time.
The second problem is when a zombie exits the stairwell onto the ground floor of the retail room, sees the player on the glass floor, and immediately re-enters the stairwell. It's nonfatal because they'll eventually reach the floor above or below, then make their way back to the retail room to chase the player. This behavior seems to be random and somewhat rare. I'm not sure what causes it. It's difficult to debug because I don't know until after I see them enter the stairs, so I can't query the system for their state before they made that decision. I attempted to fix this multiple times. Each time I thought the fix worked because I didn't catch a zombie doing this, but I saw it happen again later when I was trying to debug something else.
Here's a final video showing the player and AIs using escalators and walking on the reflective glass floor. Maybe later I'll record a video of zombies in the retail room.
At this point I'm calling escalators and glass floors "done enough". I may get back to them later. Next up: glass elevators to city elevated walkways. I already have elevators, walkways, and the drawing code for glass surfaces, so why not?
Nice work on the escalators! I'm sure you'll get shopping malls at some point, where they will be a critical asset. Underground subways and airports are the other places I've seen escalators.
ReplyDeleteThe glass is great as a technical achievement, but I'm not sure glass floors are the right application. Especially if you're going for realism, no one wearing a dress would shop on the second story.
Thanks! I did think about adding shopping malls. The problem is that I need a large area for this, and buildings are constrained to fit inside terrain tiles (or only go outside by a fixed amount) due to the shadow mapping and object placement systems. I was thinking that I could put shopping malls underground where the space is effectively unlimited/unbounded. Maybe they can have skylights that are on/in cities between buildings.
DeleteThe glass floors have already been added. I didn't think about the privacy concerns until you brought it up in my YouTube post. At least I don't have any women wearing dresses in 3DWorld (yet).