2

A friend of mine had to draw a mandelbrot with opengl in c. I decided to do it in Swift.

The first method I tried was by creating an array with ARGB data and convert this into a CGImage and view that one in an UIImageView. However this was not fast enough.

Now I am wondering, what is the fastest way to draw individual pixels onto the screen. I looked into Metal but that seemed to be mostly about triangles and 3d stuff. Then I came to scenekit shaders (.fsh) and thought maybe that was a good solution. However I want also be able to zoom into the mandelbrot fractal and I couldnt find a way to input variables in my mandelbrot (my reference: https://www.weheartswift.com/fractals-xcode-6/)

Can you guys tell me/give an example (Swift please) on the fastest way of drawing individual pixels, or at least a way to draw raw pixels to the screen without having to use something intermediate like composing a CGImage?

Simon
  • 2,419
  • 2
  • 18
  • 30
  • Why do you believe drawing a CGImage is slow? Did you run Instruments on your code? What, exactly, did you discover when you did? – matt Apr 07 '15 at 20:50
  • Do you want to compute the fractal samples on the GPU (using an OpenGL shader)? Or do you want to compute them on the CPU (using Swift) and just draw them in a fast way? Were you creating a new `CGImage` every time you computed a pixel, or were you creating one `CGImage` after computing all pixels, or something in between? – rob mayoff Apr 07 '15 at 20:53
  • @matt It is a workaround because I couldnt find a more direct way of drawing onto the screen, and I also had to create a bunch of pixels in memory so I assume it is indeed slower. – Simon Apr 07 '15 at 21:55
  • @robmayoff I assume using the GPU is a lot faster so I would rather do it on the gpu and I also think a task like this should be on the GPU. I created one image for every frame in the worst case – Simon Apr 07 '15 at 21:56
  • "Assume"? You know what _that_ is worth. I would suggest that the _calculation_ is slow but that the drawing of the pixels is not. – matt Apr 07 '15 at 22:03
  • Okay lets say I am not happy with the way I do it at the moment because I have the feeling that this isnt the best way of doing it. Basically I am wondering how close I can get to setPixelXY(x, y, color) – Simon Apr 07 '15 at 22:12
  • You are a UIView and you have a `drawRect:` implementation, or you are a CALayer and you have content, or you are a GLKView with an OpenGL framebuffer. That's how things get on the screen in iOS. – matt Apr 07 '15 at 22:43

2 Answers2

3

Rather than using vertex and fragment shaders, take a look at using a kernel function (or compute shader). This would be a single shader that does the maths and sets the color value at each pixel of a texture. You can then render the texture to screen using CAMetalLayer.

Take a look at this blog post where I write to a texture using the coordinates of particles passed into a kernel function: http://flexmonkey.blogspot.co.uk/2015/03/swift-metal-four-million-particles-on.html

Flex Monkey
  • 3,583
  • 17
  • 19
  • Wow thanks this looks like an amazing source of more knowledge :) Ill dive into this when I have time! – Simon Apr 09 '15 at 13:36
0

If you want to compute the fractal on the GPU, then this is much more an OpenGL (or Metal) question than a Swift question. You need to take smaller steps:

  1. Get a solid-color triangle on the screen with OpenGL.
  2. Fill the screen with two solid-color triangles.
  3. Fill the triangles with a simple gradient using a fragment shader.
  4. Fill the triangles with a simple texture.
  5. Perform two-stage drawing: draw into an off-screen buffer (with triangles and a shader), then use that buffer as your texture to draw on-screen.
  6. Draw your fractal into the off-screen buffer using a shader.

Note that step 6 may be hard, and you might need help with it, but there's no point in even starting it until you can do steps 1-5 successfully. You should be able to find lots of tutorials to help you get through steps 1-5, though you may have to translate them to Swift from C, C++, or Objective-C.

The page you linked skips steps 1-5 entirely, because the Xcode scene viewer takes care of them for you. If you want to write a standalone app, you need to learn how to do those steps.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Ok, so eventually I will end up with a screen with two triangles which together fill the entire screen and have the same shader which in total renders the mandelbrot? If this is the way I should do it I will try and follow your guidesteps – Simon Apr 07 '15 at 23:04