This is how it started. Rendering the floor and ceiling of a test square room in mapster. Perspective looks good.
This is the outline of the roof sector of E1L1. It was drawing both the outer and inner loops in a single line loops, so you'd get lines crossing the screen like that. At this point it was only rendering the sector where the player was.
Now it's rendering all sectors. On the right, it's the E1L1 roof crate. You can clearly see the shadow sector and the lack of slopes in the center. Far clipping plane was a little close, so nothing interesting in the distance. Polymost is still drawing the HUD, but at this point some variables aren't set correctly and this causes the 3D HUD weapons to render at weird angles.
E1L1 street. The famous crate on the right, secret apartment in the top left.
Still E1L1, cinema back door. You can see the two arcade room spotlights near the top.
Sector floor tessellation! No walls or ceilings yet, but the surfaces are properly tessellated. Still no slopes on that E1L1 roof.
More E1L1, same street scene as before.
And same cinema back door.
This wireframe shot shows the tessellation in action.
Walls and ceilings! Arbitrary solid colors for now to be able to differentiate them.
One week after the first shot, starting to look like something. Slopes still ignored.
Proper wall rendering, no holes in the map anymore.
Still no slopes, though.
Inside the secret apartment. An enemy was killing me but I obviously couldn't see it.
And a month after that, textures! Getting all the various alignment bits right was really tedious. I never looked at the Polymost code, so it involved a lot of trial and error and comparing. I still find small errors to this day.
Ceilings textures as well now. Of course the ceilings on the roof are supposed to be parallaxed, but the renderer doesn't know about that just yet.
Wall texturing, and hooked up with hightile. The cinema entrance is still buggy, though. Also, sector shade is now rendered.
And it's fixed! Note how the 1-way walls (and masks) are missing from the secret apartment windows.
First attempt at sky rendering. The red mspaint stuff illustrates how it should look, but sadly the reality differs. I still need to sort it out at some point.
Fog. Let's tone it down a little, though!
I got the sky tiles right! Too bad it's picking the wrong sky and rendering it upside down...
That's more like it. Also, fullbright tiles are rendered properly.
Polymer allows you to view a map from the outside like that. Handy in Mapster32 3D mode.
E1L1 from outside, and with the proper sky.
Half a year later, still experimenting with various hidden surface removal techniques. This illustrates a visportal-based method. Very efficient when you have a couple of portals in view, but absolutely not suited for rendering a thousand sectors at the same time.
And almost a year later, it's time to tackle sprite rendering! This is a quick hack that makes Polymost render its sprites on top of the Polymer map (just for the kicks). Of course, totally misaligned results.
Sprites! No size, no shade, no texture, nothing. They're all front-facing, too.
And ten hours after that, everything is (somewhat) properly scaled and aligned.
This is the first pass of a floor mirror.
So is this.
And now with high-res textures.
I think this was the first screenshot I showed to JonoF.
In these shots, all floors are mirrors.
This looks pretty good. Too bad the sky was in that state because I hadn't implemented high-res skyboxes at this point.
Floor mirrors suit space levels pretty well, I think.
But that's just my opinion.
A test map I came up with to experiment with mirrors.
Now ceilings are mirrors too!
And walls now! This is getting out of hand.
Lights! It took a lot of tries to get the lighting model right, but I apparently don't have any screenshots of that. The specular highlight was hardcoded to white so it looks a little weird. It also looks like I implemented models during that time.
Experimenting with a different specular highlight color. Fits the atomic health pretty well.
Hardcoded a few lights to follow projectiles. Note how lighting is just added on top of the diffuse texture while it should be affected by it.
Lighting on models! At this point, I found out that none of the models in the HRP had correct normals or bounding boxes, so I had to recalculate them by hand. The material is hard-coded and way too shiny, but it's the least of my worries at this point.
More shiny troopers.
The shiny material fits quite well on the frozen trooper.
Two light sources lighting the same model. Back then, it was all done in a single pass. I since had to change it to multi-pass since cards that didn't have Shader Model 4 couldn't handle all the branching and long programs.
I like this shot.
This is supposed to be normal mapped, but I apparently got the texture-tangent basis calculation wrong. The texture is the first set I could find when searching for "normal map" on Google.
Still wrong, although it's getting closer. I only had a component inverted at that point, I think.
And it works! Still shiny, though.
I had some debug code to draw sprite normals enabled, I think. You can see a little RGB basis next to the shrinker blast.
And here next to the tripbomb and its laser.
And the blood too.
This is a floor mirror with a per-pixel perturbation based on a normal map texture.
So is this. I think I had the rock normal map applied to all the textures at this point, so it looks horribly out of place.
Spotlights and shadows on a test map.
And in E1L1.
Had the explosions emit extra-large and wide spotlights to stress the sampling a little. Also had a flashlight emitting another shadow and a normal map on the floor. I think Parkar made that normal map for the HRP concrete texture after I showed him Polymer.
Some sprites were showing up in grayscale because of a bug I never was able to track down. It just stopped happening at some point, though.
Testing specular maps on mirrors. The RGB channel modulates the reflection color and the alpha channel changes the mirror opacity per pixel. That's how you can have colored and opaque tiles. There's also a normal map that perturbs the reflection. Parkar made both.
Parallax mapping. Looks especially good on this heightmap Parkar made.
Comparison between Polymer...
... and Polymost. It does look flatter.
Starting to stage the infamous bathroom shot. First a single spotlight to make sure that the maphacks work.
More lights, more static enemies.
Added a laser, a muzzleflash spotlight for the dude upstairs, and parallaxing on the carpet.
And here's the hardcoded wall mirror.
Texture compression made the parallaxed sink look a bit weird, so I disabled it.
This is the final scene.
This is how it looks when projecting sprite shadows.
Hardcoded room-over-room with refraction. You can see an Assault Captain underwater next to the Octabrain.
Added lights to explosions.
Added dynamic spotlights to the Recon Cars.
Normal map by Parkar.
This is an attempt to pair a normal map that Roma Loom made with the original tile. It looks somewhat good, but it's mismatched in some places.
Here's the flat tile for comparison.
E1L1 cinema room with Parkar's normal maps and lighthacks.
Looks pretty good, but the floor isn't receiving light for some reason.
A closer inspection reveals that the normal vector for this part of the floor (represented as RGB in this shot) doesn't get computed properly, causing the lighting problems.
Trying to get model rotation right, nothing to see there.
It's not obvious from this shot, but the Recon Cars are projecting textures on their spotlights.
Testing a texture by Roma Loom.
Note the specular map around the letter edges.
E1L1 street with an early version of Parkar's lighthacks.
Parkar's gorgeous texture.
Testing point and spotlight SEs from Mapster32.
This shows the window lightmap being projected on Duke's back.
First working highpalookup implementation. This highpalookup map only inverts the diffuse components.
This one inverts the G component and sets it to all three, I think.
Classic mode, pals 0, 21 and 22 for tile 857.
Polymer, test highpalookup for pal 21 on the left, hardcoded HRP replacements on the right.
And pal 22. Still needs a lot of tweaking, obviously.
Generated nightvision-ish highpalookup.
Highpalookup for pal 20 on tile 3387 on the left, pal 6 (half-assed) on tile 837 on the right
These show the effects of texture compression. This is uncompressed.
The diffuse is now DXT-compressed.
Diffuse+normal are now compressed. Ugh.
Highpalookups again, this time with pal 2. This is the software renderer in The Abyss.
Same scene using Polymer, using the regular HRP (lighting disabled for clarity).
This is using Lezing's pal 2 highpalookup map. Looks a lot more like classic. The only difference is that pal 2 becomes redder and redder as it gets shaded, and we can't replicate that (right now?).
And this is by applying the highpalookup after the diffuse modulation to leverage the full range.
How APLAYER palettes are currently handled in the HRP (some aren't).
What it looks like in software mode.
What highpal does using Lezing's generated set.
Colored fog fixed with several lights, had been broken forever.
Polymer ROR support + mirrors.
First step towards proper rendering of 8-bit tiles in a modern renderer: feed the raw ART data in a non-interpolated single-channel texture, here rendered as the red channel.
Second step: apply the first level of indirection and resolve the indices you get from ART against the currently installed palette. Cut out alpha if you get 255.
Third step: apply a second indirection in the middle that shuffles indices around, swapping some colors. For each of these lookup tables there are 32 derivative darkened levels in Duke3D, which the renderer decides how to pick depending on the current lighting conditions and per-sector attributes.
This shows why you can't just turn on texture filtering on the raw 8-bit data. Doing the interpolation in indexed space doesn't make sense since all the values generated in the middle correspond to completely different colors. If you're implementing this approach fully on the GPU you need to sample the neighbors yourself, and perform the filtering by hand after resolving the palette.
First attempt at hooking basic range fadeoff; it's spherical in the sense that it's using the 3D distance, so the fadeoff is more realistic but unlike BUILD.
Changed it to a radial fadeoff and hooked it up to sector visibility with the real BUILD algorithm. Some sprites aren't hooked up but the gist of it is there.
Sample scene of E1L5, displayed in Polymost (identical to Polymer before ART mapping).
Same scene in the software BUILD renderer.
And in Polymer, with the final version of ART mapping enabled. Casualties: texture filtering, mipmaps, aniso.