Skip to main content

Blog Archive

Dynamic Lighting and Shadows: The Voxel Solution

February 7, 2013

by zeuxcg


Graphics gurus Simon Kozlov and Arseny Kapoulkine have been hard at work prototyping a ROBLOX lighting system that uses voxels to create dynamic shadows and lights that can be placed anywhere. 

A constant challenge for us is improving the ROBLOX world while keeping it scalable–as much as we want ROBLOX to look and feel like a triple-A video game, we have to make sure a wide range of hardware can handle it. With that in mind, we’ve created a lighting and shadows prototype that not only drastically changes the look of our game, but can also run on a range of different machines. In order to create this new look, we’re developing a dynamic light and shadow engine where most of the heavy lifting is done on the CPU (instead of the graphics card) and we’re leveraging a voxel-based data structure to do it.

Using Voxels to Create Light

What is a voxel? A voxel is a volumetric pixel in three dimensional space–much how a regular pixel is a building point for a 2D image. We’re no strangers to voxels–we use them to represent our terrain. Now, voxels are the foundation to our new method of lighting and shadows. In this prototype, we are able to surround a character with up to two million voxels at a time–which can be split into a grand total of 64 chunks (which is a 32x32x32 box of voxels), each chunk containing just over 30,000 voxels. With our new lighting system, each of the chunks can light parts of a scene in a completely adjustable manner.

Here’s how the new system works. Your character is surrounded with a voxel grid, which is a fixed radius invisibly placed around your character. This grid determines how light reacts as you move through 3D space, and it moves with you. The grid itself is quite sizeable; at 512 by 512 studs, it’s slightly larger than our famous Crossroads map. Everything within that grid will be fully lit and feature shadows. To do this, we’ve converted all parts and terrain into voxel data–making it easier for us to then compute the lighting of any given point based on that data.

This will allow for some interesting use of light moving forward. Each voxel can have its own light value, meaning different sources of light can be strewn throughout any given map. Though this sounds great in theory, you have to remember that the more points of lights that are created, the more types of shadows will have to render in real time–meaning the more computing power it’s going to take to light your world realistically. Don’t worry, though, we came up with a solution.

Objects will become their own sources of light, realistically brightening environments in real time

The Batching Solution

Each lighting voxel has a size of four studs–which is the minimum size any object in ROBLOX has to be in order to generate a realistically dynamic shadow. We can use information from smaller parts (less than 4 x 4 x 4) to determine how dark or light a given voxel is–that way all elements, big and small, contribute to shadow intensity. Why four? We’d like to make them one stud, which would give us higher resolution shadows. But one-stud parts with dynamic shadows would increase the voxel volume in a way that most computers wouldn’t be able to handle.

Each "light ball" lights up different parts of a closed environment

When your character moves around in ROBLOX, the lighting begins to shift based on your proximity to surrounding light sources. That’s why we’ve chosen to bundle the voxels into groups–we can dynamically change each groups’ light settings to be different depending on the source of the light. If we were to attempt to do this without grouping the voxels together, it would simply take too much computational lifting to provide a stable gameplay experience. This is why we chunk together our voxel data and why the size of each chunk is so important–the chunks are just big enough to compute everything efficiently, while just small enough to recompute small changes in your virtual world when light sources or parts move. Now that we’re giving users the ability to add lights virtually anywhere, we had to develop a system where the light becomes dynamic.

The Ever-Present Moving Parts Problem (And Our Solution) 

Since we’ve changed the way light and shadows move in ROBLOX, what does that mean for moving parts? Thanks to our featherweight and fast parts, we’ve managed to drastically lighten the computational load of say, a building exploding. But how does a change in lighting and shadows affect an exploding building?

When a building explodes, parts fly out from the blast radius, and each of these parts belong to a different group of voxels. Our system works by focusing on updating just the voxels with parts that are moving–so even though a building is being destroyed, we like to think of it as being updated; changed from a solid form factor to a series of loose parts. By focusing on updating just moving parts that intersect with voxels, the shadows can update in real time, completely synchronized.

We’ve applied this mentality to the placement of lights as well. Because light sources can change the surrounding environment, every time you move a light, we update only the groups that are within proximity of it. This keeps computations low while allowing you to have complete creative freedom with light placement, and as many separate sources of light as you’d like.

The Future

We obviously can’t just turn this on (the interiors of all your virtual homes would go totally dark, for one thing), so we’re kicking around ideas as to how we’re going to introduce users to our new lighting system. It could be an opt-in sort of scenario, or a setting for your place that you could turn on and off. We’re working daily on ironing out the bugs and we’ll keep you posted as soon as this becomes an active part of ROBLOX.