Building a PS1 style retro 3D renderer
david-colson.com
david-colson.com
Another thought - I also wrote a similar renderer under similar constraints a while back, just for funsies, and I'm wondering what would have came if I thought "I should write an article about this". I generally don't think to write articles over every side project I do, what's the impulse for when someone decides to detail their work to the internet?
When it comes to writing, I think the biggest factor that determines if/what/and how you write is the audience you imagine. When you write, you sort of picture yourself telling the story to someone. And the way that scene plays out in your mind depends entirely on who that person is.
If your mental image of the audience is "some random Internet user whose interests are different from mine", then you can't imagine them standing there patiently while you laboriously walk through all the details of your renderer. So you don't.
But if you imagine an audience that is "another retro renderer enthusiast who has similar projects", then you can imagine them getting hyped up by what you're saying and gleaning bits of useful stuff from it that they can apply to their own side projects. It almost feels wrong to not write it and let them down.
One advantage of this is being able to look back on previous projects in the future, as a form of documentation. That helps me pick up on a project I haven't worked on in a bit. True, you don't need to publish the documentation publicly, but since I wrote it, putting it up publicly is almost no effort now that I have a blog.
I personally am not "retro renderer enthusiast" nor have similar project, but this article was joy to read.
Either audience choice is fine, I just think it's interesting how it impacts the resulting writing.
While it's true that the PS1 handles perspective projection through the GTE (as the GPU is a primitive rasterizer, after all) I don't think it's fair to call it 'faked 3D' since, in my understanding, 3D projection is another fundamental stage in the graphics pipeline (our displays are 2D grids of pixels, so we need to transform the 3D world into something it can be displayed there). Other consoles like the Nintendo 64 provided more capability on the GPU side (the RCP) which allowed to move part of the matrix operations away from the CPU chip.
Be as it may, I've seen the 'fake 3D' claim before and I'm starting to wonder if I'm missing something in my understanding of this technology, maybe someone can offer a third opinion?
P.S I'm the one that wrote https://www.copetti.org/writings/consoles/playstation which is referenced at the bottom of the article (the 'Other reading'), I'm glad the author found it helpful (or interesting)!
So, like, the vertexes are in the right spots, but the texture mapping is off. So it kinda depends on if you need texture mapping to be perspective correct to consider a given example of 3D "real" vs "fake". Dark Forces also has perspective warping that happens in it's engine when you look up/down, as an example.
* https://youtu.be/VutzIK3DqZE?t=341 DF Retro analyzes ports of Tomb Raider
Great link. The artifacts are especially apparent when the walls are near the camera, for example at this timestamp: https://www.youtube.com/watch?v=VutzIK3DqZE&t=398s And note that here, the seemingly flat walls are already heavily subdivided into smaller polygons to lessen the impact of the problem. (Why they wouldn't then make use of those additional polygons to include more geometry details for free is beyond me, however.)
Wolfenstein's correct texture mapping is due to it using raycasting in a 2D plane and rendering scaled vertical strips of texture, which just happens to be perspective correct because you only ever have surfaces at 90deg angles in the vertical.
As to why those extra triangles weren't used for detailing, it's likely because that would take up extra level data. Tessellation of an existing triangle into smaller triangles doesn't.
Wolfenstein and Doom are 100% correct because Carmack 'cheated' by deciding to never look down/up or draw slopes :-) so whole game is drawn with 'lines of constant Z'. Or as they put it
Chris Hecker (Microsoft/Maxis/etc): that's a classic Carmack thing which is like Fuck those general problems, Im gonna solve this other problem perfectly
John Miles (ORIGIN/Miles Design/etc): Its all about not doing the math, we were still at a point in time when you won by not doing the math
I agree that all 3D is 'faked' in the sense that it's drawn to a 2D grid of lights eventually, I guess it just depends on where in the pipeline you make that fundamental transformation. I only meant faked in that the GPU itself is 2D, whereas the GTE is just math. So it's kinda like doing CSS transformations to make a web page all 3D-looking (a gross understatement I know, but, nevertheless). Though, semantically, I guess the '3D' part of a modern GPU is also 'just math'. Well now you've got me thinking about it harder...
Wonderful article by the way! I've read yours a few times myself.
In a "real 3D" rasterizer, you interpolate the depth coordinate for each individual pixel. You need this value to perform two steps in the pixel pipeline that are required to get the correct look: First, you use the depth coordinate the perform depth testing (reject pixels that should be hidden). Then, you use it to perform a perspective correct texture lookup (make straight lines on the texture obey the laws of perspective).
If you throw out the depth coordinate anywhere earlier in the pipeline, as the PS1 did, you can’t do either of those things, so you get artifacts where objects flicker and warp when rotating. The rasterizer really needs to be "3D aware" right until writing out the final pixel values.
Note that both artifacts can be lessened, to some degree at least, with workarounds. For depth testing, you simply sort the polygons (which doesn’t work in every case, as triangles can overlap in cycles). And for the texture lookup problem, you subdivide the polygons (this helps because the vertex calculations are perspective correct, but it's expensive and you'd need infinite subdivision to fully solve the problem).
As an aside, the PS1 had another issue where the rasterizer didn’t support subpixel precision, which also leads to artifacts. But IMO that’s mostly unrelated to the 3D coordinate problems — 2D games need that as well to get smooth movement.
Z-buffer is just an array of values you can sample, often as a texture. There is no inherit coordinates, unlike, say, vertices. Z-buffer is a 2d map anyway. The offset into that buffer would be the x and y.
Or do you just mean there's no hardware accelerated z-buffer?
The company I work for considers this kind of writing to be fundamental to being a considered a principal engineer. I can't imagine they invented this idea; it's probably relatively common in the startup world.
While this might not have been the author's motivation, having a popular tech blog certainly doesn't hurt one's employment prospects.
The N64 is, in a lot of ways, on paper, a more powerful system than the PS1. Better CPU, depth buffer / Z test, perspective-correct texturing, antialiasing, subpixel precision, etc. And yet the PS1 completely dominated the N64 in the marketplace and in terms of longetivity--a big part of that how cheap it is to manufacture CDs. And so people lovingly remember PS1-style graphics, but there isn't as much of a resurgence of N64-style graphics.
Another cute thing to note about PS1 is how it renders dark clouds on-screen. You might be familiar with the "add" blend mode for things like lens flares. Well, the PS1 also had a subtract blend mode, which has some unusual effects... basically, anything partially obscured by a dark cloud gets darker but also more colorful.
PS1 rendering also has a bit more charm than N64 with its affine texture warping. N64 was just blurry.
This article and output would make a great WebGL project, and they could embed real demos of it running right in the site.
What's missing that prevents us from building these types of complete projects in WebGL?
Iirc, Godot and Unity can both target WebGL.
Crosscode is pure HTML5 according to the devs. No webgl at all. Games like Quake have been ported to run in the browsers (and did so ~10 years ago).
I'm sure there are a lot more complete games out there targeting web browsers, but it isn't immediately apparent that's what they are using. A lot of the newer games I play feel like they are running in a web browser.
That said, there is an ecosystem of web games and you might be surprised by the sophistication of some of them. https://venge.io/ is a good example, try https://poki.com/ for a sampling of more. https://playcanvas.com/ is the most advanced WebGL-specific engine.
Unless a AAA studio releases a main title for web that will be true as there are no $50 web games to buy to make this come true. I'd guess most non-AAA game sales on Steam aren't near $50 though but both of those can still be extremely lucrative.
> there's no in-app purchase system
90% of browsers support the Payment Request Web API and you're also free to make your own integrations to your payment processors directly yourself (which isn't always true of consoles/app stores).
> no web gift cards in stores
You can piggyback off the traditional payment backends (e.g. Google Play) and use their cards or use your own (like game specific Roblox/Fortnite cards in stores)
> and the exploitative interstitial ad networks that enable free mobile games to make boatloads of money don't exist on the web
I don't think you saw tons of interstitial ad companies for mobile prior to having mobile games that made sense to use them either. After all it's not like the web is incapable of delivering ads it's just there is no point in delivering these types of ads without that type of content.
.
I think the real reason is distribution pains. By the time you make a games impressive enough to garner strong sales it becomes a PITA to distribute via the browser. Large amounts of persistent storage are a pain to manage in browsers (if you can even get the amount you want) and delivering an entire game or designing it to be completely streamable is a ton of cost and overhead vs just serving persistent differential app updates via traditional means. You get less control of the environment the game is run in and what you get in return is worse performance and feature capability to work with out of the gate. Compare this to any other distribution means where you're able to manage distribution, use the full capabilities of the device, and more long term stable platforms with less overhead.
Google does offer a webgame interstitial ad network. You'll need volume for this.
I've written a lot of code for PS1, Dreamcast, Gamecube, PS2, XBox 360 and PS3, and except for the last two, what they had going for them was complete, absolute predictability. Your game was effectively running in realtime mode.
In a browser, you have a lot of jitter due to things out of your control; garbage collection, cpu frequency scaling, that kind of stuff. So, you see jerkiness, and that really breaks the feel of a game.
It will take a while to polish the browser tech stack to this level, and there seems to be no market to encourage that.
While I eventually figured out that the reason my textures looked fucked up, especially in long corridors, was because they didn't take into account perspective and thus needed an extra set of per-row and per-pixel interpolations (which killed the frame rate), I actually never realized until this article that my Gouraud shading was actually suffering from the same issue because it was so much less noticeable to the eye.
IIRC games back then also used to do perspective-correct interpolation every 8 or 16 pixels, and linearly in between, which is a good compromise (you always have to interpolate U and V, what they wanted to avoid was the division, which is more expensive).
I've written about this here, https://gabrielgambetta.com/computer-graphics-from-scratch/1..., including some detailed examples of how the math works. Very fun topic :)
I didn't even think about the zbuffer and the shading when I wrote my engine - I was too preoccupied by the weirdness of the textures.
https://www.vice.com/en/article/3an385/were-in-the-beginning...
The PS1 3D games look worse when you look back at them, because they were not really the next logical increment of 2D gaming, but the first step into 3D. So more like the Pong, Asteroids, etc of the 3D era. They were exciting at the time as a glimpse of where things were going, but objectively they looked pretty bad.
I know that's what the developers claim, but the game looks so much better than a PS1 game. The only PS1 aesthetic the game can honestly claim to have is low-res textures. It doesn't have the weird texture warping, shallow draw distances, rigid animations, or really anything else that we associate with the PS1.
Video Review: https://www.youtube.com/watch?v=-jaTKi-1rz4
I made an internal "cel-shading" tech demo back in 1998, tracking the polygon edges and then using line primitives to outline the objects but there was no game to apply it to.
There were bump/normal mapping demos around then too, where a palette entry was assigned to a vector (so 256 vectors max), lit, and the texture applied additively (or subtractively).
On a personal project attempting a mesh shader like approach (although you can say it's really a PS2 VU1 workflow) to transform and sort a cluster on scratchpad, then triple buffer the output in memory, ready to be kicked off to the GPU in slice mode. It might end up slower than the old brute-force OTZ approach but it's fun to figure this stuff out.
I'm not sure what tools were used to achieve the look, but the outcome is great.
It’s such a cool aesthetic, I’m surprised it hasn’t ‘caught on’ yet as a modern design fad.
He brought up an interesting point: One thing that made for example Silent Hill extra scary, was the janky PS1 graphics.
Oh yes I've been waiting for this!
As for developing directly for the PS1 there are many practical reasons not to, like ease of development and actually being able to release/sell your game on modern storefronts
e.g around 1:47, the tunnel walls go zigzag in a very obvious way but the effect is present in most textures, only more subtle https://youtu.be/WLJqWtnFkdY
I’ve considered doing this —digging out PS1 homebrew tools and targeting libRetro. I even worked on PS1 games just a bit a long time ago.
Then I looked at actually doing it and, oh man, it’s a lot of work to get started! If I was a younger man with more free time I could pull it off. But, at the moment I need to keep my side projects smaller scope.
As far as OP goes, setting up a renderer like this requires digging out some unusual techniques. But, they aren’t hard to implement once you figure them out. And, then you can go back to the speed and convenience of modern gamedev environments.
The PS1 has 2MB RAM. The average consumer laptop these days has 8GB. My dev laptop has 16GB. And that's just RAM. Video memory, similarly; allows us a lot more physical space in our game areas while still retaining this aesthetic, if we choose - it allows more enemies, or objects on the screen...more complexity in AI, etc, etc.
None of these have to do with the visual aesthetic, but are all previously creative restrictions we no longer have to deal with as creators.
I'm a Homebrew dev for the SEGA Saturn, whose architecture is actually way more of a pain in the ass to dev for than the PS1 ever was - but I do it specifically for the challenge and joy of learning the ins and outs of the hardware.
That being said - in no way would I want to take on a project specifically for that architecture, especially because; if the project is successful in any way - porting it to another platform would be a nightmare.
Much better to use something like Unity, or - if you're a 'total control' kinda person, SDL, etc.
I use Unity extensively and adding a PS1 filter to an existing game takes a 15$ asset. The only real downside is your stuck in the Unity verse.
I would absolutely love for Godot to have a robust asset store ( yes paid assets , I've no problem paying for good code ). Let's hope Godot 4 is nice.
Unity just works for me. Whatever works for you is great. I have never once found the 'Unity-verse' to limit or hamper my creativity or ability to do anything I wanted, and; in fact, have found it more empowering than the dozens of other game IDE's I've worked with in 20+ years of game dev. Since Unity provides me with more than I could possibly need for myself; and I've been using it since I had it on my PowerMac G5 back when that was still a thing - I never foresee myself swapping IDE's for any reason. Especially with a backlog of 10+ years of projects backed up.
Can you explain this, you have games planned ?
>Especially with a backlog of 10+ years of projects backed up.
For better or worse, that project is going to require a decent budget to organize, as hardware is a big part of some of the subprojects. Unity is at the core of both the interactive and less interactive aspects of the project.
It'll need to be pretty much a full-time gig for 6-9 months to pull off the stability the project will require to be safely scaled to the mammoth size it'll need to be.
Knowing that, I've saved dozens of prototypes over the years which represent different important iterations of the technology, and as technology grows some of those demos and ideas become more or less important.
I expect this year I'll finally have the finances to truly get started on some serious demos with the expectation/assumption that I will actually be going into full-time development shortly after the releases of the demos - I expect the demos to be fairly mind-blowing if executed better than they were able to due to technological and budget limitations, say - 5 years ago; and I've held out on speaking to investors or doing crowdfunding until I absolutely knew everything was there.
Since...well, the main chunk of this project has always been...not a video game - Unity allowed me the environment to create, I guess...something incredibly unique, because it was more of a sandbox to me than a game engine. I'm interested to see where I can take the project when I'm not hampered by the tech.
I'm considering taking off a few months myself to finish my side projects.
Highly recommend the Haunted PS1 Game Demo Disc 2021[0] if you're into horror, indie games, and the PS1 aesthetic.