2

I'm working for some days now on a DirectX 11 version of the Mandelbrot set. What I've done so far is create a quad with a texture on it. I can color the points with a Pixel Shader, but for some reason the Mandelbrot set in the Pixel Shader does not return the expected result. I tested the logic in plain C++ code and I've same eroneous result. Any idea what's wrong with the code? I have a proper version working in Python and I just replicated the code, but it seems something is missing.

The Width of the set is 2.5 (will stretched the image a bit). It assumes a 1024*960 window and max. iteration of 1000. I compiled with Shader Model 5.0. It starts with the default set with

RealStart = -2.0;
ImagStart = -1.25;

Passed via the constant buffer

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;
}

Edit Python version

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

The creal, cimag and are created like that and then just looped through.

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

It return the maxNumberOfIterations to a two-dimsensional array, which is plot to draw the Mandelbrot set.

Gilles Walther
  • 126
  • 1
  • 7
  • 1
    That is not the mandelbrot formula as I know it. It should use constants instead of the coordinates. Only the start conditions are the coordinates. Would you like to show the python code which you describe as working? If you have the same problem in C++, not only in shader, then remove all shader related parts from the question to simplify it. Instead add a python tag (in addtion to the python code), to attract people who know Python AND C++ to help with transposing. – Yunnosch Jan 11 '20 at 20:33
  • I'll edit the post with the Python code – Gilles Walther Jan 11 '20 at 20:34
  • You will have to [edit] to make non-trivial code visible. It will also be much more suitable to get helpful formatting and the needed space... – Yunnosch Jan 11 '20 at 20:34
  • Try to make two [mre], python and C++, which should theoretically produce same output but don't. If you pick a few characteristic coordinates, then you won't need graphics for demonstration. Which will be very helpful for making things reproducable. – Yunnosch Jan 11 '20 at 20:37
  • I think I might have misread your code, sorry. My comment might be completely off. Your variables names unrailed me. Could you comment your code? That would also mean doing a few steps by the very helpful method described here: https://ericlippert.com/2014/03/05/how-to-debug-small-programs/ Also, MREs might help getting me back on track, by helping me which variables get filled from where. What is constant? What changes per pixel? – Yunnosch Jan 11 '20 at 20:39
  • RealStart and ImagStart are the constant (will be variable once it works and I can implement the zoom). position is the position of the pixel in with x and y coordinate. This is tested and works. for instance if I return CalcColor[0] = position.x it will color the screen with a gradiant red from left to right. I'll write comments. – Gilles Walther Jan 11 '20 at 20:49
  • The python code comes from https://gist.github.com/jfpuget/60e07a82dece69b011bb the Numba version decomposed into two floats (little bit further down) – Gilles Walther Jan 11 '20 at 21:01
  • Thanks for looking at this with me, I think I found the error, the ImagStart and RealStart in the "Else" need to be scaled. – Gilles Walther Jan 11 '20 at 22:37
  • I would be interested in a detailed solution. You are aware that you absolutely can make your own answer here, aren't you? – Yunnosch Jan 12 '20 at 07:59
  • I posted the answer thanks, still struggling retrieving the other data from the constant buffer... – Gilles Walther Jan 12 '20 at 16:45

1 Answers1

1

The error was that the ImagStart and RealStart in the Else need to be scaled as well. The code in the Shader has been modified as follows:

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;
}

The Mandelbrot set in drawn correctly. Mandelbrot set

Gilles Walther
  • 126
  • 1
  • 7