Rain effects, better lighting model, optimized code
v4.6 (Jun 09, 2021) optimized PBR, tweaked fake specs, boosted vehicle shine, headlights kill night time specular shine
FUEL: RESHADED v3.2 is HERE, and can be considered a stable archive.
This 4.x branch was started as an experimental branch, but has pretty much become the main branch now since I've added so much stuff to it.
Some changes are under-the-hood (EG: code cleanup / refactoring to make it easier to work with the code). But, I point out the major changes in the running change logs below that you would notice and possibly be interested in.
* factored out a few calculations from the overall Cook-Torrance BRDF equation. Probably won't notice any performance improvement, but it's something.
* fake specs are now shadow-dependant. They do percent curve in shadows, and a mix of grayscale & percent curve in sunlight. The percent curve basically takes the grayscale and converts it from 0 to 1 into a 0 to 0.25 to 0 curve. Basically it does ( grayscale * ( 1 - grayscale ) ), which cuts the high & low values down to zero while keeping the mid-tones. This will help tone down specular shines greatly in shadows.. namely the ones on white surfaces that are super-bright and unnatural. It also helps tone down specular shines in sunlight, b/c the percent curve helps reign the grayscale in some. The grayscale adds more variation to the shine, but it was getting ridiculously bright on some white surfaces.
* I was miffed that vehicles looked dull & faded in BRDF specular lighting. FUEL uses falloff values to clamp the specular amount for things in the scat_mesh shader (vehicles, buildings, etc). For things that didn't have falloff values set, I set some default amounts (0 to 0.5, so things won't get too shiny). But, vehicles still seemed dull. So, I added 0.25 to the min/max falloff amounts to punch it up some. Dull vehicles finally have a decent shine to them now, even if it's just highlighting their rough paint job.
* During the night, it always bothered me seeing a specular shine of the night time light color shining in headlights... you usually see it on a road as an ugly blue or dull pink (right before sunrise) tint that seems to sit unnaturally in your headlights. Headlights should be bright enough to over-power that. So, I made it where the headlights cancel out the specular shine on things at night. This is done with a #define HEADLIGHTS_KILL_SPECULAR flag, so if you don't like it you can turn it off.
As an FYI, in case you dig in __setup.h ... I bolted on a different specular PBR BRDF which I found on FilmicWorlds' web site/blog. It's supposed to be more optimized. I got the code bolted on and working, but it's super shiny and ugly right now. I created a #define SPECULAR_BRDF that controls which BRDF is used... 0 is the one that's working right now (a mix of Urho3D & LearnOpenGL's versions). 1 is the FilmicWorlds version.. again, it's super-shiny and ugly. Makes things glossy & wet and the "sunny trail" is blinding. I need more time to mess with it. But, I've disabled it for now. However, someone may go snooping and wonder what that is. So, that's what this explanation is for.
Minor update / corrections...
Ambient Occlusion was missing from sunlight, so added that back in. Some how got lost in the PBR shuffle. AO was already impacting shadows & speculars, just not sunlight. And, since sunlight is the brightest light, it makes a difference when it's not impacting that. So, AO under vehicles, vehicle detail, etc is darkened up again.
Sunlight had a greenish tint to it. Kept wondering what was going on, or maybe I was losing my mind. But, I switched the ambient light function to use a lerp to mix sun & shadow color instead of the 20/80 split I had been doing by hand. For starters I had the sun & shadow reversed in the lerp statement (d'oh), and, also, after reading Nvidia's Cg reference on lerp, it does weird math to calculate it in a way that I wasn't expecting. So, I just switched back to the old way ambient light was calculated.
And that's it. Like I said, minor changes. But, they make an impact.
This is just a lot of bug fixing and tweaking for PBR...
Distribution function needed Pi added to it's denominator to work properly. Learned this while messing with PBR in The Dark Mod. We noticed some textures looked posterized, like a distinct break between color sections. It's because I pulled out Pi from the equation, since we're not dividing diffuse by pi. But, the BRDF distribution function does need pi. So, added it.
Originally, I had FUEL BRDF skipping the R0 calculation in the Schlick Fresnel equation. R0 is usually refractive index, not specular texture / color. Water in FUEL does a Fresnel equation where it supplies values for R0 to do real refractive indexing. But, other objects do not. But, after experimenting, the specular texture (or fake ones), can be used as the R0 value in the Schlick Fresnel equation. So, got that going.
I was wondering why BRDF specular in shadows was so bright. Turns out I forgot to make it work Ambient Occlusion in. So, I got that added to the BRDF mix.
Ground fake speculars were just using the basic ground texture. I shifted code around, so the ground texture would mix with its decal texture (dirt road tire tracks, asphalt paint stripes, etc) and THEN do the fake spec with it. This makes things like paint stripes on roads stand out more in the specular shine, adding more detail.
With R0 going, FUEL's scat_mesh mega-shader that handles too much stuff (vehicles, buildings, misc objects) wasn't applying specular to many things. After messing around, the base specular materials lighting was pitch-black on several things. So, I ditched that; everything should have some specular amount, even if just a little. I then had to figure out how to work their odd min/max materials specular falloff values into the BRDF mix, otherwise some objects (like ones with cubemaps doing IBL clear coat reflective lighting would have black streaks for some reason). So, I had to fiddle around and do some hackish things to get that sorted out, and then add specular to things missing it. Now more things have specular, like they should.. rocks/boulders, wood ramps, etc. The shine amount is something that hit-or-miss, but it's difficult to isolate things and apply specific amounts to them when Asobo decided to lump so many things into one shader and I can only work with the compile-time flags given to me to try to branch it.
That's pretty much it... but it was a PITA sorting out.
Fake Specular Textures / Maps: A lot of the specular in FUEL is just a generic, constant value added to things. EG: for plants/trees, they get a generic 0.075 value for specular. This can create a very uniform specular shine on things. While messing around with The Dark Mod lighting shaders, I decided to grayscale the diffuse color texture rgb to create a fake spec map that has more variation in it. Came back and did that with quite a few things in FUEL, too .. ground, plants/trees, vehicles/buildings/etc that don't have real spec maps. This adds more detail & variation to the shine you see on things.
New #DEFINE ... SPECULAR_LIGHTING: This new define lets you do 0 for FUEL's default Phong specular shine. 1 for new Blinn-Phong style specular shine. 2 for Cook-Torrance PBR (Physically-Based Rendering) specular shine.
Blinn-Phong Specular: FUEL does Phong specular by default. This is an old-school method for basic lighting models. Most modern basic light models have moved on to using Blinn-Phong. It helps create a bit more realistic specular shine. Added it as an option.
Cook-Torrance PBR: Physically-Based Rendering (PBR) is what modern game engines use. Problem is, to do it correctly you need to have more textures (albedo, roughness, etc). While working on The Dark Mod lighting shaders, I researched PBR & BRDF's, and bolted on a Cook-Torrance specular BRDF by faking roughness maps using speculars (which I also faked.. see above). Came back to FUEL, and bolted it on. I wouldn't call it true PBR, because it's faking roughness and (sometimes) specular to get things done. But, it looks good after some fiddling. A goal of PBR is to not have to mess with variables and such; just dump values in and let the algorithms do the work. They are physics-based algorithms to create more realistic-lighting by curving light around the geometry of the object better, taking microfacets of the object into account, making specular shine look glossy or rough based on surface type, etc. Also, at it's core is...
Conservation of Light Energy: A goal of PBR is that a surface can only output as much light energy as it's been hit with. IE: Law of Conservation of Energy states you can't create energy; you can only transfer (eg: reflect) or transform it (absorb light as heat). When light hits a surface, it reflects both specular shine & diffuse color. Specular shine is part of the light color/energy reflected as-is. Diffuse color is the color the surface reflects while absorbing the others. (EG: a red surface reflects red light while absorbing blue & green). To make this happen, you use a ratio for diffuse & specular (kd/ks ratios) to ensure that their total output doesn't exceed the total input. The Cook-Torrance model helps focus on that. But, I also added it for non-PBR (Phong or Blinn-Phong). Basically, the fresnel value we can generate creates the ratio, and fresnel * specular color is the specular ratio while 1.0 - that is the diffuse ratio. So, all we have to do is multiply the ratios by their light dots to make that happen.
"Enhanced" PBR: If you turn fresnel lighting enhancements on, then they magically create more light energy out of thin air. This violates the Conservation of Energy principle. But, this is a video game. Nobody says we have to follow physics precisely for a video game. So, PBR lighting gives us a base, more-realistic lighting we can then enhance by turning fresnel highlights on.
The _setup.h file has SPECULAR_LIGHTING set to 2 (PBR lighting), and has all the fresnel highlights turned on. If you find specular a bit too shiny, try turning down the FRESNEL_ENHANCEMENT_CAP to 1.5 or so to tone down the fresnel highlights. If you still find it too shiny, try turning SPECULAR_LIGHTING to 0 or 1 for Phong or Blinn-Phong, respectively.
Smooth Night Transitions: popular request, but before you get your hopes up, you can't have smooth nights and darker nights going at the same time. It's just a restriction of what I'm working with from the game engine. The sun color value from the game engine is a smooth, consistent color change from day night. The sky/shadow color is what starkly changes at 2200 hours (10pm) when the game engine turns off shadows and switches the sky color from a dusky light blue to an electric night blue. So, I ditched the sky color, and just use sun color to do both sun and sky/shadow. The coloration takes some getting used to, and also sunrise / sunset tend to have a bluer sky than normal. There is a smooth transition from sun to moon and the sky color smoothly changes. But, because the night flag I have access to from the game engine is an "on/ off" thing, I have to disable it when smoother nights option is on in order to keep that from still starkly switching things over to darker nights. Unless I can find some value from the game engine that smoothly tracks time of day, I'm SOL tracking when night comes and goes and using it to smoothly do that AND make nights darker. I tried tracking the height of the sun in the sky, but it borked up other things (eg: shadows on wheels spun with the wheels). So, you can either have smooth night transitions or darker nights, take your pick. Best I can do. I've reached my level of incompetence on this avenue of exploration.
Rain Impacts Stuff More: As it rains, smoke and fire die down from burning forests / smoldering wrecks / distant smoke from forest fires .. and the sun/moon also try to fade behind the clouds more. I say "try", because for some reason in certain areas you can have pouring-down rain, but the rain value the game engine sends the shaders says that it's not raining. So, it creates awkward moments. The game engine is supposed to hide the sun/moon behind clouds in overcast weather using the fog/horizon atmospherics, but doesn't do so sometimes. So, it's odd when it's pissing down rain and you see the sun or moon sitting there brightly. So, I forced their alpha transparency to kick up when it rains more, making them fade more and act more natural.
Tornado Cloud Swirl impacted by Fresnel World Light: experimented with this more, and decided it looked ok with a little tweaking. The large swirling cloud over the funnel now brightens up on the end coming from the sun.
Misc performance tweaks. EG: realized I didn't need to do a few calculations in the fresnel backlight equation to get same results. Realized that some shaders were doing a lot of vertex calculations for no reason when certain game engine flags were set, so had the vertex shaders test for those flags to bypass that processing. That kind of stuff.
I'll probably take a hiatus working on the FUEL shaders, because I took an interest in The Dark Mod, and decided to see if I could apply anything I've learned with shaders in FUEL to help them out there. Plus, they actually have entire game engine code accessible to look at, so I can learn more about how shaders connect to game engines than I can with FUEL.
If you've played old-school Thief games (Thief: The Dark Project / Thief Gold, Thief 2: The Metal Age, Thief 3, Thief 4), then The Dark Mod will be something you'll enjoy. It's basically what Thief 3 should have been... Unlike Thief 3, The Dark Mod keeps the game play styles of Thief / Thief 2, but adds better graphics and enhances the game play to enhance the style of Thief 1 / 2 instead of becoming something different. The folks that made The Dark Mod used the Doom 3 engine when it went open source, and heavily tweaked it to create it's own thing. You can download The Dark Mod and play it for free.
I'm gonna mess with their shaders for a while to see if I can add any value, and also see if I can migrate anything I learn there over to FUEL. (EG: if I found they were doing shader-side-only SSAO, I'd ask if I could chuck the code into FUEL, too). And, there's still the need for a job. But, currently I've gone 3 days without power in Dallas / Fort Worth due to the snow storm knocking out our power, and that sucked hardcore. We're expected to act like everything's fine, but we have record unemployment, the technology industry wants to hire folks for gig contracts instead of full-time employment these days (so you're constantly worried where your next job will come from), and now we have record snow that's mucked up our power grid.
But, just act like everything is fine, just go get a job, and snuggle under a blanket and read a book. It's just that simple. (smh)
Anyways... I'll stop complaining. People complain when they think things can be fixed. When they stop complaining, but things haven't been fixed, it means they've become demoralized. I'm just becoming demoralized. Not sure where life is going in these "unprecedented times", which is why I keep working on side projects. I want to feel like I'm working on something productive that I have some semblance of control on seeing as life, employment, etc all seems to be out of control lately. Ok, I said I'd stop complaining...
Fresnel World Light Blocked By Shadows: Added option to make the large brightness when facing the sun get blocked by shadows. This will help deepen shadows a bit. Made it an option to turn on/off, b/c if you turn it on then FUEL's dynamic eye adapt / brightness can start to get annoying as you see it change when you go in and out of shadows. Not too drastic, though. Game is playable. I'm just not a fan of noticing the eye adaptation happening. (My opinion is that when everything is working as it should, nothing should stand out like a sore thumb). With the shadows blocked, the scenes are now a tad darker. So, might want to fiddle with your in-game brightness a little. I defaulted the _setup.h file to have this feature turned on, so if you don't like it, just switch it off there.
Nicer Moon: Really sick of the purple moon FUEL has. In other shaders, I tried to make the moon more natural looking, but it would still look super pink/purple in some settings. What I figured out to do was to remove one of the atmospheric / horizon color'ing values, so now the moon can retain most of it's original color while only being impacted a bit. I also got rid of the sun & sky color lights that were also drastically altering the moon's color. Instead, I just amped up the base moon textures brightness as-is before applying a single atmospheric modifer. I checked it out in clouds and clear nights, and it looks decent now in most settings. It will still start to turn more yellowish / reddish as it transitions to sun, though. That's just due to the horizon light color change, and that's needed for it to look natural.
Rain stands out a bit more: Rain was sort of fading into the backdrop during storms, so I made it stand out a bit more. I was sick of rain looking like stark, white streaks, so long ago I made it where the alpha transparency of rain would increase as storms increase, so rain looks more transparent. But, it seemed a bit too transparent. So, modified that to stand out a bit more. (death of a thousand cuts with these changes... sheesh)
Clouds won't brighten so much at night when fresnel world light is on: To compensate for darker nights, I had clouds use a brightening algorithm to stand out a bit more (which acts like light bouncing off the earth and lighting up the clouds). But, with the fresnel world light added in, they were too bright and awkward. So, if fresnel world light is on, the other brightening modifer will get skipped.
Flare smoke & Fires bright at night again: not sure why I switched this off. Probably b/c the shader that handles those two also handles dust / smoke in some places and makes it look weird. EG: on the white flats airport, at night, there will be white dust clouds showing up. They're impacted by this shader, so with brighter flares & fire.. these whiffs of dust are also brighter and stick out at night. This is the problem with tying too many dissimilar things to a single shader. But, I'd rather have flares and fires stick out like they should at night. They're the main thing folks will notice.
... these are minor changes.. just wanted to wrap up a few things. With the introduction of new features, like the fresnel world light, there's always a "oh crap" phase, where I add a feature, think it's fine, post an update here, then realize after further testing something needs to get impacted or tweaked to accommodate it. I'm trying to not spam out updates on here, but I just wanted to post these changes while they were fresh. I really do need to stop working on the shaders. I've kind of done all I can do with them.
Sandstorm Fresnel World Light: realized sandstorms and tornadoes, being large set pieces in the game world, might need to get some fresnel enhancement to look nice. Tornadoes didn't look good. The funnels got too bright. The spinning clouds overhead looked ok with just fresnel world light, but then didn't blend well with the funnel. So, skipped tornado enhancement. Sandstorms looked ok with just the world light added. So, stuck with that.
Fresnel Enhancement Cap: The fresnel enhancements work by boosting the final lighting on things. The problem with this is it can over-saturate the brightness if too much is done. I noticed this on some areas (eg: deserts were blinding, white dirt roads were hyper-bright, white rocky mountains were super bright, etc). So, I added in a value to let the end user cap the amount of overall enhancement. It impacts the final enhancement amount from all 3 fresnel effects combined. So, you can individually tweak how much each of the 3 effects is done, then the cap keeps them all from combining and going overboard. I preset it to an amount that allows a bit of over-saturation to help simulate dynamic eye adaptation / dynamic brightness when in lit areas (IE: so when you look towards the sun it acts like a brightener, b/c you're taking in direct sunlight and reflected sunlight from objects). You can tweak it down if you like.
...things that still annoy me, but I can't seem to fix (IE: they came like that in the game, but I can't figure out how to make them better)
I gotta stop working on the shaders, but just wanted to add final touches to the fresnel enhancements for usability's sake.
Fresnel Enhancements Now Individual Options: realized some folks may not like an "all or nothing" fresnel enhancement that merges the highlights, backlight and world light all together. So, broke them out into individual options to turn on/off, and add percentages for each to let you tweak how much you want each one. (Mostly for the Fresnel Highlights and Fresnel Worldlight, because those combined may create too much brightness for some folks once post-processing bloom kicks in).
Added Fresnel Worldlight to Clouds: The fresnel "world light" is the one that acts like the sun shining a shiney spot on earth from orbit. I already applied it to ground, plants, tire tracks, water, and vehicles/buildings/etc. (Basically anything that had a normal / bump map, because most of the fresnel highlights need a dot product of normal texture by something else.. eye vector, sun vector). But, the fresnel world light I'm doing via dot product of sun vector and eye vector, both of which are easily accessible / calculated in all shaders. So, I added the fresnel world light to the clouds, too. This helps brighten them up when they're near the sun, helping to enhance the "sunny trail" and atmospherics. Probably won't add the fresnel world light to anything else, because most other things are soft particles (dust, smoke, etc), blend in to the scene well already, and it would just add extra processing. The goal is to hit the main things that would really make the biggest quality improvement to the overall scene.
Removed vertex light dots: so, the improvements I made by shifting some light calculations to vertex shaders... they borked up specular shines on things. I was wondering why suddenly the specular was hard to notice on ground, etc. So, I shifted light calculations back to pixel shaders. At this point, I'm shooting for quality, b/c even my potato Intel Integrated HD 4600 can play the game at about 15-20FPS @ 1080p. So, I'd rather have the game look correct & good than run fast but not look right. Even after that fix, I still noticed specular was very dull in shadows. It was b/c I was using ambient light for shadow speculars. I switched all specular light back to using sunlight, and they brightened up and look good now.
Cutoff Lake/Ocean Foam in Distance: shore foam looked awful from far away. EG: sitting up on a hilltop looking at the distant scenery... the shore foam was a squiggly white line dancing around which was very ugly and distracting. Since I was tracking the shadow bands, I decided to kill the foam in the last / further out shadow band. So, long distance scenery shots show the lake/ocean water just seaming along the land. But, horizon fog helps blend it, so it doesn't look all that bad. If the foam (and shadows) didn't spaz out by flickering, I'd probably keep it. But, the constantly flickering foam (and shadows) gets annoying when viewing long distance scenery.
Pre-set Softer Shadows: I turned softer shadows on, and tweaked it's amount plus the ambient occlusion light value to make shadows look nice, but not over soft, and also where the dynamic lighting when going in and out of shadows is almost unnoticeable and helpful now. You can still tweak that if you like, but too soft of shadows, and they look unnatural. To strong of shadows, and the dynamic brightness becomes blinding on the way out of shadows.
Added "World Sphere" Fresnel Highlight: if you look at earth from space with the sun next to it, the sun will create a shiny specular on the earth where the light shines off the earth like a basic ball/sphere. I simulated this using the sun & camera's viewing angles and piping it through the fresnel function. What this does is make it where when you look towards the sun, the entire area brightens up, to simulate this "world specular". It's brighter, because it simulates looking at direct light from the sun as well as light bouncing off the earth (and objects). Where as when you look away from the sun, you just see light that's bouncing off objects and back towards your eyes. The highlight is mixed in with the other two fresnel highlights... the backlighting / spotlighting one, and the "frosted tips" one. Might want to turn down your brightness in your settings when switching this stuff on, b/c it adds brightness to the scene, to which the bloom also enhances.
Mainly, this update was to fix the mistake I made by pushing lighting to vertex and borking up specular.
Vehicles & Drivers Look Better in Overcast Skies: Vehicles & Drivers were over-dark in overcast skies, and stuck out like a sore thumb, like something was darkening them further than the ground and plants around them. After some experimenting, I finally figured out the mega-shader (scat_mesh.phl) that handles buildings, vehicles, riders/drivers, etc had a materials lighting algorithm that was applying broad-brush-stroke gray-scaling to parts of objects, which would darken the lighting further than what it naturally was. This is a case of just assuming the "black box" technology you're given is working out fine, but after experimenting you find out it's kind of wonky.
The materials lighting was setup weird in that it was intended to skew the lighting for parts of vehicles and such, but didn't seem to be set up properly for much of it... EG: on the general custer, the body was setup to be darkened more than the wheels in the wheel wells (which should be darker, since they're in wheel wells that block light). It feels like Asobo bolted on material lighting to the shaders, but didn't full implement it.. or implement it well.
So, I killed the algorithm, and things looked better in overcast skies. But, then I noticed the haze around gate lights and the sand patches in Dustbowl city were white. So, some things needed the material lighting. So, I had to find ways to isolate just those things without impacting everything else. Finally did, and now vehicles, riders/drivers, etc look more natural in overcast skies while other things don't look broken as a result. Huge PITA.
Lighting Performance Tweaks: some objects in the mega-shader (scat_mesh.phl) that handles buildings, vehicles, etc, had very simple lighting, but were doing it in the pixel shader. I found I could move their calculations to the vertex shader to pre-calc for all the pixels that vertex handled. Had to do some testing to figure out what could get by with this, and then how to branch the code to make it happen.
After some experimenting, I also realized that the specular and occlusion texture maps that mega-shader were calling were all just grayscale, which means all channels (red, green, blue) were holding the same b/w grayscale values. So, instead of tracking 3 values for those (6 in total with spec & occ), I reduced each down to 1 value (so 1 value for spec & 1 for occ texture). This lessens the math involved when calculating lights, so another performance tweak.
Overall, it's not drastic performance improvements, but performance improvement is death of a thousand cuts. So, here's a few more cuts.
Extra Vehicle Detail: after doing debugging to look at the actual specular and occlusion texture maps in the mega-shader, I realized the specular texture map is quite intricate and nice. So, I messed around trying to see how I could apply it to vehicles and such to make them have more detail. Eventually found a way to do so, so created an option in _setup.h called "EXTRA_VEHICLE_DETAIL" that lets you add it or not. It darkens some things, adds some dents and scratches here and there... basically the specular texture map is how damaged the clear coat on the vehicle would normally be, but instead of just chromes, clear coats and specular, this option lets you apply it slightly to the vehicle color as well. Some vehicles look more worn now.
Tweaked Water: modified lake/ocean water to not look so emerald green in rain when the sun's out. It's a pain balancing that, b/c when the sun's out it's green, but when skies are overcast you can barely see the color. I think I came up with a decent compromise. Puddle pond scum foam also properly eliminates during rain storms to simulate rain hitting the puddle and dispersing the foam.
Misc refactoring, cleanup, etc... cleaned up the code a bit, b/c it was looking like a child having every toy in the house lying on the floor as I was experimenting with a bunch of stuff. I documented / commented on a lot of my experiments, so I'd know what I did, what worked, what didn't, and why I'm doing things a certain way, then deleted disabled experimental code chunks that were ugly and not needed anymore.
The final goal I'd like to accomplish with the shaders is find some way to smooth out the day/night transition. I've messed around with it, and just can't find a way so far. So, need to back-burner this, b/c I still need to look for a job. I keep distracting myself with the shaders, b/c it feels like something I can work on and see results with. Where-as my job hunt for the past year has been massive disappointment and frustration without anything to show for it.
Fresnel Highlights: Fresnel is light that wraps around the edges of something, or when you look more parallel to a surface, the fresnel makes the surface seem brighter. Fresnel is what the velour shadow highlights were doing to some extent, but this time I went all-in.. everything has Fresnel Lighting now, and it's noticeable in sunlight as well as shadows. When you drive around, you'll notice surfaces that seem more parallel to your view angle will seem brighter. You'll notice the "frosted tips" on things. Etc. This adds more body to the objects and overall scene. It also makes rain more "rainy" as the velour haze simulates rain splattering off things and creating mist that interacts with light.
Fresnel "Backlight": Using the base fresnel term, I played around and found a way to make it look like a faint backlight was hitting things when you look at them. It's most noticeable in shadows. This simulates light reflecting off sunny-facing surfaces into shadow-facing surfaces and creating slight changes in lighting. It especially simulates light reflecting off your vehicle into something you're driving near, creating a very soft moving light that adds more body to objects. It will be very faint, but you'll notice it as you drive around and adjust your viewing angle. Objects will have more body as the lighting changes slightly on them to simulate this.
Both of those are enabled with the new FRESNEL_HIGHLIGHTS flag (which defaults to on in the shaders). Turning that flag off will turn both of those off.
Puddle Pond Scum: used the shore foam water texture to add a faint, slow-moving pond scum foam to puddles. It diminishes when it rains to simulate rain breaking up the puddle surface.
Ocean / Lake Rain Foam: When it rains, lakes/oceans turn greenish to simulate algal bloom. But, now I used the shore foam texture to add in patches of foam all over the surface of the water (not just the shore) to simulate the algal bloom frothing up some. This was interesting to do, because I pull up a tiny foam texture to use as the patches of foam, but then pull up a super-sized version of the foam texture to use as a subtractor (mask) to not make the tiny foam show up in spots. End result is you get patches of foam floating around here and there instead of the entire ocean/lake covered in tiny foam. (Did the same thing for the puddle pond scum.)
Misc Code Tweaks: lots of minor code tweaks for performance, refactoring and testing that would bore you to death if I micro-catalogued them here.
My GTX760 died, and I'm still unemployed. So, haven't popped $ for a new card. Instead, I'm using Intel HD 4600 integrated graphics from my mobo. I get pretty consistent 30 FPS @ 720p, even with the most intensive features turned on (EG: fresnel highlights). So, if you're running any kind of modern, dedicated gfx card, you should hopefully get 60 FPS @ 1080p reasonably.
Velour Shadow Highlights ... Changed shadow highlight feature from reflection (which made things look wet in shadows) to a velour-style haze. The haze "frosts"/highlights things better, and adds more depth to the shadows w/o looking like wetness. It's not just done in shadows, either. It's done to the shadow light, but that light is added to the sunlight. So, as it rains and the sunlight diminishes, the shadow light shows up more and the velour haze makes it look like rain is really coming down and misting the place up. You can tweak the amount of highlight you want in the _setup.h file.
If you're wondering what "velour shadow highlights" are.. a lot of games in the 2010's used velour shadow highlighting to help the player see in caves. EG: Far Cry 3. It simulates ambient light bouncing around and highlighting stuff, so you're not just wandering around blind in pitch black.
I was looking at various shader code on github trying to find a decent velour haze shader to try to shoe-horn in, then it dawned on me one day that Asobo already coded such a thing in FUEL in the vehicle/building shader file. It was just never implemented in the game. I hadn't looked at the original shaders in so long I forgot it existed. So, I checked it out, and the code was exactly what I was looking for. Years later, and I'm still finding code in their shaders to salvage. Go fig.
Added a value in _setup.h to let you tweak how much specular "sunny trail" you want bleeding into shadows. Did this and the shadow highlight amounts, because as you soften/lighten shadows, it washes out the shiny highlight stuff. So, wanted a user-settable value folks could tweak as they mess with softening shadows.
_setup.h is defaulted to a mid-way soft shadows with specular "sunny trail" and shadow highlight amounts that blend in well. But, I also put suggestion comments in the file to help guide you if you choose to try other values.
Better Water Edges ... Tweaked water so the environment reflection and the specular "sunny trail" on the surface would die off as it nears the water's edge. This should help it blend into the ground better. EG: rivers often had spots going up the sides of the river bed unnaturally. This was because the env reflection and specular were going all the way to the edge, not impacted by the edge decay / softening algorithm. So, I just pre-calc'ed the edge softening value sooner, so I could apply it to env reflection and specular; force them to blend away to nothing as the edge blends away to reveal the ground underneath. So far, they look pretty good, and I'm happy with the result.
Forced down-sampling on a few things (which I thought I did before, but turned out I didn't). So far, it's only the shore foam on water, (no shore foam.. looks awful from a long distance away, like from up on a mountain looking down at ocean). and the refraction ground texture under water. Shore foam is already smudgy from a distance, so some loss of detail isn't noticed there. Refraction is only noticed when you're right in the water and can see the ground waving about, or your vehicle shimmering in the water. Other then that, refraction is hidden as you look out towards water due to the transmission vs. transparency (transmission is the light reflecting off the water to show the surface detail, like environmental reflection, as opposed to looking straight down at water where you see through it due to transparency then). So, refraction can get cut, since it's hidden underwater unless you're right on top of it. If you're wondering "why is forced down-sampling something to talk about?" It's because it can potentially improve performance. It's low-hanging fruit; things that don't need a lot of detail getting their processing cut to try to save memory and processing for other things. Not sure if it really helps, but death of a thousand cuts and all that.
Refactored a bit of code, but that's under the hood.
FUEL shaders originally use a tex2D() function to do texture / sample pulls. However, a while back (in the v1.0 days) I tested several other HLSL tex2D functions to see if I could get better performance. Of note, tex2Dlod & tex2Dbias.
tex2Dlod lets you pass in a variable to tell it to blur or sharpen a texture for LOD (Level of Detail). Problem is it's very erratic. The "sharpening" is basically it increasing the texture size and using a quick-n-dirty "noise" function to scatter pixels all over the texture in dithering fashion, so the "sharpened" texture looks like it has ants or tv static crawling all over it. Very distracting and ugly. When it finally moves into downgrading, it blurs textures very quickly. So, things get ugly fast that way, too.
tex2Dbias was more promising. Nvidia's CG / HLSL documentation says it can sharpen textures, but, after experimenting, I never noticed any texture sharpening. Which is ok, because it means it won't screw up textures with gaudy texture sharpening like tex2Dlod.
The better use for tex2Dbias is to downsample textures with a bias amount you can pass in, essentially trying to force the texture to sample at the next mipmap level if possible.
IE: if you have a 64x64 texture, then you can create mipmap levels for 32x32, 16x16 and 8x8.. and then use LOD transitions to (hopefully) smoothly blend between them as things go off into the distance. By shifting to lower-res textures, you save processing power, so only the stuff nearer to the player / camera has more detail (and uses more processing) while stuff farther in the distance (which has less pixels to work with anyways), isn't hogging as much processing.
So, how does this help us?
Well, FUEL tracks shadow slices / bands to do lower and lower res shadow maps the further away from the player / camera the distance gets. In the image above, you can see them heatmapped...
(Shaders won't make your game look like that when you use them. That was just something I did for debugging / testing.)
As shadows process, they come up with an integer index value to pick which band they're processing shadows in. We can capture that value, and pipe it back to other shaders that do shadows, and use it for other stuff.
Ideally, we'd use it for logic branching, in order to avoid processing a bunch of stuff as things shift to outward bands. (EG: degrade from high quality to low quality lighting). But, logic branching with it was killing performance rather then helping. (Which seems to be the norm after I've done more testing).
The better use for it is to use it as our base bias amount to shove into tex2Dbias. We can multiply the band by a bias amount adjustor to make the bias more or less noticeable, and thus, the textures more or less smudgy / blurry / downsampled.
Since the band on top of the player is "0", any adjustment we multiply that by will be 0, which means textures around player will remain unaltered / unbiased. But, as we move to band 1,2,3, the adjustment amount creates bias amounts. But, tex2Dlod is good about blending them together. So, when done properly, you get a seamless, smooth blending of modestly downsampled textures. When done heavy-handed, you get noticeable blurring and noticeable seams where things are trying to blend.
I implemented this hoping there'd be a nice performance improvement. But, with some testing on MSI Afterburner, I didn't really notice much. The Avg FPS & % Lows didn't seem to improve after several rounds of testing. The game felt more responsive, though. Could just be placebo effect or tester bias (IE: I want there to be an improvement, so I'll think there's an improvement even if there isn't a measurable difference).
But, I incorporated the feature into the shaders, thus tossing a new version here. You can mess with it and see if it helps your performance.
The main bonus of it is that it helps to smooth out some transitions on default ground, object, etc mipmap LOD changes FUEL does. FUEL has some very stark / blatant LOD changes in textures as you're crusing around sometimes (EG: a distant ground texture will just instantly flip to a near texture instead of smoothly changing). The bias'ing seems to help create downsampled textures that smoothly transition a tad better (since it's basically overlaying its own mipmap blending on top of FUEL's harsh blending technique).
I applied this bias'ing method to a ton of texture pulls.. ground, vehicles/ buildings, headlights lighting (!), water, chrome / clear-coat / environment reflections ... I even did it to post-processing algorithms doing texture pulls. But, I gave them a separate flag to let you turn them on/ off, because making post-processing do bias to downsample seemed to actually hurt performance when I did some testing. (Your mileaage may vary).
Other then that, no other major improvements.
This should be my last major update the shaders for a long time to come. I really do need to focus on other things right now.
More code cleanup, refactoring, function consolidation, etc.
EG:
Just "quality of life" things from a developer perspective.
Game uses 4 shadow "slices" to do lower-res shadow maps at certain bands further and further from player vehicle. In the last band, they use Shadow Attenuation function to fade the shadows off into the horizon, otherwise it creates a solid black box on the horizon where there's no 5th shadow band/slice. I tried to apply the attenuation formula to every band, hoping it would smooth out the awful "seam" you see where closest 1st band shadows turn into the smudgy 2nd band shadows. I think it helps, but .. maybe not. If it's hard to tell if it's helping or not, chances are it's not helping. (There are ways to blend seam transitions between shadow maps, but that goes into the "white paper" level of incompetence I'm hitting with the shaders and reading Nvidia articles on how to do it.)
Shadows done with vertex-side matrices were also using funky flags sent in by the game engine. I switched some shaders over to use vertex-shadow processing that originally didn't do it in order to save calculations. So, I had to tweak that function to pick the correct shadow band/slice w/o those awkward game engine flags. Doesn't seem to make any visual difference, but at least I know for sure it's picking the correct slice now due to how I coded it.
Removed all of the logic branching I built in v3.2, because the cost of the logic branching was breaking even with the performance improvement sometimes, and even making performance worse. (Modern gfx cards should be ok with logic branching, but I think DirectX 9 is being the handicap here).
Color saturation function in post-processing was sqrt()'ing a static value. So, pre-calc'ed that to get rid of that sqrt() calculation. No big performance improvement from that, though.
Any soft-particle shaders (dust, smoke, etc) that were doing more expensive trilinear / cubic shadow anti-aliasing got switched to use cheaper bilinear shadow AA instead. You don't really notice shadow edges on soft particles unless you're really going out of your way to scrutinize. So, this is a minor performance improvement with very little impact to visuals.
Improved logic branching on unavoidable things by using step() functions to replace <, <=, etc.. and also created a "select" function that made it more GPU-friendly to pick a boolean choice instead of having to use lerp. (Lerp() is intended to smoothly interpolate between two values given a third factor as a percentage. If you just need to make a boolean decision between two values, it's a costly way to do it. So, the new "select" function basically shoves the two values in an array and uses the decision factor as an index to pick the correct one. Not sure if this really helps or not. Performance tests with MSI Afterburner suggested maybe it does, but not a whole lot. Like maybe it was helping with a frame or two.)
That funky shadow band flag sent in from the game engine for certain shaders that did vertex-side shadow processing? Well, I could use it to determine things off in the distance vs. up-close to the player vehicle in some shaders, namely the plant/tree and ground shader. B/c of the distance we're talking about, can't really leverage it for ground, but for plants, built in a CHEAPER_PLANTS flag to switch to low-quality lighting as trees enter that further-out LOD shadow area. This really only impacts trees, because grass fades around player vehicle before it hits that LOD zone. But, problem is, it's a tad noticeable on trees, mostly due to the poor LOD transition from the game engine. Trees already do a poor time fading from low to high quality textures. This seems to get exacerbated by them also switching from low to high quality lighting. This is odd, because the low-quality lighting is simply skipping specular, rain, shadow enhance.. expensive functions that aren't noticeable on trees on the horizon. But, it makes that transition awkward. Might help with performance, so added flag letting you turn it on/off. Unfortunately, shaders that could REALLY benefit from this (like water turning off refraction, which you don't notice unless right in the water) don't have those flags piped in from the game engine. I experimented with manually tracking the shadow band/slice variable and manually using it for logic-branching in shaders to skip expensive processing as things get far into the LOD distance. But, the shaders took forever to compile, and there seemed to be a performance hit with the GPU as it was most likely processing both branches (which defeats the purpose of choosing a low-quality path).
Tweaked moon a bit to be a little more natural / brighter. I wanted to make it a little more yellow, but the horizon blue'ing is insistent on making it blue (with bluer skies on). But, I reached a happy medium.
Biggest improvement is flags in __setup.h that let you adjust shadow amount now. AMBIENT_OCCLUSION_COLOR wasn't softening shadows enough (because it's mostly designed to soften AO to keep it from being pitch black.) So, I added a couple of __setup.h flags to let you turn on a formula that will soften the shadows, and a flag that lets you denote by how much. This gives you much better control over shadow softening / brightness.
---------------------------------
And that's pretty much it. I've basically reached my level of incompetence on some things, so can't progress further with them. Or, I'm hitting diminishing returns on tweaks now as there's hardly anything I can tweak to make things look or run better. It's just been a lot of experimentation and splitting of hairs with very little to show for it from an end-user perspective.
Like I said, this version is mostly a code refactor. Code could still use some untangling to make pixel & vertex shaders only look at their own global functions (like I had in v2.0 before it borked up). But, that's a "quality of life" improvement for a back-end coder. And, since I need to move on with other projects in life, the cost/benefit of it (to me) isn't worth it. Maybe some time in the future I'll organize it more. Who knows. But, the code works for now, does what it can do as best as I can make it do it, and I need to move on.
Average
102 votes submitted.
big thanks! Love the way you fix broken graphics and do not change it too much
thank you!
This comment is currently awaiting admin approval, join now to view.