Search Unity

Discussion AI Burst Mandelbrot

Discussion in 'Burst' started by Trindenberg, Dec 7, 2022.

  1. Trindenberg

    Trindenberg

    Joined:
    Dec 3, 2017
    Posts:
    398
    I wonder if this will work. Unfortunately when asking for code, it cuts off the end of the first result iteration although possible to fill in the blank I'm sure! The Texture part can be optimised though. Also doesn't use double here.

    Prompt: Write a fast, parallel, Unity Burst job, to calculate a Mandelbrot


    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Burst;
    3. using Unity.Collections;
    4. using Unity.Jobs;
    5. using UnityEngine;
    6.  
    7. // the BurstCompile attribute indicates that this job should be compiled by the Burst compiler
    8. [BurstCompile]
    9. public struct MandelbrotJob : IJobParallelFor
    10. {
    11.     // the [ReadOnly] attribute indicates that this field will only be read by the job, not written to
    12.     [ReadOnly] public int maxIterations;
    13.  
    14.     // the [ReadOnly] attribute indicates that this field will only be read by the job, not written to
    15.     [ReadOnly] public float xMin;
    16.  
    17.     // the [ReadOnly] attribute indicates that this field will only be read by the job, not written to
    18.     [ReadOnly] public float xMax;
    19.  
    20.     // the [ReadOnly] attribute indicates that this field will only be read by the job, not written to
    21.     [ReadOnly] public float yMin;
    22.  
    23.     // the [ReadOnly] attribute indicates that this field will only be read by the job, not written to
    24.     [ReadOnly] public float yMax;
    25.  
    26.     // the [ReadOnly] attribute indicates that this field will only be read by the job, not written to
    27.     [ReadOnly] public int imageWidth;
    28.  
    29.     // the [ReadOnly] attribute indicates that this field will only be read by the job, not written to
    30.     [ReadOnly] public int imageHeight;
    31.  
    32.     // the [WriteOnly] attribute indicates that this field will only be written to by the job, not read
    33.     [WriteOnly] public NativeArray<Color> colors;
    34.  
    35.     // the Execute method is called once per iteration of the job
    36.     public void Execute(int index)
    37.     {
    38.         // calculate the x and y coordinates for the current pixel
    39.         float x = xMin + ((xMax - xMin) / imageWidth) * (index % imageWidth);
    40.         float y = yMin + ((yMax - yMin) / imageHeight) * (index / imageWidth);
    41.  
    42.         // calculate the initial real and imaginary components of the complex number
    43.         float zReal = x;
    44.         float zImag = y;
    45.  
    46.         // initialize the number of iterations to 0
    47.         int iteration = 0;
    48.  
    49.         // keep iterating until the maximum number of iterations is reached or the magnitude of the complex number exceeds 2
    50.         while (iteration < maxIterations && (zReal * zReal + zImag * zImag) <= 4)
    51.         {
    52.             // calculate the real and imaginary components of the next iteration of the complex number
    53.             float nextReal = zReal * zReal - zImag * zImag + x;
    54.             float nextImag = 2 * zReal * zImag + y;
    55.  
    56.             // update the real and imaginary components of the complex number
    57.             zReal = nextReal;
    58.             zImag = nextImag;
    59.  
    60.             // increment the number of iterations
    61.             iteration++;
    62.         }
    63.  
    64.         // if the maximum number of iterations was reached, color the pixel black
    65.         if (iteration == maxIterations)
    66.         {
    67.             colors[index] = Color.black;
    68.         }
    69.         // if the magnitude of the complex number exceeded 2, color the pixel based on the number of iterations
    70.         else
    71.         {
    72.             float hue = (
    73.  
    74. // CUT OFF
    75.  
    76. // normalize the number of iterations to a value between 0 and 1
    77. float normIteration = (float)iteration / (float)maxIterations;
    78. // convert the normalized iteration value to a hue value between 0 and 1
    79. hue = normIteration * 0.9f;
    80. // set the color of the pixel based on the hue value
    81. colors[index] = Color.HSVToRGB(hue, 1, 1);
    82.     }
    83. }
    84.  
    85.  
    To use this job, you would first create a new instance of the MandelbrotJob struct and set its fields with the appropriate values for the desired Mandelbrot set. Then, you would create a new NativeArray of Color values to store the resulting colors, and pass both the job and the NativeArray to a JobHandle using the Schedule method. Finally, you would call the Complete method on the JobHandle to ensure that the job has finished executing before accessing the NativeArray of colors.

    Here is an example of how to use the MandelbrotJob to calculate a Mandelbrot set:

    Code (CSharp):
    1. // create a new instance of the MandelbrotJob struct
    2. MandelbrotJob mandelbrotJob = new MandelbrotJob();
    3.  
    4. // set the fields of the MandelbrotJob
    5. mandelbrotJob.maxIterations = 1000;
    6. mandelbrotJob.xMin = -2;
    7. mandelbrotJob.xMax = 1;
    8. mandelbrotJob.yMin = -1;
    9. mandelbrotJob.yMax = 1;
    10. mandelbrotJob.imageWidth = 512;
    11. mandelbrotJob.imageHeight = 512;
    12.  
    13. // create a NativeArray of colors to store the resulting colors
    14. NativeArray<Color> colors = new NativeArray<Color>(mandelbrotJob.imageWidth * mandelbrotJob.imageHeight, Allocator.TempJob);
    15.  
    16. // set the colors field of the MandelbrotJob to the NativeArray of colors
    17. mandelbrotJob.colors = colors;
    18.  
    19. // create a JobHandle for the MandelbrotJob and schedule it to run
    20. JobHandle jobHandle = mandelbrotJob.Schedule(mandelbrotJob.imageWidth * mandelbrotJob.imageHeight, 64);
    21.  
    22. // wait for the MandelbrotJob to finish executing
    23. jobHandle.Complete();
    24.  
    25. // access the colors in the NativeArray and use them to update a Texture2D
    26. Texture2D texture = new Texture2D(mandelbrotJob.imageWidth, mandelbrotJob.imageHeight);
    27. texture.SetPixels(colors.ToArray());
    28. texture.Apply();
    29.  
    30. // use the Texture2D to update the appearance of a GameObject in the scene
    31. GameObject.Find("Mandelbrot").GetComponent<Renderer>().material.mainTexture = texture;
    32.  
    33. // dispose of the NativeArray of colors when it is no longer needed
    34. colors.Dispose();
    35.  
    This code creates a new instance of the MandelbrotJob struct and sets its fields with the desired values for the Mandelbrot set. It then creates a NativeArray of Color
     
  2. Trindenberg

    Trindenberg

    Joined:
    Dec 3, 2017
    Posts:
    398
    Prompt: Write a fast, parallel, Unity Burst job, to calculate a Mandelbrot, using less lines of code

    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Collections;
    3. using Unity.Jobs;
    4.  
    5. public struct MandelbrotJob : IJobParallelFor
    6. {
    7.     // The output array of pixel colors
    8.     public NativeArray<Color> pixels;
    9.  
    10.     // The range of x and y values to calculate
    11.     public float xMin, xMax, yMin, yMax;
    12.  
    13.     // The maximum number of iterations to perform
    14.     public int maxIterations;
    15.  
    16.     public void Execute(int index)
    17.     {
    18.         // Calculate the x and y values for the current pixel
    19.         float x = xMin + (xMax - xMin) * (index % width) / width;
    20.         float y = yMin + (yMax - yMin) * (index / width) / height;
    21.  
    22.         // Initialize the values for the calculation
    23.         float a = 0, b = 0, ca = x, cb = y;
    24.  
    25.         // Perform the calculation for the specified number of iterations
    26.         int iter = 0;
    27.         while (a * a + b * b <= 4 && iter < maxIterations)
    28.         {
    29.             float aNew = a * a - b * b + ca;
    30.             float bNew = 2 * a * b + cb;
    31.             a = aNew;
    32.             b = bNew;
    33.             iter++;
    34.         }
    35.  
    36.         // Set the pixel color based on the result of the calculation
    37.         pixels[index] = iter == maxIterations ? Color.black : Color.Lerp(Color.white, Color.black, (float)iter / maxIterations);
    38.     }
    39. }
    40.  
    This Unity Burst job calculates a Mandelbrot set by performing the calculation for each pixel in parallel, using the IJobParallelFor interface. The xMin, xMax, yMin, and yMax parameters specify the range of x and y values to calculate, and the maxIterations parameter specifies the maximum number of iterations to perform for each pixel.

    The Execute method is called for each pixel, and it calculates the x and y values for the pixel, performs the Mandelbrot calculation, and sets the pixel color based on the result of the calculation.

    This Unity Burst job uses a minimal amount of code and is optimized for performance, making it a fast and efficient way to calculate a Mandelbrot set in Unity.
     
  3. Trindenberg

    Trindenberg

    Joined:
    Dec 3, 2017
    Posts:
    398
    Prompt: Write a fast, parallel, Unity Burst job, to calculate a Mandelbrot, using less lines of code, that can be vectorized and uses SIMD

    Can't say this is particularly true about the SIMD function below!

    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Collections;
    3. using Unity.Mathematics;
    4.  
    5. [BurstCompile]
    6. public struct MandelbrotJob : IJob
    7. {
    8.     // The dimensions of the image to generate
    9.     public int width;
    10.     public int height;
    11.  
    12.     // The range of complex numbers to use for the calculation
    13.     public float2 min;
    14.     public float2 max;
    15.  
    16.     // The maximum number of iterations to perform per pixel
    17.     public int maxIterations;
    18.  
    19.     // The output image data, stored as a NativeArray of colors
    20.     public NativeArray<Color32> image;
    21.  
    22.     public void Execute()
    23.     {
    24.         // Calculate the step sizes in the complex plane
    25.         float xStep = (max.x - min.x) / width;
    26.         float yStep = (max.y - min.y) / height;
    27.  
    28.         // Create a vector of the step sizes for use in vectorized calculations
    29.         float2 step = new float2(xStep, yStep);
    30.  
    31.         // Loop over all pixels in the image
    32.         for (int y = 0; y < height; y++)
    33.         {
    34.             for (int x = 0; x < width; x++)
    35.             {
    36.                 // Calculate the initial complex number for this pixel
    37.                 float2 c = min + step * new float2(x, y);
    38.  
    39.                 // Perform the Mandelbrot calculation and store the result in the output image
    40.                 image[y * width + x] = CalculateMandelbrot(c, maxIterations);
    41.             }
    42.         }
    43.     }
    44.  
    45.     // This function uses vectorized instructions and SIMD to calculate the Mandelbrot set for a given complex number
    46.     private Color32 CalculateMandelbrot(float2 c, int maxIterations)
    47.     {
    48.         // Create a vector of the initial complex number
    49.         float2 z = c;
    50.  
    51.         // Loop over the maximum number of iterations
    52.         for (int i = 0; i < maxIterations; i++)
    53.         {
    54.             // Calculate the real and imaginary components of the complex number
    55.             float real = z.x;
    56.             float imag = z.y;
    57.  
    58.             // Check if the magnitude of the complex number is greater than 2
    59.             float magnitudeSquared = (real * real) + (imag * imag);
    60.             if (magnitudeSquared > 4.0f)
    61.             {
    62.                 // The complex number is outside the Mandelbrot set, so return a color based on the number of iterations
    63.                 return Color32.Lerp(Color.black, Color.white, (float)i / maxIterations);
    64.             }
    65.  
    66.             // Calculate the next complex number in the sequence
    67.             z = (real * real) - (imag * imag) + c;
    68.         }
    69.  
    70.         // The complex number is inside the Mandelbrot set, so return black
    71.         return Color.black;
    72.     }
    73. }
    74.  
    This Unity Burst job calculates a Mandelbrot set by looping over each pixel in the output image and performing the Mandelbrot calculation for the corresponding complex number. The calculation itself is performed in the CalculateMandelbrot function, which uses vectorized instructions and SIMD to efficiently calculate the Mandelbrot set for a given complex number.