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
zwithin a rectangular area, perform steps 2-3. - Compute the minimum iteration
0 < i <= MAX_Isuch that|f(f(f(...(z)))| > R. Here,fis applieditimes;Ris a positive real-valued constant (the infinity distance);MAX_Iis a positive integer constant (maximum iteration count). - Associate
zwith a color depending oni. For example,i == 1may be rendered as black,i == MAX_Ias 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 Backends.
| 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 Rendered 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
OpenClbackend. - Julia set rendering parameters.
- Backend based on Vulkan.
- Program produced by the
Vulkanbackend.
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.