Skip to content

Ten-plus generations of a from-scratch renderer

One triangle became a whole rendering pipeline.

MyCustomGfx is a software renderer written from nothing but the .NET base class library - no GPU, no OpenGL, no engine, not one image file. It grew across ten-plus generations, each adding a real technique: a naive scanline raster, then a Z-buffer, an OBJ and glTF 2.0 loader, Cook-Torrance PBR, HDR with ACES, bloom, SSAO, and finally a Render Lab with eight shading curves and six presets. Every frame below was rendered fresh by the v10 command-line tool - no browser, no GPU in the loop.

10+ generations SelfTest hash 0xD90DBB81 - unchanged for 9 gens 53/53 tests, 11 suites BCL only, zero external assets ~0.8 s / 960x720 frame (CoreCLR)

The payoff - Render Lab, gen 10

One scene, eight shading curves, one rotation

Three icosahedra rotating; the shading model cycles from smooth PBR through Lambert, Toon, Banded, Sawtooth, Fresnel-rim and Holographic stripes across the spin.
GEN 10 - RENDER LAB

Pbr → Lambert → HalfLambert → Toon → Banded → Sawtooth → FresnelRim → Holographic

The audio-waveform idea applied to light: the lighting response is a swappable curve. Same three meshes, same camera, same post-processing - only the shading function on N·L changes as the scene turns. The Render Lab exposes about fifty of these knobs as live sliders; here they sweep automatically. 64 frames, 480x360, stitched with a hand-rolled palette.

The lineage - how it got there

From raw triangles to a graded frame

Three icosahedra drawn as thin green triangle edges on a black background - the bare mesh with no fill.
GEN 1-2 - RASTERIZER

naive scanline, then Pineda edge functions

Where it starts: hand-coded math primitives and a triangle rasterizer. Gen 1 filled scanlines the naive way; gen 2 replaced it with Pineda half-plane edge functions and perspective-correct interpolation - the same inner loop every later gen builds on.

The three icosahedra as near-black silhouettes on a dark field - a depth-buffer visualization where closer surfaces are darker.
GEN 2 - Z-BUFFER

per-pixel depth test

A depth buffer resolves occlusion per pixel, so overlapping meshes compose correctly regardless of draw order. This is the raw depth pass the shading and SSAO stages later read from.

Three cream-colored faceted icosahedra lit from one side by a single directional light on a gray field.
GEN 2 - LAMBERT

flat N·L directional light

The first lit render of an imported mesh: a single directional light, flat Lambert diffuse. Faces turned toward the light are bright, faces away fall to shadow. Loaded through the OBJ + MTL parser.

The icosahedra rendered in vivid rainbow colors where each facet's hue encodes its surface-normal direction.
GEN 6 - NORMALS

world-space normals, RGB-encoded

Per-face world-space normals shown as color - the geometric input the physically based BRDF needs. Each facet's XYZ normal maps straight to RGB, which is why the icosahedron reads as a spray of hues.

Three smooth gold-colored icosahedra with soft specular highlights from physically based shading on a gray field.
GEN 6 - COOK-TORRANCE PBR

GGX + Schlick-Fresnel + Smith geometry

Physically based shading: the Cook-Torrance BRDF with a GGX normal distribution, Schlick Fresnel and Smith geometry term. Metallic 0.2, roughness 0.4 - tighter highlights and a Fresnel lift at glancing angles.

Three icosahedra with a gold-and-navy checkerboard texture, softly shaded and grounded with ambient occlusion on a gray field.
GEN 7-8 - FULL PIPELINE

textured PBR + ACES + bloom + SSAO

The default look with everything on: a mip-mapped checkerboard sampled with perspective-correct UVs, ACES tone-mapping over an HDR buffer, bloom, and screen-space ambient occlusion - all fed by a glTF 2.0-ready scene graph.

The same textured icosahedra rendered warmer and moodier, with darkened corners from a vignette.
GEN 7-10 - CINEMATIC GRADE

Hable HDR tonemap + color grade + vignette

The cinematic preset: a Hable filmic tone-map, a color grade (exposure, contrast, saturation, temperature, vibrance) and a corner vignette. Same solve, a warmer and more compressed highlight rolloff.

The textured icosahedra shown through a simulated CRT: horizontal scanlines, a vignette, and a slight red-blue color fringe.
GEN 10 - CRT PRESET

scanlines + vignette + chromatic aberration

One of six Render Lab presets, all reachable in a single click. The CRT stack adds horizontal scanlines, a heavy vignette and a chromatic-aberration fringe over Lambert shading - a stylized post-process chain, not a filter over a photo.

How these were made

One binary, no browser

Every image on this page came out of the v10 mcgfx command-line tool, built and run fresh. It writes Netpbm PPM frames the engine produces itself; the turntable is a sequence stitched into a GIF. The same self-test that guards the canonical orange triangle runs on every invocation and still returns hash 0xD90DBB81.

mcgfx --all --frames 1 --width 960 --height 720 --out renders mcgfx --shading-sweep --frames 8 --width 480 --height 360 --out gif mcgfx --debug-mode wireframe --preset default # also: depth, normal