Freds72 3d experiments & games

Hi!
Going to capture some of my upcoming games and 3d experiments outside of Discord!

Upcoming game: Snow!
A vastly expanded port of one of my early Pico8 games, enjoy endless skiing, avoid hazards and score tricks to get coins.
playdate-20240909-223051

Experiment: Perspective Correct Texture Mapping
Hey! it's possible!
Goal was to test various options, floating point, fixed points...
Winner is clearly fixed point, doing persp. divide only every 8 pixels
ezgif-2-4424376b0c

Experiment: Quake-like Engine
I am big fan of the Quake 1 engine and really looking to make some kind of fully textured world running on Playdate.
Spent summer to get the right workflow and basic rendering code (not a game) and yes it runs between 20-30fps on device:!
xplr

Technical details:

  • Python pipeline to convert binary BSP files into a custom binary format
  • Engine decodes BSP & PVS (potentially visible sectors) to render only visible sectors back to front.
  • Mipmaping (4 levels)
  • Perpsective correct each 8 pixels
  • Supports Quake blinking lights :slight_smile:

playdate-20240831-092616

Going to post some more as game develops (finger crossed!)

Yiikes! Gifs are totally destroyed :confused:

18 Likes

The GIFs look fine for me, it depends on the device/browser/etc.

1 Like

This is all looking incredible!

hey I recognize you - you are on Discord, Choo-choo go away :rofl:

1 Like

Less shooing, more snow development!

That is super impressive! :clap:

Can you expand on the "perspective divide only once every 8 pixels" thing? How does that work?

thanks!
Say texture coordinates are (u,v).
Normal perspective correct texture mapping interpolates (uw,vw,w) where w=1/z (say over an horizontal span).
To get "back" actual texture coordinates, you need to divide by w to get (u,v) for each pixel.
Instead, I am computing (u,v) at pixel x+8 and linearly interpolating between the two sets.

Note that I did not invent that (Quake is using a 16-pixel stride for ex.)

Keep up the good work! Your previous GIFs look amazing!

Interesting topic! I dived into it more deeply and also found https://www.chrishecker.com/images/3/37/Gdmtex4.pdf, from the same era as Quake. It's written by Chris Hecker, who worked at Maxis on Spore. It mentions three other techniques:

  1. Lines of constant Z. Instead of rasterizing by scanline, you rasterize along diagonals where Z is constant. Then you can take the divide out of the loop. Of course, rasterization becomes more complicated because you've got to make sure that you don't miss any pixels. It's also terrible for subpixel accuracy, which I think starts to matter if a texel maps to significantly more than one screen pixel.
  2. Approximate the 1/z curve with a quadratic polynomial for each scanline, which replaces the divide by two adds (not even multiplies). I think it might be faster than technique 3, below, but it can fail in some cases. Maybe those can be worked around by choosing more carefully how to fit the quadratic.
  3. Approximate the 1/z curve by a piecewise linear curve. I suppose this is more or less what you're doing, and what Quake does as well. Or is that more like a piecewise constant curve (staircase)?

The rest of the article series can be found on Miscellaneous Technical Articles - Chris Hecker's Website.

same sources :grimacing:

constant-z is a pain and works well with systems with less cache issues, and indeed quality is terrible.
Did that on pico8:
image

So far the cost is really writing to a buffer - 40% of the cpu is spent writing bytes, not heavy calculation.

Going to revisit how polygons are scanned to improve cache-friendliness.

Yeah, I was wondering if cache was an issue even on the PlayDate. Apparently the tradeoffs are different compared to 1990s-era hardware.

I guess there's no way around writing individual pixels - you can't just blit larger chunks of texture. But you could accumulate an entire 32-bit aligned chunk into a register before writing it out to RAM. You're probably already doing that :smiley:

yes - what I mentioned was trying to write a full scanline before moving to the other.