crystal raytracer open source


This was an experiment in graphics programming to create a raytracer for the game Brickadia. Using a community-maintained server wrapper tool called Omegga (from which many of my small projects have spawned), I created a plugin for the game that read the server's current save (a collection of player-placed bricks, think LEGO) and used modern rendering techniques to render a raytraced image.

Sample render

This project originally started in JavaScript with Node.js, as a plugin for Omegga. This version of the raytracer could render basic scenes with small object counts, and the extent of its rendering flexibility was basic reflections and shadowing. It suffered from one major issue: performance.

I decided to rewrite the raytracer entirely in Crystal, a statically typed language that compiles to native, which in and of itself would massively boost performance. While doing so, I researched more rendering techniques like refraction, Blinn-Phong shading, lighting, mesh importing, normal maps, skyboxes, and more.

Both iterations of the raytracer were capable of converting the rendered image into a series of bricks that could be reimported back into the game world after optimization using a quadtree to merge like pixels. Below is a sample render from the original JavaScript implementation that has been imported back into the game. Notice the dark bevels around each brick. Quads become smaller in size around points of detail.

A render import from the first iteration

While the Crystal version of this project supports quadtree optimization and brick importing, I heavily moved away from it to support rendering out to a standard PNG as this iteration was capable of rendering much larger image resolutions in a fraction of the time. I implemented techniques like supersampling to experiment with high-quality images that shoot multiple rays per pixel.

Below is the most highly detailed and expensive render this raytracer has ever produced, at 1080p with 16 rays per pixel.

A highly detailed render

Extra renders

The following scene was rendered in 4K. This render took 3 minutes and 22 seconds.

A scene rendered in 4K

This scene was rendered in 1080p. It is a demonstration of the OBJ mesh importer and renderer. The image depicts the render after being imported back in-game.

A scene with a player mesh

This is a screenshot from my development environment of an early demo on lighting and normal maps. On the left is the scene built in Brickadia, and on the right is a small render of the scene.

An early scene depicting normal maps and lighting

Experimental soft shadows. First, a soft shadow accuracy is picked (we will call it n). We cast n rays towards various parts along the surface of the light. The strength of the shadow is num rays hit / n. Supersampling can be used to denoise these results, but it was not used here.

Experimental soft shadows