This week's NXT Dev Blog is a deep-dive into how our brave graphics architects tackled the challenge of making RuneScape's 15 years of content look great and perform well on an unprecedented range of hardware, using a unique range of rendering techniques, both old and new.
If you're an aspiring graphics developer or tech enthusiast, this'll be of special interest read on!
Until now, previous dev blogs have only really scratched the surface in terms of describing some of the exciting features that make the new RuneScape client so awesome. This blog will take a more detailed look at some of those features, how they're implemented, including a discussion of the rationale behind why such features were adopted.
One of the biggest challenges during NXT's development has been improving visual fidelity and performance while ensuring the game still looks like the RuneScape you all love. This is how we've achieved it.
Global illumination (GI) is how games and movies model the indirect lighting in a scene (i.e. bounced lighting). Without any global illumination, every pixel in shadow would be black.
No Global Illumination
This is extremely difficult to solve at interactive rates, and even today the majority of games use an offline pre-processing algorithm for baking GI results into texture maps (aka light maps), so they can quickly be looked up in run time.
The classic technique for previous-gen games is pre-baked radiosity (e.g. Quake and Half-Life series), but more recently games have started to bake more detailed GI data into their light maps like spherical harmonics and surface-to-surface visibility, giving the added benefit of GI working with moving lights normal maps.
At the bleeding edge, pure real-time solutions have started to emerge (light propagation volumes and voxel cone tracing), but such techniques are still maturing, and also require serious, cutting-edge GPU technology to work effectively.
This is something that we really wanted to improve on for the new client, but due to tool limitations and the sheer size of RuneScape, an offline GI solution was not a viable option. On top of that, we wanted something that would be supported on all of our target hardware.
So we reached into our graphics tool box and opted for a modern version of hemisphere lighting, using irradiance environment maps by way of spherical harmonics.
Hemisphere lighting uses a manually placed sphere in each environment to define a gradient of sky to ground colour. The surface normals of the scene geometry are then used to pick a colour from this sphere. For example, if a surface is pointing up facing the sky, the colour at the top of the sphere will be chosen, and vice versa.
Having artists create all these light spheres would have been very time consuming, and an added source of maintenance cost. Therefore, we opted for a real-time, programmatic solution.
This involves rendering a light probe (global environment map) high in the sky over several frames after each map square is loaded, baking the spherical harmonics from that in real time, giving us a highly compressed irradiance environment map in the form of spherical harmonic coefficients.
These coefficients are then used in the pixel shader with some clever maths, taking the surface normal as input to give us the irradiance at that pixel. What this ultimately produces is a single indirect light bounce from the sunlight (irradiance lighting) - or as we like to call it, hemisphere lighting on steroids!
On top of the irradiance lighting, we've also added ambient occlusion into our lighting blender. Ambient occlusion simulates soft, small-scale shadows from the environment lighting based on how visible a surface is. For this we've chosen a form of screen-space ambient occlusion called horizon-based ambient occlusion, which is pretty much the best out there right now.