The (smooth) Mandelbrot Set
After experimenting with ChatGPT to create fractal generators, I decided to make one myself. I did so with the help of a wikipedia article called "Plotting the Mandelbrot Set". If you're new to coding and looking for a fun, low effort/high reward project to work on I'd definitively give the Mandelbrot set a try, I've attempted to make a tutorial on the bottom of the page. This is my most polished, and longest running project I've been working on, and also the only fun one :).
Controls
Arrow keys/drag the mouse to move
Q/E to zoom in/out
+/- to in/decrease the maximum amount of iterations
A/Z to in/decrease samples
B to toggle biomorphs
[/] to change the biomorph value
O/P to in/decrease the bailout value
S to toggle smooth coloring
R to "respawn"
1/2/3/4/5 to change fractal
Tap/hold J to explore julia sets
U/I to downscale the image
F11 to toggle fullscreen
Compile with:g++ mandel.cpp -o mandel -lGL -lGLU -lglut -Ofast
How it works
So, the general idea of plotting the mandelbrot set is to run the formula "z=z^2+c" for a limited amount of iterations, for every pixel. The variables "z" and "c" are complex numbers. Z is initialized to be (0,0i), and c is a certain value, like a coordinate grid. To do this in code without using complex numbers, but simple numbers, is quite tricky. People have found a way to do it, I put it in the tutorial below. I am not quite sure how it works, but it sure does :).
How to plot the Mandelbrot set using C++/openGL glut.h
What you get if you follow the tutorial/copy the code
This small tutorial thing was only tested on Linux. Small modifications might be neccesary for Windows/macOS. On Linux, first install some dependencies with (for Debian based systems with Aptitude): sudo apt install gcc g++ freeglut3-dev
This command installs openGL glut, a long obsolete package but I like it for its decent simplicity.
Start your program with this basic OpenGL start project code: (I personally use this code for any new project)
#include <GL/glut.h> // Includes openGL
#include <cmath> // Needed for some math functions later
const int WIDTH=800,HEIGHT=600; // Define your resolution.
void display(){ // Display function. This
glBegin(GL_POINTS);
for (int x = 0; x < WIDTH; x++) {
for (int y = 0; y < HEIGHT; y++) {
// Drawing logic will be implemented here later.
glColor3f(0.5,0.5,0.5); // Temporary gray color
glVertex2i(x,y); // Plots the pixel.
}
}
glEnd(); // | Writes the plotted pixels to the display
glFlush();// |
}
int main(int argc, char** argv){
glutInit(&argc,argv); // Inits OpenGL
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(WIDTH,HEIGHT); // Sets the window size
glutCreateWindow("OpenGL Mandelbrot"); // Creates the window and gives it a name
glViewport(0, 0, WIDTH, HEIGHT); // Changes some werid openGL settings
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, WIDTH, 0, HEIGHT, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glutDisplayFunc(display); // Uses the display function to update the screen
glutMainLoop(); // Calls for the display function each frame.
}
This should output a grey window called "OpenGL Mandelbrot". Let's add some actual Mandelbrot code now.
Initialize some variables after including cmath and before the display function:
const int maxIter=250; // Higher value means more detail at higher zoom levels.
long double xPos=-3.2;
long double yPos=-2.0; // Feel free to adjust these values!
long double zoom= 150; // Zoom level. Higher is more zoomed-in
long double cReal,cImag,zReal,zImag,zrTemp,iter; // predefinitions
All of these values can be changed to modify the end-product. Now, go to the display function and modify it as follows.
void display(){
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POINTS);
for (int x = 0; x < WIDTH; x++) {
for (int y = 0; y < HEIGHT; y++) {
iter=0;
cReal=(x/zoom)+xPos; // | Maps the current pixel to a grid,
cImag=(y/zoom)+yPos; // |
zReal=0;
zImag=0;
while(iter<maxIter&&zReal*zReal+zImag*zImag<4){ // Checks if the iter value exceeds maxIter, or if the point gets out of bounds.
zrTemp=((zReal*zReal)-(zImag*zImag))+cReal; // Calculates the real part of Z
zImag=2*zImag*zReal+cImag; // Calculates the imaginary part of Z
zReal=zrTemp; // Sets zReal to the calculated value.
iter++; // Changes the iterations variable.
}
if(iter==maxIter){
glColor3f(0,0,0);}// Makes the point black if it didn't go out of bounds in the set number of maximum iterations
else{
glColor3f(10*iter/maxIter,10*iter/maxIter,10*iter/maxIter); // Makes the point a grey color
}
glVertex2i(x,y);
}
}
glEnd();
glFlush();
}
That should be it! You should have a nice mandelbrot image on your screen! I encourage you to make your own little modifications, like adding more interesting colors, or perhaps change the fractal a bit!
Some images
copyleft go steal it or something