On his wonderful Math ∩ Programming blog, Jeremy Kun published an article on algorithmically generating random “psychedelic” art. By combining common mathematical functions, we can generate images such as the one pictured below (they even make great iOS 7 wallpapers)!
The implementation referenced in Jeremy’s blog post uses Python, so I set out to implement some of the ideas discussed as a native OS X app, PsychedelicArt, using Core Image to generate the images on the GPU. While I won’t rehash the original article or walk through a bunch of Cocoa boilerplate code, the Core Image logic is noteworthy. PsychedelicArt is available on GitHub if you want to follow along.
The Core Image framework on OS X (unlike iOS) allows developers to define custom kernel functions that process image pixels in parallel on the GPU. These kernels are very similar to OpenCL kernels, which as of OS X 10.9 “Mavericks”, power Core Image on supported hardware. By leveraging a technology like Core Image, we can tap into the computing power of modern GPUs.
Sure enough, images in PsychedelicArt are generated with a custom Core Image filter. Unlike most Core Image filters, our drawing filter – a generator – does not process an input image; rather, it takes three mathematical functions as input. These functions determine the red, green, and blue components of each pixel. Each function has a normalized domain [-1, 1] and codomain [-1, 1], which is ultimately mapped to RGB values. By tweaking or altering the input functions, the outputs we can produce are limitless.
The interface of the filter is trivial, as expected:
The implementation compiles a Core Image kernel dynamically based on the three input functions given. These are instances of the seven MathFunction subclasses included in the project. MathFunction itself is modeled as an abstract syntax tree (with its arguments defined recursively):
String representations of the input functions are baked into the underlying kernel; the kernel is then compiled. Conveniently enough, CIKernel sports a string-based constructor. The full implementation of the filter is shown below.
Now, given some input functions, all we need to do is use our drawing filter to output a CIImage, and draw the image in a custom view. This is fairly standard Core Image code:
That’s all there is to it – algorithmically-generated, “psychedelic” art on the GPU with Core Image.