Valve Developer Union

Custom 2D Skyboxes and the light_environment Entity

(December 7, 2017)


A 2D skybox is a set of six images (up, down, left, right, front, and back) that wrap around the playfield in a box shape and never move, as if they were the distant sky. In a map of custom assets, a custom skybox helps to add that extra bit of polish, and they're rather easy to compile. A bit harder is how to make it give off light that matches the texture, but this guide will go over that as well.

Preparing your assets

First, gather the six separate images that'll make up your skybox. It helps if their respective sides are labeled beforehand. If you're looking to make a skybox, you can do a search for "skybox generation tools" and something will turn up. For this tutorial, we'll be using a sky generated by the Space 3D web app by wwwtyro (the seed is 5reyuop11oo0). This skybox will be named "nebula".

Nebula, our demonstration skybox
Nebula, our demonstration skybox

The process from here on out depends on whether you're mapping for GoldSrc or Source.

Custom skyboxes in GoldSrc

GoldSrc skyboxes should be rendered at 256x256 per side. Your mod folder should have a folder inside of it called gfx. In it is a folder called env. For base Half-Life, you'd be looking at a path of Half-Life\valve\gfx\env. Convert your six images to TGA and give them all the same name, punctuated by a two letter abbreviation of the side name.

Our Nebula skybox, ready to be used in GoldSrc
Our Nebula skybox, ready to be used in GoldSrc

Drop these into the env folder. If you're using a Hammer-like editor, you can set the sky by going into the Map menu, selecting "Map Properties..." and setting the sky name as the name of the skybox texture without any side abbreviations. In our case, we'd put in "nebula".

Nebula used in a custom Half-Life map
Nebula used in a custom Half-Life map

Custom skyboxes in Source

Source skyboxes are a bit more involved. Render out your six images at any resolution. Default Half-Life 2 skyboxes are 512x512, and the engine will accept higher. Make sure they're all the same size. Our images will be rendered at 1024x1024. Compile them all as VTF files with the "Clamp S" and "Clamp T" texture flags set. (You don't need mipmaps or bumpmaps for a skybox.)

The "Clamp S" and "Clamp T" texture flags in VTFEdit
The "Clamp S" and "Clamp T" texture flags in VTFEdit

If you're using VTFedit, make sure you save after checking the flags, because the program won't prompt you of unsaved changes. Put all of the VTFs in materials/skybox/.

The skybox blurs and smears when the one the game wants doesn't exist

Blurred expanses

Your skybox must be stored directly in the materials/skybox directory of the game. Even if it's in a subdirectory and you set it as such in Hammer, the game won't see it. As a result, you'll get a strange, smeary black void instead of a skybox, or a jet black void if you have gl_clear set to 1.

Name them all the same, appending two-letter abbreviations according to the sides. Your VMTs for all six sides should be relatively identical:

UnlitGeneric
{
	$basetexture skybox/[texture]
	$nofog 1
	$ignorez 1
}

Replace the $basetexture value with the side in question. You should have twelve files. (The PNGs listed below aren't necessary, but we've included them for visual reference.)

Our Nebula skybox, ready to be used in Source
Our Nebula skybox, ready to be used in Source

At this point, you can set it in your level editor by going to the Map menu, selecting "Map Properties..." from the dropdown, and setting the skybox name as the name of the sky without any side abbreviations.

Nebula used in a custom Garry's Mod map
Nebula used in a custom Garry's Mod map

Setting light_environment keyvalues

After you've set a custom skybox texture, the next step would be to pair it with a light_environment entity, to simulate sunlight and ambient light coming from the sky itself. Only problem is, the light_environment entity can be a bit confusing. With Hammer's standard "pitch-yaw-roll" settings, a separate pitch setting, and both a Brightness and an Ambient setting, It's hard to tell what you should put in which box. Of course, if you were using Valve's default skies, you could rely on Valve's official settings, but what should you put for a custom skybox?

Brightness and Ambient

The Brightness and Ambient values set the color of the direct light from the light_environment entity, and the light coming from each of the tools/toolsskybox-textured faces, respectively. The green light in the picture below comes from the Ambient value, and the sun spots are from the Brightness value.

Ambient light coming from the skybox
Ambient light coming from the skybox

We'll use an image editor to sample colors from the skybox texture to use with these keyvalues. (This assumes you are proficient with some kind of image editor, such as Photoshop or paint.net. Any editor that will display the RGB values of a color sampled using the Dropper tool will work.)

Using an image editor, sample two colors from any of the sky textures. The first color, what we'll be using for the Brightness keyvalue, should be one of the richest and brightest colors in the skybox. If a sun is present, you can use its color. The second color, for the Ambient keyvalue, is most often some kind of deeper blue used to offset the Brightness color. This isn't always true, however; the sky_dust Ambient, for Counter-Strike: Source, is another shade of yellow, and our "nebula" skybox uses a green Ambient. (GoldSrc doesn't use the Ambient color, only the Brightness color.)

The Brightness keyvalue in Hammer The Ambient keyvalue in Hammer
Left: The Brightness keyvalue in Hammer
Right: The Ambient keyvalue in Hammer

Using the RGB values sampled from the skybox, fill in the Brightness and Ambient keyvalues. For our "nebula" skybox, we went with a Brightness of 200 190 192, and an Ambient of 38 96 65. Of course, Hammer requires four digits, with the fourth setting how bright the color is. We went with brightness values of 400 and 150, respectively. You may need to scale it up or down, depending on how bright your skybox should be.

Info

A dark cloud over HDR skies

You likely won't need to change the AmbientHDR, BrightnessHDR, or either ScaleHDR value. Not to mention that, if you've followed up to this point, you'll only have an LDR skybox, not an HDR-capable one. HDR skyboxes are much more complicated, and as of writing this, we've been unable to find a free alternative to HDRshop, Valve's recommended tool for making one.

Pitch and Pitch Yaw Roll

These control the angle at which the direct sunlight from the light_environment will hit the world. Likely, this will correspond with your sun, either one painted onto the skybox or one using an env_sun entity. To set this, select the "Pitch Yaw Roll (Y Z X)" keyvalue and click the "Point At..." button. Your cursor will turn into a crosshair, and you can click anywhere in the world. The light will point to the spot in which you clicked. Both Pitch values will function identically, and the "Point At..." button will fill in both of them.

Using the "Point At..." button to select where the light_environment's sunlight will fall
Using the "Point At..." button to select where the light_environment's sunlight will fall

Getting the right angle can be tricky, and you might need multiple iterative compiles to test different settings. If you have a sun, try to point the light_environment towards where it'd make sense. Move around the level and block the sun from your view using your world geometry; if you're standing in a shadow, that's a good sign. If the sun is partially obscured and you're on the edge of a shadow, your shadows are likely accurate to the sun's positioning.

The shadows cast by the world geometry are roughly accurate to where the sun points
The shadows cast by the world geometry are roughly accurate to where the sun points

SunSpreadAngle

Essentially, the higher your SunSpreadAngle is, the softer your shadows will be. Sunlight will almost always be blurred somewhat by clouds and atmospheric conditions, so you should always set something for this value. The scene above uses a SunSpreadAngle of 5, though values up to 100 and more aren't unheard of. Play around with it.

Paired with the right light values, a custom skybox can completely alter the look and feel of a scene. The above test map, paired with our "nebula" skybox, gives City 17 an eerie, alien feeling, like the place has been transported to Xen. It's definitely worth looking into custom skyboxes for your maps.

↓ Download Example Skyboxes ↓