Pseudo-reflections in Tomb Raider II on Psx
The first game I got when I finally had enough money (this include the money I made from saling my Sega Megadrive/Genesis and few games I owned) to buy the PSX was Tomb Raider II.
I didn't have enough to buy a memory card at first, so for a time, I just played the game from the beginning each time. I also remember leaving the game on pause all night with the tv off, hoping my parents would'nt notice the green light and strange humming noise from the cd reader, only for me to return in the morning and finding all my progress gone...
This could explain why I remember so fondly of this game (appart of course from Lara's other assets that might have enticed me as a 11 year old back then), and especially of the first four levels.
Playing through one of these a few years ago, I noticed something that almost shocked me upon realizing what I was looking at. It looked like the developers at Core design managed to include some kind of reflections in the PSX version of the game !
I was learning about shaders and PSX dev at the time, and thought, no way the PSX had this capability. Or did it ? I did a bit of research about it and it seems this effect is achieved through a clever hack involving the PSX's framebuffer.
First, a few pictures to see what I'm babling about:
Do you see it ?
Ok, once again with stills :
Do you see it now ? On the PSX version, on the blade, you can see what looks like a reflection of the surroundings...on a ps1...in 1997...3 years before DirectX 8 and its shader language. Isn't that crazy ? At this point, I thought it had something to do with a special capability of the PSX's GTE or something like that. So I looked into it in order to have more info on this feat.
So, I first checked in the whole game to see if there were other occurences of this effect.
There was. You can find this effect in a few places, and at least in:
- the first level : The great wall : at the end of level, you have to run through a corridor whith collapsable floor and horizontal blades before encountering two rolling-spiky-bloody things - Other video of this effect here .
- Third level : Bartoli's hideout : When entering the hideout, you have to go through a corridor where meany-blade-swinging armors await you to slash you to death, and further in the level, some more blades (to prevent big rats from coming in by the chimney ?)
You can find this effect all over the place in Tomb Raider 1, in the form of blue cristals that allows you to save the game:
In my researches, I stumbled upon this page, with links to several PSX alpha and beta demos.
The effect is not present in the Sept. 30th 1997 beta :
so this means this feature was added at the last minute between the end of september and the release in November 11th 1997.
Whas it a sneaky dev that inserted this code at the last moment ? Who knows ...
So how does this work ?
I reached to the skilled devs at psxdev.net and talked about my findings. Soon enough, a few theories were offered and users gwald and sicklebrick seem to have nailed it. Sicklebrick develops this theory in in this comment :
The TL;DR is that the PSX uses double buffering, so at any time resides in the frame buffer the actual frame, and the one being composed. This effect maps the next frame to the objects on which a reflection is wanted and that's it.
Let's hear him explain it in more details:
sicklebrick says :
Re: Question regarding "shaders" on Psx ( TR2 )
Post by sicklebrick » September 21st, 2016, 3:16 am
I think gwald's onto something here. I just tested on actual hardware. Here's the VRAM as it is normally:
To the left we see both frames in the VRAM... Essentially one is drawn while the other is being created, then it's 'flipped' and the process continues (Double buffering). The drawn area is the one being sent to the screen at any particular time.
On the right (red outline) we see the Colour Lookup Table (CLUT). So instead of textures being stored as groups of RGB triples (e.g. one byte for Red, one for Green, one for Blue for each pixel)... generally a texture will just use something like 64 colours, and each of its pixels will be 'indexed' to that colour. Those colour indexes are the little swatches on the right. The fucked up looking unrecognisable bit at the top is the actual indexed texture data, since it's not stored like a normal bitmap it's not very clear to the human eye. I drew a dick on the stone texture though, so you can see it works. All of the colour swatches have been replaced by random solid colours to make things a little clearer too.
And here are the alterations in game. So much easier to see detail/shapes.
I think in a way this effect exeplifies playstation graphics - "it's crude but it works". Instead of the UV map for these things covering the indexed colour area, as you'd expect, it looks like it's just covering the actual frame area...so costs no more to render than if it were any other texture. Obviously this approach comes with its fair share of issues including the weird warping you see from some angles, the fact it renders itsself, its also likely mapped to the previous frame, the colour reproduction is a little off (see shadows), and it seems to attempt to render different bits of the screen based on viewing angle + position... but it's pretty cool - and actually very clear from the other side with textures cleaned up a bit.
You can get decently fast pixel effects on small areas but you can't operate on the VRAM as if it were a regular chunk of memory and uploading to and downloading from VRAM is kinda slow (for a full frame) and would take up a massive chunk of the main RAM.
For obvious reasons they skipped this effect on the PC because directx doesn't work the same way and seriously... would you want to be the guy in charge of compatibility acrross all of those old 1997 DOS/DirectX machines? I mean we can't even get decent compatibility on open hardware like Android a lot of the time.
Cool effect though, cheers for sharing.
By a remarkable coincidence, as I rewrite this article, Paul Douglas, co-creator of Tomb Raider ran a twitter thread where he elaborates on some trivia about the original game's creation. I couldn't let this occasion sleep by so I created an account and reached out to him about this very subject. Here is his answer, which seems to confirm sicklebrick's theory.
As he point out, the effect exists in TR1 in the 7th level, Midas Palace. When you climb on the hand, Lara turns into gold. Behold the majestic golden reflection effect :
Ok, but how does it work ?
Yeah, okay, the above does not really answer the question of how the 3d engine knows where it should display this effect. Let's //try// to get a bit more technical.
The levels in the Tomb raider games are just files (*.TR2 files in the present case). These files are the same for the Saturn, PSX and PC versions (and I suspect the Android version too). You can compare (diff) them, they're the same !
So it's on the engine side to check if an object should "reflect". How does it know that it should draw reflection ? According to Paul Douglas, based on the item it's drawing, the engine checks if it's the PSX version and apply reflection accordingly.
So to simplify, it's really just a case of the engine going "Oh, we're drawing a crystal, let's put this nice effect on it!"
As a sidenote, a shader version of this effect exists in the open source engine OpenLara for the TR1 crystals and Midas Death, which isn't applied yet to the TR2 objects.
I've gone and mentionned this on the issue tracker...
Yeah, but how does it really work ?
My knowledge of C or how a PSX works is really too limited to understand or explain how it's achieved below this point. If you're really interested in this though, You can have a look at Joshua Walker's compiled documentation about how a PSX work, or the noobs FAQ on hitmen's website.
You can also check out www.psxdev.net which is full or resources and skilled PSX devs.
As for me, I hope to be able to explain how it really really works someday, but for now, that'll be all.
Links and notes
psxdev discussion : http://www.psxdev.net/forum/viewtopic.php?f=48&t=976
OpenLara on github : https://github.com/XProger/OpenLara/issues/240
Thanks to psxdev users gwald and sicklebrick, and to Paul Douglas for their time and answers.
To comment, elaborate, correct, contact me : contact at arthus.net