Sunday, October 23, 2016

The Boyscouts



Back in the day, I wasn’t a very good pathfinder at the “Jagers” (our local cheap variant of the Scouts). Map reading? Fooling around (and drinking beer or rolling cigarettes on a later age) you mean. Usually we took the third turn left instead of right, got lost, and made it a six hour walk instead of four. But much fun we had, sneaking through ditches and backyards, getting chased by cows or talking about boobs in the woods. And always bringing back a surprise for mom… mud-caked-cloth.

I wish our kids will join the Scouts or alikes one day, instead of wasting all their time on Youtube. But it seems the oldest girl is more into girl things, like flying on unicorns. We’ll see. Until then, my pathfinding skills are used on Tower22 A.I.

Pretty much every game with foes + a world more complex than a simple side-scroller, requires pathfinding. The word is self-explanatory, but still I’d like to point out there is a strict difference between deciding where to go, and figuring out how to get there. Pathfinding techniques usually focus on the latter, although the decision-part is maybe at least as important in order to make your foes smart, tactical or humanlike. Anyhow, pathfinding usually consists of path-data and a (fast) algorithm that calculates the shortest or “best-quality” path between point A and B. Like configuring your car navigator.
Now the real question is; man or woman?



I won’t dive into algorithms such as A* (yes, A-star), a very common pathfinding algorithm. Let’s just chat about what I did last summer, last week I mean; making a “Navigation Mesh” for the playable demo world.

Any pathfinding algorithm will need data to work with. Like the Boyscouts had their map (hm, map?). In a 3D game, we have world-geometry, but it’s too complex to directly use. World Geometry is basically a bunch of polygons, which could be anything really. Road, pavement, but also walls, roofs, pipes, windows, wires, chimneys, lava-pits, horse manure, and so on. Polygons too small, turned upside down, or made of nuclear acids aren’t suitable for walking. They just litter our algorithm with extra load. Neither do decorative polygons, somewhere in a far background. What you would need is an extra “yesYouCanWalkOnit!” property or something… letting the artist mark “floor” polygons you can walk on, in the editor.

That still stinks though. Games tend to tessellate their geometry in smaller chunks. A soccer field might be made of 100 x 50 quads, while just a single rectangle is enough for pathfinding purposes maybe. Pathfinding algorithms are pretty heavy shit, in calculation terms. Less connections / cells / polygons / grid-points = faster results. So you really want to filter our noise. When the Boyscouts are reading their map (IF they are reading their map…), they don’t want to know the location of each manhole, lamppost, bench, trashbin, dogturd, or liquor store… I think.

What you want, is a simplified version of the world, the (walkable) floor shaped out of as little polygons as possible. Engines like Unreal offer tools to create those meshes for you… How does that work?
T22 demo floor has about 21.000 triangles. The simplified mesh about 1.500. Notice the NavMesh doesn't have to follow the exact stairs. And also notice not every floor polygon is necessarily walkable. Ceiling too low, obstacles placed, or the NPC jusn't not having any business there.

NavigationMesh generator: Auto versus Handmade
First of all, they define a boundary-box where to create that navigation mesh. Anything outside that box is skipped right away. Perfect to get rid of backgrounds or stuff that might be walkable, but isn’t always useful (like roofs on houses). Next, if we forget about Spiderman for a second, you could help a hand by filtering out any polygon that is NOT facing upwards (thus potential ceilings / walls). Then maybe have a look at its material. If it says “boiling tar”, you probably want to skip it as well.

Still doesn’t mean those left-over polygons are actually walkable though. If your monster weighs 400 kg, chances are he may not fit through a normal door portal, unless he’s made out of jelly. Basically the floor polygons need to shrink a bit, away from the walls, and also testing the height. If your guy is 2 meters tall and can’t dug, any polygon with a low ceiling will definitely suck.

I’m not sure if those auto-generate algorithms are even using the existing (floor) geometry like that though. I’m more thinking in terms of floodfilling; make a (3D) grid inside an artist defined bounding box. Then click a piece of floor (“inject”) has is walkable, and check all its neighbour cells:
·         Put a cylinder there. Dimensions are based on NPC radius / height parameters.
·         Check what surrounding polygons it intersects?
o   Does it intersect “floor” polygons (upwards facing)? Good.
o   Does it intersect non-“floor” polygons (ceil, wall, obstacles)? Not good.
·         If passed, repeat the check for neighbours

That’s the easy part. More tricky is to generate an actual, optimized, mesh out of those cells, which basically represent a voxelized version of your map-floor. And no, I didn’t figure out how to do that (yet).


Not being blessed with grandiose math skills, and seeing some other possible issues, I decided to go for a good old hand-made NavigationMesh instead. Issues? Well, what if we do have Spiderman? Tower22 dudes may not necessarily stick to the floor. Hell, some may even cheat and fly through walls, or “warp” to certain spots. Second issue is that it’s a bit hard to define a bounding box and generate a mesh within that area. Tower22 has a roaming world, the navigationMesh is much bigger than the actual loaded parts of the world. Unless you generate multiple smaller meshes, and weld them together. But again, it introduces some tricky bits.

And there is something else. In previous NavigationMeshes (made manually for the older engine), I had some more information stored in the mesh. Like the type of floor. Pedestrians can walk the highway for sure, but they should avoid it as much as possible. To put it more abstract, polygons need some sort of QualityRating, which is relative to its target audience. Pigs prefer mud, cars asphalt, and Kanye West Gayfish people water.



Battlefield
I can still hear you thinking, an auto-generated mesh could do that as well right? Right, but here is yet another excuse; storing Battle-Data in the NavMesh. Now the irony is that Tower22 dudes don’t fire machine guns, toss grenades over walls, and run into cover. So I could do myself a favour and NOT bother all of this. But it’s just to cool to not implement, and actually it does give some interesting A.I. capabilities to even dumb guys like my T22 scum.

Like pointed out at the top, there is pathfinding and decision making. You can give the Boy-Scouts a map, but without a clear goal, they still don’t know what to do. Get back home, go to the liquor store, find a bench and smoke weed, whatever. Practical, humanlike tasks. Sims with blatter problems will look for toilets. Soldiers under fire will look for cover. Or “assault-spots” with sight on the target, preferably still as much covered as possible. Tower22 monsters will… I don’t know what monsters do. Play billiards, read the newspaper, find Boy-Scouts to eat them, I don’t know.

Anyhow, again just a map doesn’t help, other than you could have objects with a special tag, like “isFood, isMedkit, isToilet, isBed, …”. But to make your NPC’s feel natural, they need some more advanced tasks, requiring knowledge of their surroundings. One common way is to provide (artist-placed) Info-Nodes. In Tower22, I can place nodes and tell what we can do here. Restroom, kitchen, workplace, et cetera. Then NPC’s can search for such nodes based on their needs, a certain range, randomness, or a pre-programmed schedule.
Rather than just randomly ghouling around, I made a bunch of "interesting locations" for my monstrous friends. Depending on the context, they can eventually search more specfically, filtering out nodes based on groups, required skills or type.



Nice & Simple, but also predictable. If you pre-define cover/assault/sniper nodes, you will know where the Bots will hide or go after a few rounds. Unless you place many, many nodes.

Now here is something the makers of Killzone did in their world, creating a somewhat more dynamic solution. A lot of nodes are placed, and each node measures global “sight” distances in radial segments. So you can quickly tell NodeX has proper sight on the North, and is covered from the East. By measuring on both gun and ballsac height, you can also tell if your lower body is covered yes or no. So if we know the enemie(s) are somewhere North, and you’re a fanatic, you’ll search for nodes with sight on the north, but coverage from other (potential threat) directions as much as possible.

 Based on the node data, yellow-badguy distance is larger than we can see from there, meaning we can't him, nor can he hit us. Be aware the data is somewhat global/inaccurate though (just 8 distances stored here). More slices provides better data, but also increases memory and pathfinding complexity.



So I figured, why not automatically generating such a node at each center- and/or corner of the NavigationMesh? Should offer a rich set of BattleData. And not just that, it also provides tactical pathfinding information –and now it gets interesting for T22!. If you are busy saving private Ryan, you should know to get off the beaches ASAP, as well as to stay out of lines of fire as much as possible. While running a (A*) pathfinding algorithm, you can check your visibility on each node, and make a balance between shortest / most covered route. If you plan to flank your enemy, you’ll need a path that is invisible for your primary target, and finally offers sight on its flank, at a certain preferred distance. If you're a Ninja, you may prefer the shady route. If you store “lightFlux” in your nodes, and also avoid open-spaces as much as possible, you’ll be picking a path that is not necessarily the shortest, but gives you stealth advantages.
 
So… what’s the problem with auto-generated meshes then? The lack of tessellation. Yeah, first I said NavMeshes should have as little polygons as possible –which is still true. But at “tactical” spots, where light/cover/sight varies, you want additional polygons so you can quickly hop between a wall(cover) or window(fire). T-junctions, windows, doors, spots with lamps – all interesting places that may need a few more polygons to get more accurate BattleData about your surroundings. Or if your NPC likes to hug walls, he can follow polygons at the corridor sides.
We placed two "Cover" polygons just around the corner. An (auto) optimized NaviMesh wouldn't have those.


So, summing that up, I decided to just manually make the NavMesh. Which sucks, but doesn’t take many hours either. It’s doable, unless you have “Just Cause” sized levels. To help myself, I made an exporter in the Map Editor that filters out (potential) floor polygons only, giving me a background to work on. The NavMesh itself is just a 3D model, and I’ll be using the polygon names to tell what they are: Floor, Stairs, LeapOverWall, Water, GhostCheatingThroughWall, and so on. Then when importing the mesh, additional BattleData can be generated. Its nodes would be placed on NavMesh polygon centres and corners, giving a pretty detailed datagrid –but only dense at interesting points. The Boyscouts would be proud on me.

Sunday, October 2, 2016

Physically Based Headache

A long time ago I used to write much shorter posts, reporting whatever I did that week before on Tower22. Usually about some new shader, which are fairly quick to implement, and generate nice screenshots to share. Especially when "completely awesome" graphics with some fancy shader technique weren't too common yet. Nowadays, pretty much every game looks Next-Gen (whatever that exactly means), making it harder and harder to impress here.

So, let's do that next time, writing a shorter report about whatever I did on this game. Although it will be less visual appealing. For one reason, I simply didn't do any graphics coding lately. As explained before, I shifted the focus on making actual gameplay instead. Not that T22 will be looking worse from now on. Eventually the rooms, assets, and also engine techniques will be upgraded. By artists. But since I don't really have artists helping at the moment, nor any active search for them, I'll have to do the job with placeholders. Programmer art. Dummies.

Got racks full of dummies. On a dummy floor between dummy walls. Actually those boxes are garbage-bags. You're the Caretaker of T22, remember?


Physically Based Rendering
There used to be a time that, even with my limited skills, I was still able to produce pretty decent stuff. Because the quality-bar wasn't as high in other (commercial) games. Much simpler models, low resolution textures, and "bumpMapping" was still a state-of-the-art thing. Nowadays you can't get away without ultra-dramatic scenery, using PBR -Physically Based Rendering. This changed "drawing" into science almost. This new (well, not so new anymore) catchword "PBR" is not some specific technique to achieve photorealism, but more like a label on your rendering-pipeline, claiming your shaders will be using real or close-approximation physics formula's for lighting and such. That's nothing new really, stuff like Fresnell has been there since the start of shaders. And also, techniques like IBL, reflections or GI are still half a bunch of hacks. It's just that hardware allows to rely on the higher-end shadermath these days.

But what did change, are the textures. Less cheats and more reallife based shaders, would also require realistic input parameters. In games, much of that input comes from textures. Whereas an old Quake2 3D asset just resembled a wireframe model & a "texture" (technically the Diffuse texture), modern assets require a lot of layers, describing (per pixel) properties like:
                - Metalness
                - Color
                - Roughness (or Smoothness, if you wish)
                - Normal

And there are more properties like translucency, emissive, height, or cavity/ambient occlusion, but the ones above are most mandatory for PBR. Let’s give a brief explanation. Yes there are plenty of tutorials out there, but I found them a bit long or hard to understand at a first glance. So let’s explain the dummy way first, and after that, you’ll click here for more:


Metalness
Most (game) materials are either a "Conductor" (metal), or "Insulator"/"Dielectric" (non-metal). This can be considered a boolean parameter; either you are a metal, or you aren't. But be aware that rusty or painted metal may not exactly be a 100% pure metal though. So in those cases, you may want to describe this property per pixel. Anyhow, the big difference between the two, is mainly how (much) they reflect. Metals reflect almost everything, making them appear shiny, or "very specular", while Dielectrics only reflect a relative small portion at glancing angles (Fresnel). Think about asphalt; you won't see it reflecting unless looking at a sharp angle, with lot's of light (sunny day) coming in from the opposite side.
                
Older shaders would often allow to manually slide the bars, telling how much "specular" there would be. So the formula became something like this:
                result = diffuseLambert + (specularPhongOrBlinn x SpecIntensity)

This slaps the law of "energy conservation" in the face though, and would basically led to overbright surfaces. You can't be very diffuse and very specular at the same time. Think about it, and hence the term "Physically Based". Surfaces are specular if they are very polished, like a mirror... or a brushed metal sheet. And otherwise they are diffuse, meaning the microstructure of the material is rough, scattering light in all directions. So to put it simple, the formula should have been something like this:
                result = (diffuseLambert x (1-SpecIntensity)) + (specularPhongOrBlinn x SpecIntensity)
               
So the sum of the diffuse and specular components would be 100%. Nothing more, nothing less. Obviously a surface can’t generate more light (unless it’s actually emissive). The metal component we just mentioned can work like a switch: Metals are up to 90% reflective, dielectrics maybe usually somewhere around 3 or 4% only. But instead of making two different shaders with cheap tricks, all materials would follow the same math -thus one uniform supershader-, and using a "metalness" parameter. Either a single parameter for the whole material, or on a per-pixel level, in case there is variation (rust, dirt, paint, coat, objects made of multiple materials, …).

It must be noted though, that there are still exceptions on this uniform shader. Complex materials like human skin, velvet, ruby, liquids or other translucent crap may still be better of using a special-case shader. Or, you can extend this "metalness" parameter to a "surfaceType" one, and switch rendering strategies based on that.

From left-to-right: 1: non-metal + rough. 2: metal + rough. 3: non-metal + smooth. 4: metal + smooth. Direct light coming from left-top btw.


Roughness (the opposite of Smoothness, if you wish)
If you got stuck in older shaders using specularity, like me, this is a confusing one. As mentioned, in the past you would define the amount of reflectivity/specularity. Typically encoding this in the diffuseTexture alpha channel. And then another (sometimes hard-coded) parameter would define "specular Power", or "Shininess", or "gloss". Very high power factors would create a narrow, sharp specular highlight. More diffuse materials like a woodfloor would typically use a lower power, smearing the specular lobe on a wider area, making it appear less shiny.

This was a somewhat close-but-no-cigar approximation. Could be used very well, making realistic results, but could also potentially lead to an impossible combination of factors. Although PBR does not exactly dictate how to do things in detail, it's more common now to define metalness and roughness only. Indirectly metalness would stand for "specularStrength", and "roughness" for "specularPower". The roughness factor does not add more or less specular, but is used to mix between sharp and very blurry reflections.

Another common aspect in PBR systems, is IBL (Image Based Lighting). Again, fancy talk for something that existed since Halflife2 already really (but “low-end”). You would sample light in cubemap/probes on lot's of spots in your world. Than everything nearby that probe, can use that data for both reflections, as well as diffuse/GI. By either blurring (downscaling/mipmapping) the probe, and/or taking multiple samples in scattered directions, you would simulate roughness. A very diffuse surface would sample the probe in very random directions, while smoother ones focus their rays in a more narrow beam, the reflected vector.
                


But... how the hell do you control more or less reflectivity then?! You don't, at least not the traditional way. Non metals would typically use a fixed ~3 or 4% F0 input for their Fresnel value, metals a variable one from a texture (see Color below). And the gloss finishes it off. Very blurry reflections tend to dissapear. They’re still there, but kinda appear as diffuse, making them harder to spot. Note that pretty much all materials actually do reflect to some extend in reallife. But anyhow, if you prefer better control, you could still make that Fresnel factor adjustable (which is what the Metalness map basically does really).


Color
Another confusing term is the texture itself. I'm not even sure how to call it now... AlbedoMap, DiffuseMap... Probably BaseColorMap would be the closest thing, as it often is a multi-purpose texture now. Standard diffuse materials like concrete, would translate this color to, well, a diffuseColor. As we always did.

Metals on the other hand have little need for diffuseColor, and require a "Reflectance" (F0 / IOR (Index Of Refraction) / Fresnel) parameter instead. Which is most often a grayscaled value, indirectly telling the amount of reflectivity. But materials like gold or copper may actually want a RGB value, to give them, well, that gold or copper colour. So, in that case, why not use the same colorMap to encode F0 then? In fact you could store both diffuse and F0 values in the same BaseColorMap, in case it holds both metals and non-metals.

Of course that is all possible. But -and this adds some extra difficulty to making textures in general now- you can't just draw some yellow/brown/orange color to make it look like gold. Well, you can, and you'll be close, but it's cursing in the PBR church. *Physically Based* remember? That would mean you should draw the exact values, the kind of numbers you would find in tables of physics books. Gold would be {R:1  G:0.765557  B:0.336057}. And now I'm in unfamiliar terrain so I shouldn't say too much and misinform you, but to make life easier, artists work with sRGB colours, have to calibrate their screens, and/or use pre-defined pallettes in their drawing software. All part of this PBR Workflow.

Also non-metals should use the right colour intensities by the way. To make a proper HDR (High Dynamic Range) pipeline, all colors and intensities should be in balance. A white paper shouldn’t be as bright as the sun. Or how about putting paper in snow? Snow should reflect more light, so be careful with your color values.

This is a whole struggle, and may distract the artist from just drawing on good old creative instincts. Then again using real data and calibrated presets (that your engine should provide maybe), would result in more consistent results. That's what PBR is all about really.
Good news about PBR, is that this "ColorMap" is more about colors, and less about tiny details now. This ugly dummy texture doesn't turn out to bad with some roughness / metal properties, and a cheap normalMap. Imagine what a proper artist could do with that...



NormalMap
Nothing changed here really, but it should be noted that, thanks to increased videocard memory & computing-power, that the NormalMap has become standard, rather than an optional feature for more advanced surfaces. It should also be noted that materials often have a secondary "detailNormalMap" nowadays, which contains the smaller bumps, nerves and wrinkles, noticeable when looking at a closer distance. It should also be noted that more bumpy surfaces on a micro-level, may go hand in hand with specular roughness. You could chose to encode roughness in the normalMap alpha channel, and metalness or some other parameter in the colorMap alpha channel. So in the end you (still) have only 2 textures for most “normal” assets.




PBR = Photorealism?
So, with PBR we finally touch photorealism? Well some games would definitely start to qualify for that, but not necessarily thanks to PBR. A non-PBR game can look fantastic (first Crysis anyone?), and a PBR pipeline can still look like shit... like Tower22 in its current state.

Hey... where did that go wrong?! Well, it didn't go wrong actually. Left is more “realistic”, technically, as light scatters in a more natural way, and the surfaces don’t reflect as if they were soaked in olive oil. But… hell, its boring. Of course it must be noted that the right(old) side was more complete. The old engine had lens flares, blur, volumetric light, dust, and sharper shadows. But also, the scene itself contained more details, like the stains on the walls, carpet-crap, decals, paintings, et cetera. But in other words, PBR is not an auto-magic key to beauty.

PBR is just a way of working really. One that leaves less room for cheats and inconsistency errors that may follow because of cheating. Maybe more important is the fact that the new engine relies a lot more on IBL (Image Based Lighting), thus sampling cubemaps everywhere. But... if the surroundings are still ugly because of lacking detail, badly used textures, or lack of a good light-setup, then also the sampled & reflected lighting will suck of course. Mirrors can't fix ugliness!


So is Tower22 "PBR"? Yes and no. The shaders are "PBR-Ready", so to say. But my input materials (mostly programmer "art" dummies or recycled items from the older engine) haven't been made on calibrated screens, their metal colors are just approximated, and they were equiped with "SpecularStrength" parameters, rather than roughness. Which is usually not that much of a difference, but still.

Do I want it to be PBR? Not necessarily either. It's up to the artists later on, but I can imagine it over-complicates the content. Don't forget, this is still a hobby project, and eventual future artists may not be the most experienced ones. Also, a horror game like Tower22 doesn't necessarily have to look photorealistic. It should look better than the pics above though, but that is more a matter of giving the scenery more love. Getting the UV-maps right to start with, adding detailed and decals, dim the lights and put them on more interesting spots, use different textures maybe, and then finishing off with improved shading.


A long way to go as you can see. But as said, I'm focussing on gameplay now (read physics, scripting, solving puzzles, inventories, ...). Which I planned to write about today actually... but PBR took me off, damn it.