A while ago I tweeted about Max Payne 2’s character shadows, which were really nice for 2003. Luckily, a couple of Remedy folks who worked on the game saw it and provided scoops:
Me:
Max Payne in 2 only ever casts one shadow, so it just moves around based on – I guess? – averaging the relevant lights. It’s a nice shadow though. A lot of UE3 games did this too, I think including Batman AA?
Petri Häkkinen:
Hey, that looks familiar! I wrote the shadow rendering code for Max Payne 2. 🙂 It’s basically a CPU decal with 2 shadow maps, hard and soft, blended together. Direction & intensity is sampled from the radiosity lightmaps. @jaakkolehtinen
wrote the GI system.
Jaakko Lehtinen:
It’s a shame we never talked about this, or the (what I still think is cool) distributed radiosity solver that scales well with scene complexity by breaking things down with portals and mediating radiance between “rooms” with 4D light fields in a 2-level iterative manner. It’s based on a 1st order SH irradiance volume, which is equivalent to an ambient term (DC) and two directional lights, positive & negative, from opposite directions (linear terms). Shadow direction and strength come from the latter: in a uniformly lit spot, the shadow fades away.
EDIT: After I posted this very post you’re reading, someone else chimed in!
Peter Hajba:
So, what Jaakko was saying there was that the shadow (light) direction is baked into every point in the rooms where the light is rendered on, so you didn’t need to cast any rays to cast the shadow, just look up the direction value from the spot Max Payne was standing on.
Radiosity rendering is pretty neat. Basically it goes onto each point on a surface, looks around to see if there are any lights visible, and then decides if that spot is lit. That’s the first pass. Then in the second pass the renderer also sees the lit surfaces with color.
So if there are strongly coloured surfaces, the light applied to each point gets coloured by that. Then you run a third pass and the light bounces a third time, and more, until you have beautiful baked lighting.
We had a little distributed render farm at the Remedy office. Whenever we let our work computers idle, they would start calculating Radiosity lighting on the Max Payne levels.
Thanks Remedy gang!
in reply to @joewintergreen’s post:
I did a similar thing in Blade 2, although it was fully dynamic. For each character we made a list of all the nearby lights. The first one would cast a proper shadow and bumpmap.
The second one would be a blend of the second light and the third light, depending on the relative intensity of lights 1, 2 and 3, such that if lights 1 and 2 were the same intensity, light 2 would be 100% (so if they swapped, you wouldn’t know), and if lights 2 and 3 were the same intensity, light 2 would be 0% (so if they swapped, you wouldn’t know).
The remainder of light 2 that wasn’t done directly, and all lights from 3 onwards, were baked into a second-order SH and lit per-vertex. So the artists could have tens of “mood lights” and they’d all be squashed into that. It worked outrageously well on the original Xbox and PS2.
Something like that was the default on UE3, so ended up shipping for most games on that engine. The worst attribute of it, which some games cleaned up and most didn’t, was your character only ever cast one real shadow, so if you ran down a hallway with lights along it the shadow would jump around, which is less noticeable in MP2 because it’s a soft shadow and harder near the contact, but in UE3 it was just a uniform much-harder shadow. Gamers’d never notice though.
I think I tried just have a single shadow that interpolated position/direction, and yeah it bounces around like crazy. So I had two and they faded in/out so that it only switched lights when it was fully faded. It still looked a little goofy in some cases, but mostly nobody noticed.
Leave a Reply