Generowanie animacji fraktala Mandelbrota z precyzją 80-bitową i SSAA
Narzędzie generuje 255 klatek zbioru Mandelbrota w formacie BMP z rozdzielczością 1920×1080 i składa je w wideo MP4 z częstotliwością 30 FPS. Integracja z FFmpeg pozwala zautomatyzować cały potok przetwarzania: od obliczeń fraktala po finalny render. Parametry FFmpeg zostały zoptymalizowane pod kątem zachowania detali: qp=20 zapewnia wysoką jakość, pix_fmt yuv420p gwarantuje kompatybilność, deblock=-6 minimalizuje artefakty kompresji.
Kluczowe opcje polecenia:
- -stream_loop 3: cztery przejścia animacji (bazowe + 3 powtórzenia)
- -framerate 30: wejściowa częstotliwość klatek
- -color_range full: pełny zakres jasności 0-255
- no-psy: wyłączenie psycho-wizualnych ulepszeń dla czystości struktur fraktalnych
Klawisze skrótów i współrzędne punktów
Program obsługuje wybór spośród 8 presetów regionów zbioru lub ładowanie parametrów z pliku Mandelbrot.txt (klawisz 9). Współrzędne są zadawane z 80-bitową precyzją (long double):
case 1: absc = -0.5503432753421602L; ordi = -0.6259312704294012L; size_val = 0.0000000000004L; break;
case 2: absc = -0.691488093510181825L; ordi = -0.465680729473216972L; size_val = 0.000000000000003L; break;
case 3: absc = -0.550345905862346513L; ordi = 0.625931416301985337L; size_val = 0.000000000000005L; break;
case 4: absc = -1.78577278039667471L; ordi = -0.00000075696313293L; size_val = 0.000000000000004L; break;
case 5: absc = -1.785772754399825165L; ordi = -0.000000756806080773L; size_val = 0.0000000000000014L; break;
case 6: absc = -1.40353608594492038L; ordi = -0.02929181552009826L; size_val = 0.000000000000095L; break;
case 7: absc = -1.7485462508265219L; ordi = 0.000002213770706L; size_val = 0.00000000000029L; break;
case 8: absc = -1.94053809966024986L; ordi = -0.00000120260253359L; size_val = 0.00000000000003L; break;
Arytmetyka 80-bitowa i FPU x87
Implementacja wykorzystuje long double do pracy z zakresem skalowania 10^18 (w przeciwieństwie do 10^14 przy double). Sprzętowe wsparcie FPU x87 zapewnia maksymalną precyzję obliczeń bez programowej emulacji. Jest to krytyczne dla głębokiego zoomu w mini-fraktale bez pikselizacji.
Zalety 80-bitowej precyzji:
- +4 cyfry dziesiętne precyzji
- Skalowanie 10 000 razy głębsze niż w standardowych implementacjach
- Bezpośrednie użycie rejestrów x87 bez pośrednich konwersji
Paralelizacja z OpenMP
OpenMP jest stosowany do równoleglenia pętli obliczeń iteracji. Dyrektywa #pragma omp parallel for schedule(dynamic) efektywnie rozdziela obciążenie na rdzenie, zapewniając skalowalność od systemów 4-rdzeniowych po serwery ze 128 wątkami.
Superpróbkowanie 8×8 (64 próbki na piksel)
SSAA realizowane jest przez render w superwysokiej rozdzielczości 15360×8640 (8× oryginału 1920×1080). Każdy finalny piksel agreguje 64 niezależne próbki fraktalne z osobnym obliczeniem składowych RGB.
Algorytm wygładzania:
- Obliczenie iteracji dla każdego subpiksela w arytmetyce 80-bitowej
- Niezależne kolorowanie subpikseli z rotacją palety
- Akumulacja intensywności R/G/B (uśrednianie po kanałach)
- Downsampling do docelowej rozdzielczości
Rezultat: brak szumu chromatycznego, kinowa ostrość krawędzi struktur fraktalnych.
Zoptymalizowane generowanie klatek
Potok przetwarzania podzielono na dwa etapy dla minimalizacji obliczeń:
Etap 1: Mapa iteracji
- Tworzenie tablicy uint8_t o rozmiarze 132 MB (15360×8640)
- Wykonanie pętli iteracji do-while jeden raz dla całej animacji
- Równoległe wypełnianie z OpenMP
Etap 2: Render 255 klatek
- Odczyt mapy iteracji z pamięci
- Zastosowanie przesuniętej palety dla każdej klatki
- Lokalne uśrednianie bloków 8×8 (bez long double)
- Równoległy zapis plików BMP
Paleta sinusoidalna: 127 + 127 cos(2π a / 255) i 127 + 127 sin(2π a / 255).
Przykład implementacji
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
using namespace std;
const double PI = 3.14159265358979323846;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
Co ważne
- Precyzja 80-bitowa long double + FPU x87: zoom do 10^18 bez artefaktów
- SSAA 8×8: 64 próbki na piksel, całkowita eliminacja szumu
- Dwuetapowy render: mapa iteracji 132 MB + szybkie składanie kolorów
- OpenMP: automatyczna wielowątkowość z dynamicznym harmonogramem
- Integracja FFmpeg: qp=20, no-psy, deblock=-6 dla profesjonalnej jakości
— Editorial Team
Brak komentarzy.