Back to the Future

Thu, Aug 3rd, 2000 | 9:00pm

I felt like writing some of my predictions for what the most important steps in 3D FPS engines are. Today's blathering is about deformable terrain.

As computing power increases and AI doesn't, more and more processor speed will be available for other nifty things. Deformable terrain would require the engine to be able to, on the fly in real time, break up faces into smaller faces, move vertexes, create new faces, and choose/apply a texture properly to those new faces. As far as the bsp engine is concerned, it would also have to deal with visibility change issues.

Let's look at this through several examples, the first and most popular being the rocket hitting a wall. The wall would have to have a large chunk blasted out of it, and that chunk split into small and large pieces of debris which would go flying. The wall would go from being two textured faces to being a great many faces, as well as a large number of unique entities, each of which was generated by the engine. The engine would have to come up with numbers for depth and radius of the hole, chunk size, mass of each chunk generated, shape of each chunk, direction each chunk would be thrown, and whether or not to consider a chunk "vaporized," since some portion of the wall is sure to be reduced to dust. Some stock rubble texture would have to be applied to the previously unseen surfaces - on the inside of the hole and on the inward sides of the chunks. There would also have to be rather aggressive tracking of "wounded" walls - if at any time a part of the wall is no longer connected to the rest of the wall in any way, it has to be made a moving entity and dropped or thrown or something. This is to prevent the player from shooting out the top and bottom of a pillar and having the midsection floating in mid-air.

How would the game know all this? My solution would be shaders: now almost every surface would need a shader, in order to specify it's parameters for destructibility. Strength (glass, paper mache, plaster, concrete, rock, steel), deformation style (chunks, splinters, shrapnel, denting/bending), weight (for determining shrapnel masses) and what rubble texture to use. There could also be template material types (so the shader can simply say "material starcrete1" instead of every texture in the starcrete series having to recopy the same information).

Second example: what happens when you blast all the way through a wall? What happens if there isn't anything on the other side of the wall? What happens if the other wall has a different texture with different material? Etc? The map file would have to store more information than just the spaces that make up the map - it would have to store info on the brushes between the spaces. Blasting from one room made of concrete into another room of something else would tunnel through a wall that would have to change from one material to another at some point, and the .bsp would have to know where. What if you aren't supposed to be able to blast through certain walls, for gameflow reasons? The mapper would have to put a layer of steel or some non-breakable material between the two walls - a brush of steel that wouldn't actually be a part of the world but what's position would be recorded.

This could quickly get tedious - a mapper would have to build an entire map with layered walls. It would be easier to specify a certain maximum depth in the shader that a surface could be blasted through before not being able to break through any farther. Perhaps for cosmetic reasons two depths - a density depth and a stop depth. Once the player breaks past the density depth, it becomes much harder to break away the wall, but still possible, until you reach the stop depth. This is to keep craters and huge gouges from having flat bottoms.

Another way would be to simply make it a function of the depth of the brush - a 64 unit thick wall between rooms would have a 32-unit thick brush on one side and another on the other, with their density depths being about halfway between the midpoint and the surface. This would put the stop depth at the same point, which theoretically should allow the wall to be broken through but with lots of work. This wouldn't require the compiler to store information about the void either - the depth of the brush away from the surface along its normal could be stored as a surface val with a few extra bits ala quake2, with the density depth being maybe 2/3 that by default. Walls that cannot be broken through would have a thin bit of void between them, and walls that can be broken through easily would overlap about 50%.

Third example is stuff that breaks in odd ways. You can't shoot off a chunk of a metal pole (not a thick one), and wood doesn't break into hefty pieces. The simple way would be to simply choose a fragment type as another surface parameter: chunk (a shape with even proportions and lots of rocky angles and cracks), splinter (a chunk but long and thin), fragment (a very sharp piece without crumbles and waves - for glass), or metal (doesn't break - bends and deforms slightly). Knowing Carmack, this is the path he'll choose - it works fine for what it will initially be used for (insert very bitter thoughts about curve-lod-cracks and soddy useless fog here). The elegant method would be to define everything with variables of material density and composition (ranging from very rough - like a sandstone wall - to very smooth - like metal or glass). It could then extrapolate the roughness, size, and shape of each chunk from these values. Concrete would be dense and sort of rough, dirt would be very rough and very light, glass would be not that dense but 100% smooth, etc. Some other variable to define grain strength, for wood or other splintery materials, would also be required, but I haven't quite figured out how it might operate. It would need some kind of vector to point the grain - defaulting to positive x would require all wood or grained textures be saved pointing that way, then rotated to whatever direction is proper by the map maker.

Here's the really exciting bit: it can be used on bad guys, too. :) The polies of a model can theoretically be split and the spaces filled in with more polies with a gory texture on them. For animation, the new vertices should already move fine - full collapsible-mesh model LOD should provide the information for the surface deformations, and new polies on the inside should just stretch across from one side to the other. Imagine blowing a person's side out, or taking off an arm, or cutting them in half. Or gibbing them and seeing them actually tear apart and having one arm go this way, an arm, bit of rib, and head all in one piece go that way ...

Problem with this is, how does the game know which bit falls off and which bit keeps going? And what if you blow someone's gun arm off - how would the game know he couldn't still shoot? If you blow off both their legs will they still come floating at you?

I'll cover that topic tomorrow with real-time enemy animation.