Уменьшение фрактального разрешения (фрагментарный шейдер)

Я использую 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
см. Не могу найти способ раскрасить набор Мандельброта так, как я стремлюсь для вдохновения. Да, проблема в точности с плавающей запятой. Если вы можете использовать double, но будьте осторожны, это будет примерно в 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, поэтому вычисляется внутри шейдера фрагмента графического процессора, нет длинного двойника ... он не полностью совместим с 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, кстати, что это за зум? с double я могу подняться до zoom=10^14, где начинается пикселизация.   -  person Spektre    schedule 11.03.2021