Red Alert: A Path Beyond Dev. Blog
APB update coming soon! In the meantime, have a dev blog of the latest changes that will be implemented.
Water Effects Tweaked
Come on in! The water's fine! Water effects have been tweaked just a bit so that the blue fog/tint that normally only shows for submarines now shows for anything going underwater. Anything! Even those soldiers doomed to a watery grave... Good day for a swim still!
Players love to fly our Yaks and MiGs. For our intrepid pilots, they will be glad to know that planes will now be able to free-look. This should offer better visibility when necessary and offer better scouting to report enemy movements back to your teammates. Remember that you can now type in team chat and global chat without fear of crashing or stalling out, thanks to previous improvements in our flying mechanics.
New Unit Sounds
Before we get into what we have added, let's preface with something neat. For those who have been keeping up with Command & Conquer news, CCHyper, Nyerguds, Tore, TaxOwlBear and Chad1233 have shared Red Alert Beta with the community!
Click the image below to be directed to the Reddit thread celebrating this present to the C&C Community and all its full details.
From the Beta, we have been able to make use of unheard voices for our units. Particularly, we have given our Thief new lines.
“Like candy from a baby.”
“Let’s pick ‘em clean.”
“Time for a little five-finger discount!”.
Players should know however, that you will only hear these lines when you are actually in range to steal. Good luck to those brave infiltrators! May you make a clean getaway after the Soviets hear "Credits Stolen".
Additionally, we have added another line to our generic Allied infantry.
"It is done."
Perceptive listeners may have previously heard these lines in Counterstrike's Radio 2 Remix, during the vocal break in the track. Before CCHyper and Co.'s delivery of this build, these voice lines were not isolated from the track nor found anywhere in the game files. With the release, we are fortunate to now be able to add finer details such as these to A Path Beyond.
Battlefield Unit Reference
Players familiar with Renegade's menu may recall the EVA Data Link that included the map, objectives, and data for your campaign missions. Players may also recall there was a tab for Characters, Weapons, Vehicles, and Buildings. What we are excited to unveil is the Battlefield Unit Reference for our APB units!
Thanks to CMDBob, we can now offer this useful resource to players new and old. Pushwall is adding the models and unit descriptions and will ship this out with the next APB update! As you may guess, there is much to fill out. We have barely scratched the Characters tab after all!
And that concludes this dev update for APB! However, there is much more to show! Dghelneshi, our scripts and coding wizzard, would like to show you the following...
Dynamic Lighting Improvements
The way lights were handled in W3D has been a thorn in my side for a while so I recently decided to tackle that problem. Especially spot lights were basically unusable (not a single one is presently used in any 5.0 project) due to various shortcomings both in the engine and the editor.
To be clear, I'm almost exclusively talking about how light interacts with dynamic/moving objects, not about the baked vertex lighting for static meshes ("light solve"). The latter is not easy to replace at a reasonable performance cost despite how terrible it looks, so I'm leaving that for the future. I'm also slightly misusing the term "Dynamic Lighting" to mean static lights illuminating moving geometry. We do not have moving lights in W3D.
Lighting in W3D
The most egregious problem was that most of lighting calculations were done on a per-object basis, at the center point of the model. For example, the incoming light direction was calculated once for each mesh and thus every light was effectively treated as a directional light (infinitely far away) in the pixel shader. This means that there was no smooth distance falloff (attenuation) for the light across a larger object. The only thing that was considered per-pixel was the angle between the mesh normal and the incoming light direction.
You can clearly see the jarring visuals this can create in the screenshot below (walls are usually not lit as dynamic meshes, but they demonstrate the issues quite well):
The wall in front is lit by a red spot light, while the back wall is lit by a white point light. There are horrible discontinuities in the lighting across the three wall segments, and the leftmost segment in the front doesn't receive any lighting because its center point is not within the maximum attenuation radius of the light. Furthermore, the tree to the right is fully lit up despite only grazing the red spot light cone (the cone visualization is also new) because it is still only checked aginst the radius, not against the actual cone.
The latter is not just a minor visual problem since we can only have a maximum of four lights processed per object (for performance reasons), so if there are multiple spot lights close to each other with non-overlapping cones, but overlapping spheres according to their attenuation radius, the game might have a difficult time picking the lights that contribute the most light to this mesh, leading to annoying situations where lights suddenly "pop up" or flicker when you're moving through the world.
This means we largely had to make two fundamental changes:
- Move the code that handles light attenuation from the CPU side to the GPU pixel shader and pass all the relevant information along (light position instead of direction, inner and outer attenuation radius, etc.).
- Improve the light culling code so that it can more accurately predict how much a light would contribute to the resulting illumination of a given mesh.
#1 was mostly straightforward, modern GPU shader code is quite flexible and the worst case performance impact was below 10%. The overall behavior of lights was kept close to what it was before in order to not force the project developers to relight all of their maps.
#2 required adjusting the code to work with the bounding boxes and spheres of the objects instead of just the center point. Every model now first checks its (axis-aligned) bounding box against the bounding box of the light (hierarchically using an AABB tree), then its box against the light sphere and for spot lights it also calculates the intersection of its bounding sphere with the spot cone (box vs cone is much more complicated and costly).
The picture below shows the sphere vs cone test in action, with various colors representing the different individual tests that are performed in that function (you may notice the cone visualization now has a proper spherical cap instead of just a circular base).
If all of these tests succeed, we try to approximate the potential contribution of this light by doing the same light calculations that would now normally happen GPU-side and per-pixel at the center point and the eight corners of the bounding box of the object and averaging them. This kind of code needs to exist for light solve anyways. If more than four lights pass the intersection tests, we use the approximate contribution to (hopefully!) pick the four visually most important lights. If we don't additionally use the corners for the approximation, we can run into problems where the light is considered for inclusion, but displaced by other nearby lights that visually contribute less in the end. I'm still not happy with this result but for now I can't think of anything better that isn't even more expensive.
The two screenshots below illustrate the "popping" behavior that can happen if light culling isn't picking the most important lights correctly.
During the course of development, a few smaller changes were made to improve various aspects of lighting:
- Accurate visualization for the spot light cone instead of just a sphere like for point lights
- Numerous types of objects that don't actually use any dynamic lighting now don't unnecessarily have their light environment calculated as per the description above
- The rotation controls in Mammoth were actually broken in a few ways, this has been fixed.
- Light attenuation has been changed to a quadratic falloff instead of linear (between inner and outer radius), for a smoother appearance without changing the overall look too much
- I considered using a more physically accurate attenuation model, but decided against it since that would make the light's maximum influence radius bigger (potentially forcing a higher light limit per object) and the results would look so different that all lighting would have to be redone across all of our 5.0 projects.
- Added inner cone angle setting to spot lights, replaces "spot exponent", which was completely unused anyways.
- Light solve and approximate light contribution now use the same code instead of there being two functions that even slightly disagreed with each other (e.g. spot light direction was not consistent between static and dynamic lighting, which is yet another reason why they were not used at all)
- Small changes to specular lighting shader code
After all of this work, the scene from the first screenshot now looks like this:
Aaaahhhh... Much better!
Actual Dynamic Lighting
Since I was already working with the lighting code, I decided to disable light solve and quickly hack two moving lights onto a vehicle just to see how well it would work. I had to increase the maximum number of lights per mesh to 64 to make it even remotely viable, despite this being a very small map (still not quite enough for the gigantic terrain mesh, which touches every light on the entire map...). This made the game run at barely 60fps on a GTX 1070 and a small empty map, so please don't expect anything to actually come out of this any time soon. It was just a test, this is not a feature announcement. Various things in the engine would have to be fundamentally restructured to make this even halfway realistic in terms of performance.
Light Solve and Transparency
A small change to light solve makes it actually shine light through transparent objects like windows (though it effectively just ignores them instead of doing any fancy light transmission calculations since we can't easily sample textures on the CPU...). The screenshot below shows a test scene where I just deleted all lights inside the APB war factory on Guard Duty and only let it be illuminated by the sun shining through the windows. I wouldn't quite call it "pretty" due to the lack of bounce lighting and the usual issues with vertex lighting, but I would say it's at least somewhat interesting to look at. I pushed the light solve change out to the main branch and so far nobody has screamed at me yet.