Expand description
Julia set boundary computation and rendering.
§Theory
Informally, the Julia set for a complex-valued function f
(in Rust terms,
fn(Complex32) -> Complex32
) is a set of complex points for which an infinitely small
perturbation can lead to drastic changes in the sequence of iterated function applications
(that is, f(z)
, f(f(z))
, f(f(f(z)))
and so on).
For many functions f
, the iterated sequence may tend to infinity. Hence, the
commonly used computational way to render the Julia set boundary is as follows:
- For each complex value
z
within a rectangular area, perform steps 2-3. - Compute the minimum iteration
0 < i <= MAX_I
such that|f(f(f(...(z)))| > R
. Here,f
is appliedi
times;R
is a positive real-valued constant (the infinity distance);MAX_I
is a positive integer constant (maximum iteration count). - Associate
z
with a color depending oni
. For example,i == 1
may be rendered as black,i == MAX_I
as white, and values between it may get the corresponding shades of gray. - Render the rectangular area as a (two-dimensional) image, with each pixel corresponding
to a separate value of
z
.
This is exactly the way Julia set rendering is implemented in this crate.
§Backends
The crate supports several computational Backend
s.
Backend | Crate feature | Hardware | Crate dep(s) |
---|---|---|---|
OpenCl | opencl_backend | GPU, CPU | ocl |
Vulkan | vulkan_backend | GPU | vulkano , shaderc |
Cpu | cpu_backend | CPU | rayon |
Cpu | dyn_cpu_backend | CPU | rayon |
None of the backends are on by default. A backend can be enabled by switching
on the corresponding crate feature. dyn_cpu_backend
requires cpu_backend
internally.
All backends except for cpu_backend
require parsing the complex-valued Function
from
a string presentation, e.g., "z * z - 0.4i"
. The arithmetic-parser
crate is used for this
purpose. For cpu_backend
, the function is defined directly in Rust.
For efficiency and modularity, a Backend
creates a program for each function.
(In case of OpenCL, a program is a kernel, and in Vulkan a program is a compute shader.)
The program can then be Render
ed with various Params
.
Backends targeting GPUs (i.e., OpenCl
and Vulkan
) should be much faster than CPU-based
backends. Indeed, the rendering task is embarrassingly parallel (could be performed
independently for each point).
§Examples
Using Rust function definition with cpu_backend
:
use julia_set::{Backend, Cpu, Params, Render};
use num_complex::Complex32;
let program = Cpu.create_program(|z: Complex32| z * z + Complex32::new(-0.4, 0.5))?;
let render_params = Params::new([50, 50], 4.0).with_infinity_distance(5.0);
let image = program.render(&render_params)?;
// Do something with the image...
Using interpreted function definition with dyn_cpu_backend
:
use julia_set::{Backend, Cpu, Function, Params, Render};
use num_complex::Complex32;
let function: Function = "z * z - 0.4 + 0.5i".parse()?;
let program = Cpu.create_program(&function)?;
let render_params = Params::new([50, 50], 4.0).with_infinity_distance(5.0);
let image = program.render(&render_params)?;
// Do something with the image...
Modules§
- Post-processing transforms on Julia set images.
Structs§
- Backend that uses CPU for computations.
- Error associated with creating a
Function
. - Parsed complex-valued function of a single variable.
- Backend based on OpenCL.
- Program produced by the
OpenCl
backend. - Julia set rendering parameters.
- Backend based on Vulkan.
- Program produced by the
Vulkan
backend.
Traits§
- Complex-valued function of a single variable.
- Program for a specific
Backend
(e.g., OpenCL) corresponding to a specific Julia set. A single program can be rendered with different parameters (e.g., different output sizes), but the core settings (e.g., the complex-valued function describing the set) are fixed.
Type Aliases§
- Image buffer output by a
Backend
.