Намаляване на фракталната разделителна способност (фрагмент шейдър)

Използвам SFML за c++ за генериране на набора на Манделброт. Действителната част от генерирането се извършва във фрагментния шейдър за производителност. Моля, имайте предвид, че нямам много опит с шейдърите.

По някаква причина, когато приближа над определена точка, това се случва.

въведете описание на изображението тук

Наистина няма много смисъл, тъй като не мащабирам нищо, а само настройвам параметри в генерирането. Най-доброто ми предположение е, че има нещо общо с рисуването на фрагменти, а не на пиксели.

Ето шейдъра на фрагменти (копирането/поставянето направи нещо странно с форматирането)

#version 400

uniform int window_width;
uniform int window_height;

uniform float x_translation;
uniform float y_translation;
uniform float zoom;
uniform int iterations = 255;
uniform int color;


float map(float n, float start1, float stop1, float start2, float stop2)
{
    return ((n - start1) / (stop1 - start1)) * (stop2 - start2) + start2;
}

void main()
{

float diversion_threshold = 4.0;

float saved_brightness = 0.0;

float real_translated_a = ((-2.0 - x_translation));
float real_translated_b = ((2.0 - x_translation));

float imaginary_translated_a = ((-2.0 + y_translation));
float imaginary_translated_b = ((2.0 + y_translation));

//float z_real = map(gl_FragCoord.x, 0.0, float(window_width), real_translated_a * zoom, real_translated_b * zoom);
//float z_imaginary = map(gl_FragCoord.y, 0.0, float(window_height), imaginary_translated_a * zoom, imaginary_translated_b * zoom);

float z_real = x_translation + (gl_FragCoord.x/window_width - 0.5) * zoom;
float z_imaginary = y_translation + (gl_FragCoord.y/window_height - 0.5) * zoom;

float z_real_original = z_real;
float z_imaginary_original = z_imaginary;
float z_real_temp;
float z_imaginary_temp;

float brightness = 0.0;

for (int n = 0;n <= iterations; n++) {
    z_real_temp = z_real * z_real - z_imaginary * z_imaginary;
    z_imaginary_temp = 2.0 * z_real * z_imaginary;

    z_real = z_real_temp + z_real_original;
    z_imaginary = z_imaginary_temp + z_imaginary_original;

    if (color != 0)brightness = map(float(n), 0.0, float(iterations), 0.0, 1.0);
    else brightness = map(float(n), 0.0, float(iterations), 1.0, 0.0);

    brightness = map(sqrt(brightness), 0.0, 1.0, 0.0, 1.0);

    if ((z_real * z_real + z_imaginary * z_imaginary) > diversion_threshold) {
        break;
    }
}

if (color == 0) gl_FragColor = vec4(brightness, brightness, brightness, 1.0);
if (color == 1) gl_FragColor = vec4(brightness, 0.0, 0.0, 1.0);
if (color == 2) gl_FragColor = vec4(0.0, 0.0, brightness, 1.0);
if (color == 3) gl_FragColor = vec4(0.0, brightness, 0.0, 1.0);
if (color == 4) gl_FragColor = vec4(brightness, 0.0, brightness * 0.67, 1.0);
if (color == 5) gl_FragColor = vec4(brightness * 0.1, brightness, brightness * 0.56, 1.0);

}

Шейдърът просто се прилага върху правоъгълник и това е всичко.


person SGl0bGVy    schedule 09.03.2021    source източник
comment
Вероятно е, когато ти свърши прецизността. За дълбоко приближаване на набора на Манделброт ще трябва да използвате произволна прецизна математическа библиотека.   -  person Richard Critten    schedule 09.03.2021
comment
Както казва @RichardCritten, прецизността ви се изчерпва, докато приближавате по-дълбоко. Ще получите много повече налична „дълбочина“, като използвате double променливи вместо float, но дори и тогава ще има момент, в който разделителната способност ще се провали. В зависимост от вашата платформа/компилатор може дори да имате тип long double с разширена точност. Това ще стигне още по-дълбоко (но ще бъде забележимо по-бавно от float или double).   -  person Adrian Mole    schedule 09.03.2021
comment
@AdrianMole не, няма дълго двойно ... понякога дори двойно не присъства   -  person Spektre    schedule 10.03.2021
comment
вижте Не мога да намеря начин да оцветя набора на Манделброт по начина, към който се стремя за вдъхновение. Да, проблемът е в плаващата точност. Ако можете да използвате двойно, но внимавайте, ще бъде ~2 пъти по-бавно и не можете да преминете varying double между връх и фрагмент. Така че всички дубли ще бъдат само във фрагментния шейдър и внимавайте, трябва да прехвърлите всички преобразувания между double и float. Вижте също как да получа безкрайно малки числа (за фрактали). Вашият въпрос е ОК, но е дубликат, така че затворих гласуването   -  person Spektre    schedule 10.03.2021
comment
@Spektre long double е тип, определен от стандартите C и C+. При някои (много?) реализации, обаче, той е същият като double. Относно проблема със скоростта: не знам каква платформа използва OP, но на x86/x64 системи аритметиката double не е забележимо по-бавна от float (единична точност). Но за тези системи, които прилагат 80- или 128-битови long double типове, използвайки софтуерна емулация, тогава long double аритметиката ще бъде много по-бавна, както казах в първия си коментар. Вижте например тук.   -  person Adrian Mole    schedule 10.03.2021
comment
@AdrianMole неговият GLSL, така че изчислен в шейдъра на GPU фрагмент, няма дълъг двоен ... не е напълно съвместим със C++, има много ограничения и липсващи неща в спецификацията на GLSL в сравнение със стандартизирания C++.   -  person Spektre    schedule 10.03.2021
comment
@Spektre А, добре. Но ако производителността е проблемът, тогава изчисляването brightness вътре в for цикъла не е идеално. Това със сигурност може да се остави, докато не стане известен окончателният брой итерации.   -  person Adrian Mole    schedule 10.03.2021
comment
@AdrianMole да, яркостта/цветът трябва да се премести след for цикъла, неговата пряка функция на стойността на последните итерации, така че е абсолютно безсмислено да се повтаря при всяка итерация на for цикъла. Самото изчисление не е голяма работа, основният удар в производителността е наличието на оператор if else, причиняващ забавяне, свързано с разклоняване, което при GLSL обикновено е голям удар във Fragment.   -  person Spektre    schedule 11.03.2021
comment
@SGl0bGVy btw какво увеличение е това? с double мога да стигна до zoom=10^14, където започва да се появява пикселизация.   -  person Spektre    schedule 11.03.2021