VOGONS


First post, by vvbee

User metadata
Rank Oldbie
Rank
Oldbie

A mid-90s style software 3D renderer for the HTML5 canvas. Need a clunky-looking, olden-style renderer for the browser? This is it.

https://github.com/leikareipa/retro-ngon

- Genuine obsolete software 3D rendering without WebGL
- Renders n-sided convex polygons
- Quite well documented, easy to set up
- Modern vanilla JavaScript with no dependencies
- Single-file distributable
- Blender export
- Beta

Find an interactive render sample at https://www.tarpeeksihyvaesoft.com/s/retro-ng … mb-raider-home/. Click to capture the mouse, ESDF + QS to move. May take some time to load (< 1 MB but across many files), and this particular sample may not load at all on Apple devices (I only have access to an iPad, and it doesn't want to).

Tomb Raider 1:
tr-rngon-1.png

Quake 1:
q1-rngon-4.png

Grand Prix Legends:
rngon-gpl-2.png

Last edited by vvbee on 2020-04-27, 17:14. Edited 3 times in total.

Reply 1 of 9, by xjas

User metadata
Rank l33t
Rank
l33t

Cool engine! Looks better than the stock Tomb Raider rendering. Would love to see this get used in some things.

affine.jpg
Filename
affine.jpg
File size
197.08 KiB
Views
2031 views
File license
Public domain

Nice implimentation of affine texturing. 😀

twitch.tv/oldskooljay - playing the obscure, forgotten & weird - most Tuesdays & Thursdays @ 6:30 PM PDT. Bonus streams elsewhen!

Reply 2 of 9, by vvbee

User metadata
Rank Oldbie
Rank
Oldbie
xjas wrote on 2020-04-25, 07:04:

affine.jpg
Nice implimentation of affine texturing. 😀

It's actually perspective corrected, don't know why that particular detail looks like that both in-game and in the renderer.

But you can turn off perspective correction to get pure affine as well. The game lets you do it too, and since it uses quads (or n-sided polys anyway), the effect looks a bit different than what you get with triangles.

Reply 3 of 9, by xjas

User metadata
Rank l33t
Rank
l33t

Hmm, in the Tomb Raider demo it looks like "square"/rectangular quads get rendered perspective-correctly at any angle, whereas deformed quads (at least one pair of non-parallel sides) show PS1-style warping? Does that make sense?

affine2.jpg
Filename
affine2.jpg
File size
214.22 KiB
Views
2006 views
File license
Public domain
affine3.jpg
Filename
affine3.jpg
File size
327.72 KiB
Views
2006 views
File license
Public domain

twitch.tv/oldskooljay - playing the obscure, forgotten & weird - most Tuesdays & Thursdays @ 6:30 PM PDT. Bonus streams elsewhen!

Reply 4 of 9, by vvbee

User metadata
Rank Oldbie
Rank
Oldbie

Depends on what you're after. The goal of this renderer is the opposite of rendering without errors or inconsistencies - so long as the output looks like it's held together with tape, it's doing its thing in true 90s fashion. Only those render issues that get too glaringly in the way are a problem.

It's been nearly a year since I implemented the Tomb Raider scene for this, so I can't remember the specifics, but since the software 3D engines of that era were all doing their own thing, you're probably not going to end up with a general purpose renderer that also faithfully replicates other engines without specific render paths. But rendering scenes meant for a variety of other engines is a good way to stress test yours.

I think in the Tomb Raider demo you can press F4 or F5 to toggle the perspective correction modes.

Reply 5 of 9, by vvbee

User metadata
Rank Oldbie
Rank
Oldbie

Simplest full app to render a triangle (3-gon):

<canvas id="canvas" style="width: 300px; height: 300px; background-color: black;"></canvas>
<script src="distributable/rngon.cat.js"></script>
<script>
const triangle = Rngon.ngon([Rngon.vertex(-1, -1, 3),
Rngon.vertex( 1, -1, 3),
Rngon.vertex( 1, 1, 3)]);

Rngon.render("canvas", [Rngon.mesh([triangle])]);
</script>

Reply 6 of 9, by vvbee

User metadata
Rank Oldbie
Rank
Oldbie

Beta.2 adds pixel shaders, among other things.

The repo's readme gives a good introduction to their use, and further samples are provided.

Interactive samples are at https://www.tarpeeksihyvaesoft.com/s/retro-ng … /pixel-shaders/.

Depth-aware blurring:
shader-distance-blur.png

A Quake level with a single per-pixel light source:
quake-1.png

Ray-traced shadows:
shader-ray-trace.png
Ray tracing is technically not possible with the public branch of the renderer, since shaders are given a list of the scene's clipped polygons rather than the original ones; but it demonstrates the flexibility of shaders.

Reply 7 of 9, by vvbee

User metadata
Rank Oldbie
Rank
Oldbie

A bunch of updates to this over the last four months. I think in that time we got vertex shaders, flat shading, Gouraud shading, mipmapping, benchmarks, stipple transparency, more render samples, proper point and line rasterization, threaded async rendering, lightmaps, and some other stuff.

A convenient index of render samples is now available at https://tarpeeksihyvaesoft.com/experimental/r … o-ngon/samples/. You can check out Grand Prix Legends https://tarpeeksihyvaesoft.com/experimental/r … ample=gpl-rouen, lightmaps https://tarpeeksihyvaesoft.com/experimental/r … ample=lightmaps, ray-traced lighting https://tarpeeksihyvaesoft.com/experimental/r … traced-lighting, and more.

An automated Quake benchmark with an SVG graph is at https://tarpeeksihyvaesoft.com/experimental/r … ake-1-e1m1.html. I got about 170 FPS on a 3.3 GHz Intel in Chrome.

Reply 8 of 9, by vvbee

User metadata
Rank Oldbie
Rank
Oldbie

This renderer's seen a variety of improvements and additions since three or so years ago. It's about 2-3 times faster, has new render samples, more features, etc. Check the GitHub for more info. Still in beta.

Latest interactive render samples are there: https://www.tarpeeksihyvaesoft.com/experiment … o-ngon/samples/

It's not yet been used in other peoples' retro projects that I'm aware of, but I've used it in a variety of things besides strictly 3D, like replicating a DOS game's 2.5D renderer for a track editor (https://www.tarpeeksihyvaesoft.com/rallysported/) and reproducing the Windows 95 UI (https://www.tarpeeksihyvaesoft.com/serlain/).

Can also be used for 2D tile rendering (https://www.tarpeeksihyvaesoft.com/experiment … blique-2d-tiles), path tracing (https://www.tarpeeksihyvaesoft.com/experiment … le=path-tracing), and other things.

gpl.webp
quake-bilinear.webp

Recently I've been optimizing the documentation for AI prompting, which could be a major workflow and troubleshooting boost. Right now the renderer's quick-start guide + API reference need about 8k tokens combined, so that ideally requires the full 32k GPT-4 API which many probably don't have (and you'd have to pay per token), but you can fit a useful amount of it in 4k context as well by cutting away some parts that aren't relevant.

Below's an image of first giving GPT-4 (4k context) most of the renderer's API reference and asking it to write code to convert an STL model file (exported from Blender) into the renderer's native format, then in a new session giving it the quick-start guide + some bits of the API reference and asking it for a function that renders an input mesh with the left-side polygons solid and the others wireframe. Works reasonably well though not 100% perfect, would be interesting with the full 32k context.

rngon-gpt4.png
Filename
rngon-gpt4.png
File size
105.88 KiB
Views
975 views
File license
CC-BY-4.0

Reply 9 of 9, by vvbee

User metadata
Rank Oldbie
Rank
Oldbie

Five years in, this thing is now 1.0.

That said, I'm not aware of it being used in projects other than my own, so don't expect a polished experience all around. Go check it out in production in this thing, doing custom 2.5D one-point perspective graphics for a DOS track editor.

The renderer is now more low level, aimed at intermediate/advanced JavaScript developers with familiarity in software rendering and at least 7 years of work experience as a graphics programmer.

Check out this faux legacy OpenGL API, included in the rendering samples:

function create_cube(gl)
{
console.assert(gl.GetString(gl.VERSION) === "1.1");

gl.Scalef(40, 40, 40);
gl.Rotatef(0, this.cubeRotation, this.cubeRotation);

if (this.woodTexture.$isEnabled) {
gl.BindTexture(gl.TEXTURE_2D, this.woodTexture);
}

// Back.
gl.Color3ub(64, 192, 192);
gl.Begin(gl.POLYGON);
gl.TexCoord2f(0, 0);
gl.Vertex3f(-0.5, -0.5, 0.5);
gl.TexCoord2f(1, 0);
gl.Vertex3f(0.5, -0.5, 0.5);
gl.TexCoord2f(1, 1);
gl.Vertex3f(0.5, 0.5, 0.5);
gl.TexCoord2f(0, 1);
gl.Vertex3f(-0.5, 0.5, 0.5);
gl.End();

....
}