Lighting Polish – Shempi
This week I’ve been working a lot with lighting in Unreal. Good lighting can add significant polish to any game. Lighting is a challenge because every use case requires a different lighting setup. One thing I’ve noticed is that many users find nice lighting through fakery of sorts, by using many lights of varying intensity. As a lighting beginner in Unreal, I’ve decided to start by putting the lights in that make sense, then tweaking from there. After much tweaking, the tentative lighting setup consists of 1 Skylight, 1 Directional Light, and 1 Exponential Height Fog. The skylight is a stationary light, which is the middle ground between static and movable lights. Stationary lights are not as costly as moveable lights while allowing baked lighting and dynamic shadows. Since a directional light would be necessary for believable lighting, I decided that the skylight will be used for the general “filler” lighting and therefore would not need to be movable. The Directional Light is what gives the scene shadows and depth. By making the directional light movable, and setting a variable in the engine config file (for some reason it’s disabled by default), we allow for Global Illumination through UE4’s Light Propagation Volumes. More on Global Illumination later. Finally, to soften up the scene we have Exponential Height Fog (EHF). EHF is most easily compared to plain old fog, but it’s useful for more than simply making a foggy scene. In UE4, EHF is customizable by density, starting distance (from the camera), opacity, falloff, color, and much more. Even the slightest use of EHF gives a scene depth, so it is normally recommended to use it. Don’t be deterred by the word “fog” though, because probably the most common use is producing an aerial perspective effect in scenes that have no fog at all. For both lights and the EHF, I use a very light blue color in order to lower the temperature of the scene for more believable lighting in a snowy environment.
Quick note on Global Illumination. Global Illumination is one of the most realistic lighting schemes in which each object being lit by a light source projects it’s own light onto the rest of the scene. Global Illumination allows for even a single light to produce a much more rich scene with realistic lighting and color bleeding. For example, if light were shining on a red box sitting near a white box, the white box would catch red light emitting from the red box. These details may seem small but they end up making a big difference in the lighting of a scene. Global Illumination helps realistically light BCE largely because of the snow that covers the battlefield. The snow, which is largely white, helps light the rest of the scene through the indirect lighting of global illumination. This gives our scene a richer, more vibrant look.
A big challenge for us is to have believable outdoor lighting, while also being able to have a nice transition to the darker indoor lighting of the cave. I’m currently experimenting with different methods to produce a dark, firelit cave that is largely unaffected by the outdoor lighting. While perusing the internet I found a method using reflection captures and the console command “r.DiffuseFromCaptures 1.” The basic workflow for this method is as follows:
1. Place reflection captures in the area that should be dark (house with windows, cave, etc)
2. Turn off the light source (this will only work for static or stationary lights)
3. Enter “r.DiffuseFromCaptures 1” into the console (this step might not be strictly necessary…still experimenting)
4. Update Captures on your reflection captures
5. Turn the light back on (don’t recapture!)
This method essentially preserves “out-of-date” lighting within the reflection capture volumes. This little trick is sort of a hack, so I’m hesitant to use it. One thing I have yet to determine is whether or not this method requires the ONLY reflection captures in your scene to be the ones that are used to fake darken a room. The reason this might be the case is because, as far as I know, you can’t individually update reflection captures. It’s all or none. I will continue to research that but if that’s true, then we wouldn’t be able to use this method because there are reflection captures all over our scene. Either way, my attempts at using this method have failed so far, so I must either be doing something wrong or this hack has been made obsolete by a new version of Unreal. The other method that I found involved decreasing global illumination through a post process volume. I suspect that a combination of both methods will produce the best result.
Current WIP lighting
Lighting is still very much a work in progress, but it’s getting more and more polish with each iteration.
New HUD, Grass, and Fading Scenery – Kig
The last two weeks I’ve been hopping around a number of polish tasks but today it’s all coming together and things are starting to look good. After creating a behemoth of a landscape material I mentioned in my last post, I started looking into some grass materials on the Unreal Marketplace. The one I settled on looks pretty nice and it allowed me to edit the materials to add some snow effects, wind, and play around with the spawning of each individual type of grass and flower. Right now the grass doesn’t react to player movement and does not have any collisions so it looks static when they player moves through it. This is something I’d like to change when walking through a patch of grass but that will be a lot of work which I’ll have to focus on another time.
The grass is not optimized yet so it has a slight impact on the FPS. I’ll be fixing that next week too.
Another big change to the game is the new and improved HUD. Up until this point the HUD has been a mess of mismatching art styles and odd placements. This update moves all the relevant HUD information to the top of the screen and accomplishes two things. It makes the information more readable to the player and the bar at the top slightly mitigates the problem of having an extended line of sight as a result of our 60 degree camera angle. The style of the new HUD is meant to resemble cave paintings so the colors and geometry will be simple and it will match the style that all of the upcoming UI elements will incorporate.
Still on the way: Animated fires, new font, and cleaner spacing.
The last thing I just got finished this week was fading scenery which was a really crucial feature. Once this is implemented, we’ll be able to bring in our cave asset which will add lots of polish. I started work on fading scenery about a month ago when I created a fade component. Unreal allows you to create new component actor classes so I wrote a simple fade actor in C++ that I could attach to any static mesh which would allow it to become translucent when the player was in front of it. This worked for a single player but caused issues on the network because the texture would fade for everyone on the server. After struggling with it for a few days I left it alone and finally picked the ticket back up this week. I scrapped the C++ component actor I had written and instead made a new blueprint for a parent fading object. This parent object does almost everything the fade component did but it does it at the replicated actor level instead of the static mesh actor level. This is an important distinction because when Unreal generates the map for the server and clients, static mesh actors only exist on the server. A replicated actor exists once on the server, and once for each client. This allows me to edit the translucency of a static mesh but only for the person who needs to see that change. This does mean however that the Game Mode must spawn the caves at runtime so that they are replicated to clients. The solution I came up with ended up being pretty elegant and easy so I think I’ll make a tutorial for it in the coming weeks. When I was working on this I spent a lot of time looking for tutorials and found nothing about networked fading scenery so it should save some people from the struggle I went through to get it working!
Now only one person will see faded scenery.
That’s all from me for this week. Next week I’ll be continuing to polish the HUD and map and doing a pretty deep QA pass on the game for the upcoming trailer.
BCE Netcode 2: Replicated Variables and Combat State – Toffee
Hi everyone, this is the second post in a series regarding BCE’s netcode, and how we handled network replication within the Unreal 4 Engine. Previously, I discussed on a basic level how the Unreal 4 Engine handles network replication. This time, I’m going to delve into a bit of our own netcode, beginning with the Caveman and the Weapons.
For those who haven’t seen or played the game yet, the core combat revolves around cavemen picking up and choosing their own weapons. Weapons have a melee and ranged attack, and their damage and effects depend on the weapon. For example, hitting someone with a club melee deals flat damage, but throwing the club stuns the recipient. In order for combat functionality to flow effectively, it was imperative that we categorize each potential state the caveman can be in. His holding stance, animations, and movement are dependent on the weapon held, and must be updated accordingly. We’ve deemed this state as the “Combat State.”
Above is the logic flow of our Combat State switching. If you’ve seen the previous post, this might look familiar, as it’s an extended snippet of the same code. The caveman picks up a weapon, triggering this state switch: if they are not the server, they request the server to run the following functions on their behalf. Any changed information that other players need to be aware of is stored as a replicated variable.
When a variable is replicated, all currently connected players are aware of that variable’s value. This is useful for keeping track of things like player health, or in our case, Combat State. It’s crucial that all connected players are aware of each other’s states when in combat. The key to properly utilizing replicated variables is understanding that only the server can broadcast a change to that variable. Like the example above, this means that if the client were to update his Combat State variable locally from Unarmed to Club, his version of the variable would be updated, but no one else’s would. But should he request it be updated by the server, all connected players will see that his Combat State variable has been set to Club. Ensuring that the server handles the updating of these variables keeps everyone synchronized.
What occurs following the Switch has Authority node is as follows: set the calling caveman’s speed appropriately (cavemen move slower when holding a weapon or a bundle of weapons), destroy the rock in the caveman’s hand unless he is switching to unarmed, then perform a weapon-specific attachment. The implementations of these functions is irrelevant at the moment, but what’s important is that all of this is run on the server, allowing all connected players to see what happens to both the calling caveman and his weapon.
That about wraps it up for this post. Going forward I’ll be going into more detail on other areas of UE4 netcode and BCE’s usage in particular, as well as some insight into what worked and what didn’t during our development process. Thanks for reading, and I’ll see you next time.