With our Saxxy 2014 entry canceled and a solid month’s worth of source asset development done for a cancelled project, I though I’d still release what was made for the project. These two posts chronicle my workflow and touch on some things I made, since it’s still very solid work that leverages SFM and source in ways I don’t seem any people in the community do. I wanted to do some workflow breakdowns for how I achieved a very specific look for the short in hopes it’ll help others improve their craft. This post will focus on the environmental design.
The most important (and subtle) part of the environments were an additional push to get reflections working. This post will go into detail how that was achieved in SFM, the branch of source known for being tricky to author assets for (and that’s saying something considering source as a whole has a reputation for being a struggle to work with). I won’t go too deep into the modeling side of it in this post, instead, this will be targeted towards the mapping side of things.
SFM’s Hammer, Cubemaps, and YOU
So, if you’ve used Source Filmmaker(SFM) for any length of time, you will encounter an issue with a map from another branch of source. It will A) Not load, B) Not have HDR lighting, or C) Have no or broken cubemaps.
A and B can be fixed with a simple decompile, fix the problem, and recompile process. C is far more insidious.
That effect is actually a badly broken cubemap reflection. This map is rendered essentially unusable with specular reflections.
I think this is a cubemap issue, still haven’t figured out exactly what caused this. If you’ve seen this before and can fix it, send a electronic-message to this webzone.
When you get huge flashing colors on reflective surfaces, or surfaces that should be reflective are completely flat, your map doesn’t have cubemaps, or the ones it has are broken. If you ask people on forums how to fix them, they’ll tell you to set mat_specular to 0 and deal with not having them. Other people I’ve seen evangelizing the complete removal of them from shots. This is a travesty – cubemaps are an incredibly powerful -if old- system of improving overall material definition for metallic and reflective smooth surfaces. If you know how to leverage them correctly and accept the limitations they have in source, then you can produce some impressive results. Speaking of limitations, here are a few things to keep in mind:
-On models, cubemaps are either shared with phong masking or take up the alpha slot of the diffuse, since these are the only two options for the specular reflection mask in vertexlitgeneric. A solid material definition means that you shouldn’t use the first method, and using the second disables a lot of cool features you can’t achieve without the alpha of the diffuse (translucency and dynamic tinting come to mind).
– One environment textures, cubemaps are the only advanced shader technique you get – there is no phone on world geometry, even in 2014. According to my own tests and observations, a masked pixel on the world geometry shader will be about 35% as strong as one on the model shader, meaning you have to darken a world specular mask by a third to get the similar level of reflection on a model.
– Specular tinting is global, there is no per pixel way to tint the spec mask in source. This is possibly one of the biggest caveats of the generic source shader.
– Cubemaps are placed by the mapper ad are non-parallax correcting. If you look hard enough at a specular reflection on a model or surface in a position in a map, the offset from where the map was generated and where the object is can be jarring is poorly placed. Furthermore, switching from one closest cubemap to the next can cause a form of texture popping that can be jarring and very obvious when you introduce motion. This problem is further magnified in SFM. There is no solid documentation on it (of course), but I have a hunch that projected texture on all surfaces (map and model) use the closest cubemap to the camera, not each model.
This last caveat can produce some very nasty results – imagine you have a cave environment that opens into a small clearing, and you’ve placed a cubemap entity (point to draw your map) both inside where it is dark, and outside where it is bright. In a standard source engine game, the interior of the cave- the rocks, the puddles of water, the static reflective surfaces have had their cubemap pre-defined at map compile. The player, who, for the purposes of this exercise, is holding a reflective sphere, gets a nasty texture pop as he moves from the mouth of the cave to the clearing, but at least it makes sense. The reflections are chosen by which he is closer to. In source filmmaker, the cubemap is global to the scene, so if you placed your camera outside in the clearing and are peering in, the actor with the reflective sphere, the cave walls, the puddles, all of that, is using the outdoor cubemap for reflection. This looks horrible, and as you move the camera inward, all of the textures ‘pop’ to the proper indoor one.
The way SFM handles cubemaps is questionable, there have been some scenarios where this exact event plays out as described, other times I have seen the global cubemap get ‘stuck’ to whichever the camera was closest to when the project was opened. Sometimes, it works as it does in a game – long story short, no matter how you cut it, cubemaps in SFM are broken.
A video illustration of this effect can be seen in in the first 10 seconds of this video, pay attention to the pipes along the left edge. As the camera moves from a near black ‘space’ cubemap to a brighter interior one, all of the static surfaces pop.
But fear not! Broken as they may be, if you’re smart about how you map, where you place them and how good you can cheat the system, they can still produce stunning results.
When mapping for SFM, here are a few things to consider:
-There is no gameplay and no moving objects. Remove anything that moves; nothing is sacred. Seal off doorways with static props or brushes, or leave them completely open. Rule of thumb for keeping props: if it might be animated at some point, strip it out for replacement as an element in SFM. The only props you want to keep are static ones that you want baked into the lighting and will never move. prop_dynamic and prop_physics have no place in an SFM map, or do func_trigger, func_door, or func_rotating, or anything that depends on player action. (still need an info_player_spawn though)
-With lighting, less is more. This actually solves a lot of cubemap issues I’ve discussed – the less dramatic the map lighting, the less dramatic the cubemap ‘pop’. In my experience, you want just enough lighting for a very low level ambient environment – basic shapes are visible, but it is clearly dark. Let SFM lighting shine; SFM’s dynamic spotlights can recreate everything from laser beams to artificial sunlight. You can also use hammer lighting for low level (brightness <10) point lights on objects that glow. Remember, lighting in hammer does not use dynamic shadows, so objects illuminated with map lights generally look washed out.
-Place lots of env_cubemaps, and maximize their render size (double click on the env_cubemap entity and select the largest available render size.) Valve’s recommendation is ‘less is more.’ Mine is ‘more is more.’ You don’t have to worry about performance impact on a non-real time render. In a SFM map, how an environment looks is your only real concern, and I don’t think I have to tell you (again) that cubemaps play a huge role in that.
-Don’t bother with sound. Sadly, SFM does not take advantage of soundscapes or leverage any type of audio from environments, unless you map for TF2 and do only ‘ingame’ recording (and if you are reading this post in earnest, you probably don’t).
Once you have your map done, you can run your standard HDR compile. Nothing unique about this, except you’ll want to use the version of hammer you can find in SourceFilmmaker/bin. (You can use SDK 13 hammer too, I just find that SFM’s one hammer is easier to work with when it comes to custom mods/content you have in usermod. If you’re mapping for garrysmod as well, it might be prudent to go the extra steps for SDK13 hammer.) Once it is compiled, the .bsp will show up in your usermod/maps folder (or the maps folder of your currently active mod). From here, you’ll want to copy it (and all the models, materials, and particles it needs) to your Alien Swarm directory. Yes, Alien Swarm.
Why Alien Swarm(ASW)? SFM’s BSP version is the same as L4D2, ASW, and Portal 2. (for those of you keeping track at home, this is why SFM maps don’t work in gmod) I find Alien Swarm to be the easiest to use of the three to throw a map into because A) I don’t play it, and I don’t mind if its directory gets bloated/wiped, B) Loading a map is fast as the AI overhead for a non-swarm map is low, and will play – unlike a non-AI raw map in L4D, and C) It’s free, for people that don’t own the other two games for some reason.
Once your map is loaded in ASW, run the game, open the console (~), type map my_mapname, select any random character, and hit start mission. You may or may not see your character as it is a top-down shooter, but all you need to do is open the console and run buildcubemaps. Once you see all your cubemaps flash before your eyes, the .bsp in the swarm/maps is now larger then when you put it in and you now have a map that’ll work great in SFM. (For those of you that are mapping savvy, you only need to compile HDR cubemaps, SFM does not use LDR anything, ever.)
A few caveats about using ASW: It has no shared dependencies with HL2 – no default models or textures that most mappers take for granted. You may want to extract the HL2 gcf’s and put the content into the ASW directory. Second, the laser beam shooting from the standard marine will bake into your cubemaps, as well as bullet holes, blast decals, or effects. Run your character into a corner or wall where the laser doesn’t project into the environment and you’ll be fine.
Taking it further
Alright, now that you have nice, high quality cubemaps in your map, how do you take it to the next level? What if you just want to impress your friends with source wizardry? Well I can shine some light on how to do that too.
When you compile your map’s cubemaps, the bsp will balloon in size. If you use VIDE, you can select specific files and it’ll create a zip file you can extract – this will include unopenable vtfs that will follow a cXPOS_YPOS_ZPOS.hdr.vtf naming convention, as well as specific vmts that override the defaults and tell the map what cubemaps to use. (Remember in the last section when I was talking how the engine statically casts reflections on stationary brushes? Yep, bingo, unique vmts.) The VTFs are the textures that correspond to the XYZ of your env_cubemap entities. Here’s the cool part: If you open a .bsp with cubemaps in it, you can rename the cubemaps you extracted from map A, match the names of those in map B, and manually overwrite them. When using VIDE, make sure the names are correct, import the textures from the file browser. Don’t select a relative path and you will be prompted to type one in. Make sure the path matches the existing ones directly. If you did it right, you will get a confirmation of overwrite and the .vtf files will turn bright blue until you commit your changes with a new bsp.
This works exceptionally well for ‘blank space’ maps – map a box with one cubemap at the origin. You can build your box, run buildcubemaps in SFM to get the placeholder, and replace the blank cubemap with one from another map that has substance. If you’re planning a scenebuild, then you can even build a simple version of the environment you want to make in hammer and give it simple lighting specifically for the cubemap – you get the dynamics of a scene built in SFM and the cubemaps you could otherwise only get via traditional mapping.
I created this render box that uses an unlit grey texture for the walls. The cubemap comes from one of my sci-fi maps since I mostly make sci-fi assets, but there’s nothing stopping me from taking a cubemap from almost any map and manually placing it here.
Caveat: This process may not be successful! I believe the uneditable cubemaps are locked by bsp version or vtf version, or at the very least, trying to grab cubes from a newer BSP and putting them in an older one (say a SFMASW bsp to a SDK13 bsp) might give you pink and purple checkerboards of death. Luckily, VIDE saves backup of your map for these kinds of reasons, but always be ready to undo a few steps. Overwriting auto-generated content always carries risk with any program; this is a really hacky way to work around already broken systems, and you should be prepared for trouble.
Extending on the trickery discussed in the last section, I wanted to touch on a custom map I did for the interior shots of the shuttle. I made a box map with a static prop verion of the shuttle and only minimal point lights to get the definition of interior objects for cubemap baking, extracted the cubemaps of the shuttle interior, recompiled the map without the shuttle, baked cubemaps again, and overwrote the interior cubes with that of the shuttle. What I ended up with is the best of both worlds: a dynamic shuttle environment we could modify in SFM, and reflectivity that makes sense for the bulk of the shots.
Hallway and Shuttle Bay
Not much to say about these, they’re both a bit of traditional mapping combined with custom props and decals. The shuttle bay was used for another project previously, I only made slight modifications to fit a door instead of a window. Given the time constraints of the project, I did everything I could to reuse assets from previous projects.
For reference, the map looks dramatically different without cubemaps or lighting – here’s a first pass of a garrysmod build:
And with cubemaps…
In the first draft of the script, the film would have started with the pilot getting a briefing and package in the hangar bay before walking onto the shuttle and taking off. As the script formed, it was decided that there should be a ‘wake up sequence.’ The initial idea was to kitbash something from portal props, and then it moved to a traditional vertical standing cryo-pod she would step out of. I decided, for time’s sake, to model out something closer to a morgue (without the flashy hinged doors, glass, or glowing interior trappings that seem to be the cryo-pod cliche). The cylindrical, tiered approach of the environment also meant I could turn duplication to MAXIMUM. The core design is something I made in a few minutes to simply illustrate to my partner how I thought the scene should play out:
The rest, from that concept to environment completion, took about a week.
I modeled and textured 1/24th of the main ring, and the interior of one ‘coffin.’ The upper rafters are a flipped and inverted version of the corridor, and the center connector is a 1/4th duplication. The only things that are particularly unique are the name plaques, of which I did 9 variants and a ‘power failure’ state.
When completed, I ended up with this:
On the technical side, the environment is 2 2048×2048 textures, with a 2048×1024 texture for the center connector. The holograms are two 512×128 planes, with a third smaller plane that uses scrolling proxies and a shard texture. The entire scene takes about 400k polygons (mostly in ladder rungs), but for a stationary scene, you only need a fraction of that.
The last act of the story was designed to be artistically different from the rest of the film in order to drive home the monumental shift in tone. I initially wanted to place it in what would have amounted to a modern office with cubicles and slight sci-fi trappings – initially, I had considered sourcing CS:GO office assets with a combination of my own work. As the development progressed, we decided to shift more to the idea of a large, open area.
I referred to three major sources of artistic influence:
Norad’s command center, the office environment from the film Gattaca, and a google image search for modren office chairs. I modeled a desk that I found fitting (I’ll be elaborating more on the models in this film in another blog post), and used it as a ruler for a simple environment. What I ended up blocking out looked a little like an iron cross from the top.
Once I had this blockout done, I then shaved down my vmf to the quarter of the environment I was actually going to model, and imported the scene into 3dsmax with wallworm’s vmf importer.
At this point, I focused on modeling out the core assets in max using a 1/4 repeating system, I essentially modeled 90 degrees of it and duplicated the rest.
One trick of note, I decided to not model any kind of entrances or exits, nothing in the scene is really functional. I considered doing some opaque glass doors for the area under the overhang, but that simply did not fit in the time constraints, nor would it have added to the scene as used. Instead, I baked my AO in such a way that the entrances under the corner frame would receive no lighting, and used a black texture for the surface. To complete the effect, I used a black gradient overlay on the floor and rotated/stretched it to size. Normally, this is something you’d assume vrad (valve’s map light baking tool) would take care of, but cubemaps were so strong on the floor texture that I had to kill those with an overlay. The end result looks natural but stylized, as long as you don’t draw attention to the illusion.
I also saved some time by using Portal 2’s stock elevator model for the central hub, it looks decently fitting for the environment and fulfills the need for some way to get to the upper-deck office. The model was placed in SFM not because it needed to be animated, but because placing it in hammer would have covered the lighting origin for the tower’s wall models.
Finally, I used multiple passes to ensure the desks were appropriately spaced in the scene. I did a quick compile of the map with ‘helper brushes’ on the ground that I could place and center the desks over. In the next compile pass, I removed the helpers. Since the dmx had the desks already placed on the map, the next load of SFM with the next map compile had the placement perfect.
With such a heavy reliance on models for this environment, I tried hard to make source look like anything but source. Considering that it was about 10 days of work from hammer blockout to final pass, I’m happy with the result. I’m going to try and convert the environment to UE4 – it’ll be good practice.
Shots of the garrysmod ready build are also nice…
Thanks for reading! I’ll be putting out a post on the model workflow next – the story of how I efficiently placed and populated all of those desks is worth a separate post.