Мандельброт в пиксельном шейдере

Я работаю уже несколько дней над DirectX 11 версией набора Мандельброта. Что я сделал до сих пор, так это создал четырехугольник с текстурой на нем. Я могу раскрасить точки с помощью пиксельного шейдера, но по какой-то причине набор Мандельброта в пиксельном шейдере не возвращает ожидаемого результата. Я проверил логику в простом коде C++ и получил тот же ошибочный результат. Есть идеи, что не так с кодом? У меня есть правильная версия, работающая на Python, и я просто воспроизвел код, но, похоже, чего-то не хватает.

Ширина набора 2,5 (немного растянет изображение). Предполагается окно 1024*960 и макс. итерация 1000. Я скомпилировал Shader Model 5.0. Он начинается с набора по умолчанию с

RealStart = -2.0;
ImagStart = -1.25;

Проходит через буфер констант

cbuffer cBuffer
{
    double RealStart; 'equals -2.5 from the default view of the set
    double ImagStart; 'equals -1.25 from the default view of the set
};

// Pixel Shader
float4 main(float4 position : SV_POSITION) : SV_TARGET
{
    double real, imag;
    double real2, imag2;
    int ite = 0;
    float4 CalcColor = { 1.0f , 1.0f, 1.0f, 1.0f };
    'position is the position of the pixel from 1.0f to 0.0f
    real = RealStart + (double) position.x / 1024 * 2.5;
    imag = ImagStart + (double) position.y / 960 * 2.5;

    for (int i = 0; i < 1000; i++)
    {
        'breaking down the complex number by its constituents
        real2 = real * real;
        imag2 = imag * imag;

        if (real2 + imag2 > 4.0)
        {
            break;
        }
        else {
            imag = 2 * real * imag + ImagStart;
            real = real2 - imag2 + RealStart;
            ite++;
        }
    }

    CalcColor[0] = (float) (ite % 333) / 333 ;
    CalcColor[1] = (float) (ite % 666) / 666 ;
    CalcColor[2] = (float) (ite % 1000) / 1000;

    return CalcColor;
}

Изменить версию Python

def Mandelbrot(creal, cimag, maxNumberOfIterations):
    real = creal
    imag = cimag

    for numberOfIterations in range(maxNumberOfIterations):
        real2 = real * real
        imag2 = imag * imag

        if real2 + imag2 > 4.0:
            return numberOfIterations

        imag = 2 * real * imag + cimag
        real = real2 - imag2 + creal

    return maxNumberOfIterations

Creal, cimag и создаются таким образом, а затем просто зацикливаются.

realAxis = np.linspace(realStart, realStart + width, dim)
imagAxis = np.linspace(imagStart, imagStart + width, dim)

Он возвращает maxNumberOfIterations в двумерный массив, который предназначен для рисования множества Мандельброта.


person Gilles Walther    schedule 11.01.2020    source источник
comment
Насколько я знаю, это не формула Мандельброта. Он должен использовать константы вместо координат. Только начальные условия являются координатами. Хотите показать код Python, который вы описываете как работающий? Если у вас есть такая же проблема в C++, а не только в шейдере, удалите все части, связанные с шейдером, из вопроса, чтобы упростить его. Вместо этого добавьте тег python (в дополнение к коду python), чтобы привлечь людей, которые знают Python и C++, для помощи в транспонировании.   -  person Yunnosch    schedule 11.01.2020
comment
Я отредактирую пост с кодом Python   -  person Gilles Walther    schedule 11.01.2020
comment
Вам нужно будет редактировать, чтобы сделать нетривиальный код видимым. Также будет гораздо удобнее получить полезное форматирование и необходимое пространство...   -  person Yunnosch    schedule 11.01.2020
comment
Попробуйте сделать два минимально воспроизводимых примеров, python и C++, которые теоретически должны давать одинаковый результат, но не должны. Если выбрать несколько характерных координат, то графика для демонстрации не понадобится. Что будет очень полезно для воспроизводимости вещей.   -  person Yunnosch    schedule 11.01.2020
comment
Я думаю, что, возможно, неправильно прочитал ваш код, извините. Мой комментарий может быть полностью выключен. Твои имена переменных сбили меня с толку. Не могли бы вы прокомментировать свой код? Это также означает выполнение нескольких шагов очень полезным методом, описанным здесь: ericlippert.com/2014/03/05/how-to-debug-small-programs Кроме того, MRE могут помочь мне вернуться в нужное русло, помогая мне определить, какие переменные откуда заполняются. Что такое константа? Что меняется на пиксель?   -  person Yunnosch    schedule 11.01.2020
comment
RealStart и ImagStart являются постоянными (будут переменными, как только это заработает, и я смогу реализовать масштабирование). position — это позиция пикселя с координатами x и y. Это проверено и работает. например, если я верну CalcColor[0] = position.x, экран окрасится градиентным красным цветом слева направо. Я напишу комментарии.   -  person Gilles Walther    schedule 11.01.2020
comment
Код Python взят из gist.github.com/jfpuget/60e07a82dece69b011bb версии Numba, разделенной на две части. плавает (чуть ниже)   -  person Gilles Walther    schedule 12.01.2020
comment
Спасибо, что посмотрели это вместе со мной, я думаю, что нашел ошибку, ImagStart и RealStart в Else необходимо масштабировать.   -  person Gilles Walther    schedule 12.01.2020
comment
Хотелось бы подробного решения. Вы знаете, что вы абсолютно можете дать свой собственный ответ здесь, не так ли?   -  person Yunnosch    schedule 12.01.2020
comment
Я отправил ответ, спасибо, все еще пытаясь получить другие данные из буфера констант...   -  person Gilles Walther    schedule 12.01.2020


Ответы (1)


Ошибка заключалась в том, что ImagStart и RealStart в Else также необходимо масштабировать. Код в шейдере был изменен следующим образом:

cbuffer cBuffer
{
    double2 C;
    float2 Param;
    float MaxIt;
};


// Pixel Shader
float4 main(float4 position : SV_POSITION, float2 texcoord : TEXCOORD) : SV_TARGET
{
    double real, imag;
    double real2, imag2;
    uint ite = 0;
    float4 CalcColor = { 1.0f , 1.0f, 1.0f, 1.0f };

    real = C.x + ((double) texcoord.x - 0.5) * 2.0 * 2.5;
    imag = C.y + ((double) texcoord.y - 0.5) * 2.0 * 2.5;

    for (int i = 0; i < 100; i++)
    {
        real2 = real * real;
        imag2 = imag * imag;

        if (real2 + imag2 > 4.0)
        {
            break;
        }
        else {
            imag = 2 * real * imag + C.y + ((double) texcoord.y - 0.5) * 2.0 * 2.5;
            real = real2 - imag2 + C.x +   ((double) texcoord.x - 0.5) * 2.0 * 2.5;
            ite++;
        }
    }

    if (ite > 100)
        ite = 100;

    CalcColor[0] = (float)(ite % 33) / 33;
    CalcColor[1] = (float)(ite % 66) / 66;
    CalcColor[2] = (float)(ite % 100) / 100;

    return CalcColor;
}

Множество Мандельброта нарисовано правильно. Множество Мандельброта

person Gilles Walther    schedule 12.01.2020