Overview
Oak is a 3D fractal engine and renderer I’ve been working on for about 3 years. It uses a technique called ray marching to render fractal surfaces which are defined implicitly by distance fields. You can find a set of renders I’ve done with this software on my renders page.
Oak’s main window consists of a 3D ray-marched scene and a user interface which is used to manipulate the scene. Oak is data-driven, it relies heavily on human-readable text files to specify geometry, lighting, colors, saved configurations, etc. This gives users the ability to greatly extend Oak’s content space without having to modify the code.
Illumination Modes
Oak has two rendering modes, direct illumination and global illumination. Direct illumination is the typical mode you see in a lot of computer graphics, it’s easy to implement and inexpensive, but it doesn’t capture all of the real-world characteristics of light.
Global illumination is different in that it takes into account the light arriving at a point on a surface from all directions rather than from only the direction of the light source. Calculating the appearance of a fragment involves numerical integration over the hemisphere centered about the surface normal. I use a technique called path tracing which involves Monte Carlo sampling in order to approximate the definite integral. This requires multiple iterations per ray and therefore is more expensive, but it results in a much more natural look.


Geometry
Fractals are stored individually in configuration files and are loaded dynamically into the fragment shader. Each fractal file consists of a distance function in GLSL syntax and a list of variables from the distance function which can be modified through the user interface. When the application loads a fractal, it rebuilds the fragment shader and populates the user interface with sliders for each variable. These variables can then be modified in realtime.
Geometric Orbit Traps
Oak supports simple geometric orbit traps for most of the fractals. The orbit trap functions are regular distance functions with varying parameters that can be manipulated through the user interface, so they are no different in definition from the fractals themselves.




Sphere Inversion
Sphere inversion is an operation which swaps the space inside a sphere with the space outside of it via a mapping between the two spaces. On the surface of the sphere, space is unchanged by the mapping. As you approach the center of the sphere, the corresponding inverted point approaches infinity. The results in some really great effects that are hard to describe without images:

The image above is a menger sphere that has been inverted via sphere inversion. The 6 faces which normally make up the outer bounds of the cube structure are now facing inward. The interior volume of space has been turned inside out and is now the space that surrounds the object and extends to infinity!

The image above is the pseudo-kleinian fractal inverted by the same operation. Sphere inversion transforms exterior line segments into interior arcs, which is why it produces such nice results for this particular fractal. In its uninverted form, the pseudo-kleinian has repeating structures which repeat in straight lines in all three axes. When inverted, these repeating structures are warped into arcs, and what you get are the cyclical patterns seen above.
Surface Color
Oak uses configuration files to specify color gradients which can be applied to the surface of the fractal. A spherical orbit trap is used to map the gradient to the surface.

Hosek-Wilkie Sky
Oak includes the Hosek-Wilkie sky model as one of its background modes. This model attempts to predict the appearance of the sky dome given a particular sun altitude and atmospheric turbidity.
While this background mode is active, Oak changes the appearance of the primary light to simulate solar radiance under certain sky conditions. The model is fairly crude but it seems to work well enough. The corresponding Hosek-Wilkie paper on solar radiance is behind a pay wall so I haven’t had a chance to read it, and I don’t understand their C implementation well enough to be able to implement it on my own.

Fog
Oak implements fog by mixing a fragment’s color with the background color based on the fragment’s distance from the camera. The fog’s near and far planes, which represent the mixing bounds, can be manipulated from the user interface.

Reflections
Reflections are implemented by performing additional ray marches per ray which continue along the direction of reflection. The ray continues to reflect until it either hits the background or reaches the maximum number of reflections. Fragment colors are then mixed in reverse based on the reflectivity values of each surface which was hit.

Depth of Field
Oak implements physically-accurate depth of field by taking multiple samples per ray within a cone whose apex is the focal point of the camera. This method is accurate but extremely expensive, as a scene has to be rendered multiple times per ray. I’m able to get away with a few (< 10) samples while I’m manipulating the image in realtime in order to get a feel for how the final image will look. I then increase the number of samples for the final render to disk.
Initially I implemented depth of field as a screen-space operation which involved taking multiple samples of the color buffer based on the depth buffer values. Although this method is quick (quick enough to compute in realtime), it results in undesirable effects in areas of the image where there are depth discontinuities (e.g. across the edge between the fractal surface and the background).

Camera Manipulation
Oak provides an orbit camera and a flight camera.
The orbit camera is fairly basic and does not use the sphere-projection model, so it suffers from gimbal effects. Left mouse rotates, right mouse moves forward/back, and middle mouse pans.
The flight camera supports forward and back movement, left, right, up, and down strafing, and roll-rotation.
Both cameras have an optional camera speed restriction which links the speed of the camera to the distance away from the surface. This distance is calculated on the GPU, but I can read it back on the CPU by rendering it to a depth buffer. This produces a really cool effect, especially for the flight camera. The camera speed reduces as it gets closer to the surface, but by increasing the surface detail automatically as this happens, it creates the effect of a constant camera speed and a surface which never seems to arrive. The effect is very similar to the planetary landings that are being implemented in games like No Man’s Sky, and I’ve always had a suspicion that this is how they were implemented.
Direct Illumination
Lighting
Oak uses the phong lighting model and has controls for adding, removing, and changing the position, color, and strength of the lights in the scene. Lighting configurations can be saved to and loaded from configuration files.

Shadows
Shadows are produced by performing a second ray march towards the light source after an initial ray hits the surface. If we hit the surface again during the second pass, we know that the surface at that point is not in direct view of the light source and should be darkened accordingly. Fragments are partially darkened if the ray comes close to the surface without touching it, this results in soft shadows.


Ambient Occlusion
Oak uses a pseudo-ambient occlusion to darken fragments based on the the number of march iterations it takes a ray to reach the surface. This technique is a decent approximation for ambient occlusion because it is generally the case that a ray has to perform more iterations to reach secluded nooks in the surface, and these are exactly the areas that would appear darker due to light occlusion. This technique does have a side-effect, however, in that it also darkens surfaces which are not necessarily occluded but are at a steep angle relative to the direction of the ray (e.g. the outer sides of a sphere are darkened but are not occluded.) Luckily I happen to prefer the way this looks, it gives surfaces a soft shaded feel and results in an anti-aliasing effect near surface edges.


Global Illumination
Image-based Lighting
Image-based lighting naturally occurs in global illumination mode since luminance information is drawn from the background. Oak supports loading images as backgrounds, and in global illumination mode these background will contribute to appearance of the fractal’s surface. I get all of my background images from the sIBL archive, included with these images are .ibl files which sometimes specify the location of light sources. Oak loads this information as well and automatically adjusts the current light set to match the information in the .ibl file.

Oak also has the ability to cast shadows on a ground plane without rendering the ground plane itself, allowing fractals to cast shadows into the background scene. This can add a lot to the realism of the image.

Refractive Solids
Oak’s refraction model is comprised of three main principles of optics: the law of refraction, total internal reflection, and fresnel reflectivity.
Emissive Solids
Emissive solids simply contribute their color to a ray’s total luminance and trigger ray termination. If a particular emissive solid is a sphere or a box, it act as a true source of light during next event estimation.

Rendering Details
Two-Step Rendering
Oak uses a two-step rendering method. During the first pass, the scene is rendered as usual but to an offscreen buffer. During the second pass, the buffer is rendered to a quad as a texture. This method has three really nice benefits.
1) The resolution of the offscreen buffer can vary independently from the final render to the screen. Oak uses an automatic resolution adjustment by default. When the user is in the process of manipulating the scene, Oak renders at half resolution in order to keep the application responsive. When the user lets go and the scene becomes static, Oak renders at 1.5x resolution in order to produce a super-sampled anti-aliased image.
2) Oak skips the first render pass if nothing in the scene has changed, so it only needs to render the super-sampled image once before becoming responsive again.
3) We have a chance to perform image-based post processing before drawing to screen. FXAA (fast approximate anti-aliasing) and bloom calculations occur during this step.
Sub/super-sampling resolution sizes can be changed on the fly in the user interface.
Rendering To Disk
Oak has the ability to render super-high resolution images to disk. It does so by breaking the image into tiles and rendering them separately to avoid GPU timeout. After rendering all of the tiles it automatically stitches them together and places the final image in the user-specified directory.
Software Overview
I developed Oak for Windows on Visual Studio 2013/2015. I use OpenGL and GLSL for rendering, GLFW for window management, GLEW for extension management, GLM for spatial mathematics, dear imgui for the user interface, SOIL for image loading, ImageMagick for tile stitching, and tinyxml2 for XML serialization. Oak is an extension of Cedar, my OpenGL framework for quickly generating computer graphics with a user interface. The software design is object-oriented-centric, and the implementation is in modern C++11/14.
Miscellaneous
This software wouldn’t exist without all of the crucial work done by the people at fractalforums.com. I’ve been especially inspired by Tom Beddard’s work on Fractal Lab which is probably 10x cooler than Oak. Íñigo Quílez and Syntopia have also been fantastic resources. Check out any of these sites if you’re looking to get into fractal rendering.

