Sample images. From left to right:
- The Sierpinski Triangle, a well known fractal.
- A flame fractal I created for a project in a parallel computing class.
- Another flame fractal I created while testing color implementation.
Flame fractals are fractals created by certain iterated function systems. They were created by Scott Draves in 1992. See his paper here: https://flam3.com/flame_draves.pdf. He also has a software called flam3 which is the main inspiration for writing this renderer. You can find it here: https://github.com/scottdraves/flam3.
Flame fractals are based on iterated function systems. They are typically
considered in 2 dimensions for an image, but can be generalized to higher
dimensions. In
In 2D, we have functions
Flame fractals can be rendered with color. This is done by assigning colors to each function and blending them with exponential weighting so that the pixels are colored according to which functions are most associated with that part of the image. There is a lot of complexity in methods used to render images with good appearance.
The functions
I initially created this because I wanted to create the probability distribution buffer and then render images based on that with various post-processing and filtering algorithms. Since the probability distribution buffer is the most computationally expensive part to generate, it makes sense to save its results and spend more effort optimizing its computation.
It expanded a bit when I decided to write a whole renderer that I would try to optimize decently, although that is difficult to do when trying to support arbitrary functions to be specified in JSON files and when most of the runtime depends on random access to a large area of memory. I ended up switching from C to C++ and making the whole thing templated to be able to support different compile time parameters while maintaining good performance.
Another reason was interest in exploring 3D flame fractals. Higher dimensions are supported, but no tools have been created for displaying the results in a meaningful way yet.
Flames fractals for this software are specified in JSON. See the example flames for a good idea of how to write them. Comments are allowed in JSON files used for this program.
The JSON format documentation needs to be improved, especially to show details about all the variation functions.
Make sure you have the following Ubuntu packages installed (or equivalent on other distros)
build-essential
(formake
andg++
)wget
libboost-program-options-dev
(orlibboost-all-dev
)libpng-dev
As of the time of writing this, there is a known issue with Boost 1.74 (which comes from the Ubuntu repositories) where it will not compile with C++20 (which is required for this project). In order to resolve this, install the latest version of boost. The following commands are based on this link: https://www.baeldung.com/linux/boost-install-on-ubuntu
mkdir -p boost/
cd boost
wget https://boostorg.jfrog.io/artifactory/main/release/1.84.0/source/boost_1_84_0.tar.bz2
tar -xvf boost_1_84_0.tar.bz2
cd boost_1_84_0/
./bootstrap.sh
./b2
sudo ./b2 install --prefix=/usr/local
Then if everything is setup correctly, running make all
should build 2
executables, described below.
For development, static linking should be avoided because Valgrind will show memory errors when glibc is statically linked. The solution I have for now is to install Boost 1.84 locally so it can be used with dynamic linking.
This was only tested on Ubuntu 20.04 and 22.04 since I only use Ubuntu for development. Help to expand this section to support other systems would be appreciated.
Currently there are 2 executables: ffr-buf.out
and ffr-img.out
. The first
renders a buffer, which can have a number of dimensions specified. The second
is a basic implementation that renders an image from 2D buffers only.
The options for ffr-buf.out
are:
-h,--help
help message
-f,--flame
flame JSON file (required), or -
for stdin
-i,--input
specify input buffers (can be used to add more rendering progress
to an existing buffer), used once per input file, -
for stdin
-o,--output
output file (required), or -
for stdout
-s,--samples
number of samples to render, default is 0 (no rendering)
-t,--threads
threads for multithreading, default is the number of logical
CPU cores
-b,--batch_size
number of samples per thread work unit, if 0 or unspecified
then a reasonable size is calculated, larger means less overhead
-z,--bad_values
number of bad values allowed before render terminates,
default is 16, bad values are indicative of degenerate flame parameters
The options for ffr-img.out
are:
-h,--help
help message
-f,--flame
flame JSON file (required), or -
for stdin
-i,--input
input buffers, need at least 1, usue -
for stdin
-o,--output
output file, PNG images only for now
-y,--gamma
gamma parameter for adjusting overall brightness
-m,--monochrome
binary image (white = nonzero histogram)
-g,--grayscale
grayscale image from log scaling the histogram
-c,--color
color image using 3D color vectors for RGB only for now
-b,--bits
bit depth per channel for gray/color (8 or 16, default 8)
Render a flame with 1000000 samples and save the buffer.
ffr-buf.out -f flame.json -o flame.buf -s 1000000
Add 1000000 rendering samples to an existing buffer.
ffr-buf.out -f flame.json -i flame1.buf -o flame2.buf -s 1000000
Render a grayscale image based on a buffer file using gamma=2.
ffr-img.out -f flame.json -i flame.buf -o flame.png -g -y 2
Perform a single threaded render and directly feed the buffer with stdout/stdin to render a color image with gamma=2.5.
ffr-buf.out -f flame.json -o - -s 1000000 -t 1 | ffr-img.out -f flame.json -i - -o flame.png -c -y 2.5