Skip to content

Commit

Permalink
V4.1
Browse files Browse the repository at this point in the history
  • Loading branch information
angeluriot committed Oct 18, 2022
1 parent 3b645c9 commit 6a510e3
Show file tree
Hide file tree
Showing 18 changed files with 240 additions and 88 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# 2D fractals generator

![Release](https://img.shields.io/badge/Release-v4.0-blueviolet)
![Release](https://img.shields.io/badge/Release-v4.1-blueviolet)
![Language](https://img.shields.io/badge/Language-C%2B%2B-0052cf)
![Libraries](https://img.shields.io/badge/Libraries-Dimension3D_OpenCL-00cf2c)
![Size](https://img.shields.io/badge/Size-227Mo-f12222)
![Open Source](https://badges.frapsoft.com/os/v2/open-source.svg?v=103)

<br/>

This program generate images of fractals like the Mandelbrot set, the Julia set, the Birning Ship, the Buddhabrot or Newton fractals.
This program generate images of fractals like the Mandelbrot set, the Julia set, the Burning Ship, the Buddhabrot or Newton fractals.

<br/>

Expand All @@ -25,6 +25,7 @@ This program generate images of fractals like the Mandelbrot set, the Julia set,
# Summary

* **[Summary](#summary)**
* **[Video](#video)**
* **[Features](#features)**
* **[Install](#install)**
* [Skeleton project install](#skeleton-project-install)
Expand All @@ -40,14 +41,22 @@ This program generate images of fractals like the Mandelbrot set, the Julia set,

<br/>

# Video

Here is a video explaining how the algorithm works : **[Comment Générer des Fractales ? ❄️](https://www.youtube.com/watch?v=wUlVFYJIUNA)**.

<br/>

# Features

* It can generate the Mandelbrot set, the Julia set, the Birning Ship, the Buddhabrot or Newton fractals
* It can generate the Mandelbrot set, the Julia set, the Burning Ship, the Buddhabrot or Newton fractals

* A menu to choose the fractal to generate and the parameters

* An interactive 2D camera to move and zoom in the fractal

* Save screens with F2

<br/>

# Install
Expand Down
8 changes: 4 additions & 4 deletions imgui.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[Window][InvisibleWindow]
Pos=0,0
Size=1440,810
Size=1920,1080
Collapsed=0

[Window][Menu]
Expand Down Expand Up @@ -29,10 +29,10 @@ Size=230,676
Collapsed=0

[Window][Simulation settings (F1 to hide)]
Pos=25,26
Size=277,472
Pos=35,24
Size=266,531
Collapsed=0

[Docking][Data]
DockSpace ID=0xF442860A Window=0xD8117908 Pos=0,0 Size=1440,810 CentralNode=1 Selected=0x18B8C0DE
DockSpace ID=0xF442860A Window=0xD8117908 Pos=0,0 Size=1920,1080 CentralNode=1 Selected=0x18B8C0DE

Binary file modified resources/misc/Buddhabrot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
90 changes: 50 additions & 40 deletions shaders/compute/cl_compute_shader.cl
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ real_t argument_from_modulus(real2_t z, real_t mod)
if (mod == 0.)
return 0.;

if (z.y >= 0.f)
if (z.y >= 0.)
return acos(z.x / mod);

else
Expand Down Expand Up @@ -136,16 +136,17 @@ float4 get_color(float iterations, float max_iterations, float4* pallet, int col
}

__kernel void julia(__global float4* pixels, float c_r, float c_i, int max_iterations, real_t position_x, real_t position_y,
real_t width, real_t height, __global float4* pallet, int colors_nb, int smooth)
real_t width, real_t height, __global float4* pallet, int colors_nb, float color_range, float color_shift, int smooth)
{
real2_t number = (real2_t)(0.f, 0.f);
real2_t number = (real2_t)(0., 0.);
real2_t c = (real2_t)(c_r, c_i);
real2_t temp = (real2_t)(0.f, 0.f);
real2_t temp = (real2_t)(0., 0.);
int i = 0;
float4 color = (float4)(0.f, 0.f, 0.f, 0.f);
float color_mod = (float)max_iterations * 0.01f * color_range;

number.x = ((real_t)get_global_id(0) / (real_t)get_global_size(0)) * width + position_x - width / 2.;
number.y = ((real_t)(get_global_size(1) - 1 - get_global_id(1)) / (real_t)get_global_size(1)) * height - position_y - height / 2.;
number.y = ((real_t)(get_global_size(1) - 1 - get_global_id(1)) / (real_t)get_global_size(1)) * height + position_y - height / 2.;
real_t smooth_value = exp(-length(number));

float max_modulus;
Expand All @@ -159,27 +160,30 @@ __kernel void julia(__global float4* pixels, float c_r, float c_i, int max_itera
{
temp = number;
number.x = temp.x * temp.x - temp.y * temp.y + c.x;
number.y = 2.f * temp.x * temp.y + c.y;
number.y = 2. * temp.x * temp.y + c.y;
i++;
smooth_value += exp(-length(number));
}

int shifted_i = (int)(i + color_shift * (int)((float)max_iterations / color_mod)) % max_iterations;
real_t shifted_smooth_value = (int)(floor(smooth_value) + color_shift * (int)((float)max_iterations / color_mod)) % max_iterations + (smooth_value - floor(smooth_value));

if (i == max_iterations)
color = (float4)(0.f, 0.f, 0.f, 1.f);
else if (colors_nb == -1)
color = get_color(i % 6, 6, pallet, 6);
else if (colors_nb == -2)
color = get_color(i % 2, 2, pallet, 2);
else if (smooth == 1)
color = get_color(modulo((float)smooth_value, (float)max_iterations / 10.f), (float)max_iterations / 10.f, pallet, colors_nb);
color = get_color(modulo((float)shifted_smooth_value, (float)max_iterations / color_mod), (float)max_iterations / color_mod, pallet, colors_nb);
else
color = get_color(i % (max_iterations / 10), max_iterations / 10, pallet, colors_nb);
color = get_color(shifted_i % (max_iterations / (int)color_mod), max_iterations / (int)color_mod, pallet, colors_nb);

pixels[get_global_id(1) * get_global_size(0) + get_global_id(0)] = color;
}

__kernel void mandelbrot(__global float4* pixels, int max_iterations, real_t position_x, real_t position_y,
real_t width, real_t height, __global float4* pallet, int colors_nb, int smooth)
real_t width, real_t height, __global float4* pallet, int colors_nb, float color_range, float color_shift, int smooth)
{
real2_t number = (real2_t)(0., 0.);
real2_t c = (real2_t)(0., 0.);
Expand All @@ -188,9 +192,10 @@ __kernel void mandelbrot(__global float4* pixels, int max_iterations, real_t pos
float4 color = (float4)(0.f, 0.f, 0.f, 0.f);
real_t mod = (real_t)(0.);
real_t arg = (real_t)(0.);
float color_mod = (float)max_iterations * 0.01f * color_range;

c.x = ((real_t)get_global_id(0) / (real_t)get_global_size(0)) * width + position_x - width / 2.;
c.y = ((real_t)(get_global_size(1) - 1 - get_global_id(1)) / (real_t)get_global_size(1)) * height - position_y - height / 2.;
c.y = ((real_t)(get_global_size(1) - 1 - get_global_id(1)) / (real_t)get_global_size(1)) * height + position_y - height / 2.;

float max_modulus;

Expand All @@ -203,11 +208,13 @@ __kernel void mandelbrot(__global float4* pixels, int max_iterations, real_t pos
{
temp = number;
number.x = temp.x * temp.x - temp.y * temp.y + c.x;
number.y = 2.f * temp.x * temp.y + c.y;
number.y = 2. * temp.x * temp.y + c.y;
i++;
}

float smooth_value = (float)i + 1. - log(log(length(number))) / log(2.);
int shifted_i = (int)(i + color_shift * (int)((float)max_iterations / color_mod)) % max_iterations;
real_t shifted_smooth_value = (int)(floor(smooth_value) + color_shift * (int)((float)max_iterations / color_mod)) % max_iterations + (smooth_value - floor(smooth_value));

if (i == max_iterations)
color = (float4)(0.f, 0.f, 0.f, 1.f);
Expand All @@ -216,24 +223,25 @@ __kernel void mandelbrot(__global float4* pixels, int max_iterations, real_t pos
else if (colors_nb == -2)
color = get_color(i % 2, 2, pallet, 2);
else if (smooth == 1)
color = get_color(modulo(smooth_value, (float)max_iterations / 10.f), (float)max_iterations / 10.f, pallet, colors_nb);
color = get_color(modulo(shifted_smooth_value, (float)max_iterations / color_mod), (float)max_iterations / color_mod, pallet, colors_nb);
else
color = get_color(i % (max_iterations / 10), max_iterations / 10, pallet, colors_nb);
color = get_color(shifted_i % (max_iterations / (int)color_mod), max_iterations / (int)color_mod, pallet, colors_nb);

pixels[get_global_id(1) * get_global_size(0) + get_global_id(0)] = color;
}

__kernel void burning_ship(__global float4* pixels, int max_iterations, real_t position_x, real_t position_y,
real_t width, real_t height, __global float4* pallet, int colors_nb, int smooth)
real_t width, real_t height, __global float4* pallet, int colors_nb, float color_range, float color_shift, int smooth)
{
real2_t number = (real2_t)(0.f, 0.f);
real2_t c = (real2_t)(0.f, 0.f);
real2_t temp = (real2_t)(0.f, 0.f);
real2_t number = (real2_t)(0., 0.);
real2_t c = (real2_t)(0., 0.);
real2_t temp = (real2_t)(0., 0.);
int i = 0;
float4 color = (float4)(0.f, 0.f, 0.f, 0.f);
float color_mod = (float)max_iterations * 0.01f * color_range;

c.x = ((real_t)get_global_id(0) / (real_t)get_global_size(0)) * width + position_x - width / 2.;
c.y = ((real_t)(get_global_size(1) - 1 - get_global_id(1)) / (real_t)get_global_size(1)) * height - position_y - height / 2.;
c.y = -(((real_t)(get_global_size(1) - 1 - get_global_id(1)) / (real_t)get_global_size(1)) * height + position_y - height / 2.);

float max_modulus;

Expand All @@ -248,11 +256,13 @@ __kernel void burning_ship(__global float4* pixels, int max_iterations, real_t p
number.y = fabs(number.y);
temp = number;
number.x = temp.x * temp.x - temp.y * temp.y + c.x;
number.y = 2.f * temp.x * temp.y + c.y;
number.y = 2. * temp.x * temp.y + c.y;
i++;
}

float smooth_value = (float)i + 1. - log(log(length(number))) / log(2.);
int shifted_i = (int)(i + color_shift * (int)((float)max_iterations / color_mod)) % max_iterations;
real_t shifted_smooth_value = (int)(floor(smooth_value) + color_shift * (int)((float)max_iterations / color_mod)) % max_iterations + (smooth_value - floor(smooth_value));

if (i == max_iterations)
color = (float4)(0.f, 0.f, 0.f, 1.f);
Expand All @@ -261,67 +271,67 @@ __kernel void burning_ship(__global float4* pixels, int max_iterations, real_t p
else if (colors_nb == -2)
color = get_color(i % 2, 2, pallet, 2);
else if (smooth == 1)
color = get_color(modulo(smooth_value, (float)max_iterations / 10.f), (float)max_iterations / 10.f, pallet, colors_nb);
color = get_color(modulo(shifted_smooth_value, (float)max_iterations / color_mod), (float)max_iterations / color_mod, pallet, colors_nb);
else
color = get_color(i % (max_iterations / 10), max_iterations / 10, pallet, colors_nb);
color = get_color(shifted_i % (max_iterations / (int)color_mod), max_iterations / (int)color_mod, pallet, colors_nb);

pixels[get_global_id(1) * get_global_size(0) + get_global_id(0)] = color;
}

void set_pixel(float4* pixels, int2 pos, int2 screen_size, int color_id, int max_iterations, float brightness)
void set_pixel(float4* pixels, int2 pos, int2 screen_size, int i, int max_iterations, int nb_points, float brightness)
{
if (pos.x >= 0 && pos.x < screen_size.x && pos.y >= 0 && pos.y < screen_size.y)
{
if (color_id == 0)
pixels[pos.y * screen_size.x + pos.x].x += brightness / (float)(max_iterations);
else if (color_id == 1)
pixels[pos.y * screen_size.x + pos.x].y += (brightness / (float)(max_iterations)) / 4.f;
if (i <= max_iterations / 100)
pixels[pos.y * screen_size.x + pos.x].z += (brightness * 55000.f) / nb_points;
else if (i <= max_iterations / 10)
pixels[pos.y * screen_size.x + pos.x].y += (brightness * 50000.f) / nb_points;
else
pixels[pos.y * screen_size.x + pos.x].z += (brightness / (float)(max_iterations)) / 16.f;
pixels[pos.y * screen_size.x + pos.x].x += (brightness * 70000.f) / nb_points;
}
}

__kernel void buddhabrot(__global float4* pixels, __global real2_t* points, int max_iterations, real_t position_x,
__kernel void buddhabrot(__global float4* pixels, __global real2_t* points, int max_iterations, int nb_points, real_t position_x,
real_t position_y, real_t width, real_t height, int color_id, int2 screen_size, float brightness)
{
real2_t number = (real2_t)(0.f, 0.f);
real2_t number = (real2_t)(0., 0.);
real2_t c = points[get_global_id(0)];
real2_t temp = (real2_t)(0.f, 0.f);
real2_t temp = (real2_t)(0., 0.);
int i = 0;
float4 result = 0.f;
int2 pos = (int2)(0, 0);

while (modulus_2(number) < 4.f && i < max_iterations)
while (modulus_2(number) < 4. && i < max_iterations)
{
temp = number;
number.x = temp.x * temp.x - temp.y * temp.y + c.x;
number.y = 2.f * temp.x * temp.y + c.y;
number.y = 2. * temp.x * temp.y + c.y;
i++;
}

number = (real2_t)(0.f, 0.f);
number = (real2_t)(0., 0.);
c = points[get_global_id(0)];
temp = (real2_t)(0.f, 0.f);
temp = (real2_t)(0., 0.);

if (i < max_iterations - 3)
{
i = 0;

while (modulus_2(number) < 4.f && i < max_iterations)
while (modulus_2(number) < 4. && i < max_iterations)
{
temp = number;
number.x = temp.x * temp.x - temp.y * temp.y + c.x;
number.y = 2.f * temp.x * temp.y + c.y;
number.y = 2. * temp.x * temp.y + c.y;
i++;

if (i > 3)
{
pos.x = (int)(((number.x + width / 2. - position_x) / width) * (real_t)screen_size.x);
pos.y = screen_size.y - 1 - (int)(((number.y + height / 2. + position_y) / height) * (real_t)screen_size.y);
set_pixel(pixels, pos, screen_size, color_id, max_iterations, brightness);
set_pixel(pixels, pos, screen_size, i, max_iterations, nb_points, brightness);

pos.y = screen_size.y - 1 - (int)(((-number.y + height / 2. + position_y) / height) * (real_t)screen_size.y);
set_pixel(pixels, pos, screen_size, color_id, max_iterations, brightness);
set_pixel(pixels, pos, screen_size, i, max_iterations, nb_points, brightness);
}
}
}
Expand All @@ -345,7 +355,7 @@ __kernel void newton_1(__global float4* pixels, int max_iterations, real_t posit
float4 color = (float4)(0.f, 0.f, 0.f, 0.f);

x.x = ((real_t)get_global_id(0) / (real_t)get_global_size(0)) * width + position_x - width / 2.;
x.y = ((real_t)(get_global_size(1) - 1 - get_global_id(1)) / (real_t)get_global_size(1)) * height - position_y - height / 2.;
x.y = ((real_t)(get_global_size(1) - 1 - get_global_id(1)) / (real_t)get_global_size(1)) * height + position_y - height / 2.;

while (d_min > threshold && i < max_iterations)
{
Expand Down Expand Up @@ -392,7 +402,7 @@ __kernel void newton_2(__global float4* pixels, int max_iterations, real_t posit
float4 color = (float4)(0.f, 0.f, 0.f, 0.f);

p_3.x = ((real_t)get_global_id(0) / (real_t)get_global_size(0)) * width + position_x - width / 2.;
p_3.y = ((real_t)(get_global_size(1) - 1 - get_global_id(1)) / (real_t)get_global_size(1)) * height - position_y - height / 2.;
p_3.y = ((real_t)(get_global_size(1) - 1 - get_global_id(1)) / (real_t)get_global_size(1)) * height + position_y - height / 2.;

real_t d_1 = (real_t)(length(p_1));
real_t d_2 = (real_t)(length(p_2));
Expand Down
13 changes: 9 additions & 4 deletions sources/Simulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Fractal* Simulator::fractal;
double Simulator::area_width;
std::array<double, 2> Simulator::position;
bool Simulator::moving_point;
bool Simulator::image_done;

void Simulator::init()
Expand All @@ -17,6 +18,8 @@ void Simulator::init()

void Simulator::reset()
{
dim::Window::set_cull_face(false);
moving_point = false;
area_width = 5.;
position = { 0., 0. };
fractal->reset();
Expand All @@ -26,17 +29,20 @@ void Simulator::reset()
std::array<double, 2> Simulator::screen_to_world(dim::Vector2int pos)
{
double area_height = area_width * ((double)dim::Window::get_size().y / (double)dim::Window::get_size().x);

double x = (((double)pos.x / (double)dim::Window::get_size().x) - 0.5) * area_width + position[0];
double y = -((((double)pos.y / (double)dim::Window::get_size().y) - 0.5) * area_height - position[1]);
double y = (((double)(dim::Window::get_size().y - pos.y) / (double)dim::Window::get_size().y) - 0.5) * area_height + position[1];

return { x, y };
}

dim::Vector2int Simulator::world_to_screen(std::array<double, 2> pos)
{
double area_height = area_width * ((double)dim::Window::get_size().y / (double)dim::Window::get_size().x);

int x = (((pos[0] - position[0]) / area_width) + 0.5) * dim::Window::get_size().x;
int y = dim::Window::get_size().y - ((((pos[1] + position[1]) / area_height) + 0.5) * dim::Window::get_size().y);
int y = dim::Window::get_size().y - ((((pos[1] - position[1]) / area_height) + 0.5) * dim::Window::get_size().y);

return dim::Vector2int(x, y);
}

Expand All @@ -47,7 +53,7 @@ void Simulator::update()
dim::Vector2int mouse_pos = sf::Mouse::getPosition(dim::Window::get_window());

if (sf::Mouse::isButtonPressed(sf::Mouse::Left) && !Menu::active && mouse_pos.x >= 0 && mouse_pos.x <= dim::Window::get_size().x &&
mouse_pos.y >= 0 && mouse_pos.y <= dim::Window::get_size().y)
mouse_pos.y >= 0 && mouse_pos.y <= dim::Window::get_size().y && !moving_point && fractal->get_type() != Fractal::Type::Buddhabrot)
{
position[0] -= screen_to_world(mouse_pos)[0] - screen_to_world(prev_mouse_pos)[0];
position[1] -= screen_to_world(mouse_pos)[1] - screen_to_world(prev_mouse_pos)[1];
Expand Down Expand Up @@ -95,7 +101,6 @@ void Simulator::check_events(const sf::Event& sf_event)
if (sf_event.type == sf::Event::MouseButtonPressed && sf_event.key.code == sf::Mouse::Right && Simulator::fractal->get_type() == Fractal::Type::Mandelbrot)
{
auto pos = screen_to_world(sf::Mouse::getPosition(dim::Window::get_window()));
std::cout << pos[0] << " + " << pos[1] << "i" << std::endl;
delete fractal;
fractal = new Julia();
reset();
Expand Down
9 changes: 5 additions & 4 deletions sources/Simulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ class Simulator
{
public:

static Fractal* fractal; // The fractal to compute.
static double area_width; // The width of the area on the screen.
static std::array<double, 2> position; // The center of the area on the screen.
static bool image_done; // True if the image is computed.
static Fractal* fractal; // The fractal to compute.
static double area_width; // The width of the area on the screen.
static std::array<double, 2> position; // The center of the area on the screen.
static bool moving_point; // True if the user is moving a Newton's point.
static bool image_done; // True if the image is computed.

/**
* @brief Initialize the simulation.
Expand Down
Loading

1 comment on commit 6a510e3

@S0K0lAN
Copy link

@S0K0lAN S0K0lAN commented on 6a510e3 Nov 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sin shlyuxi

Please sign in to comment.