Skip to content
Mike edited this page Aug 18, 2014 · 37 revisions

Clisk makes procedural image generation simple with a Clojure DSL.

Installation

The best way to get started using Clisk is to install it as a dependency from Clojars using either Leiningen or Maven. See details for the latest Clisk version on Clojars

Once installed you need to include clisk with something like the following code in your ns declaration:

(ns my-namespace
  (:use [clisk live]))

The clisk.live namespace contains everything you need to produce images with Clisk.

Basics

Images are made up by composing vector functions to create RGB values. The Clisk DSL allows you to declaratively define how the image will be computed. So when you are defining a Clisk image, what you are really doing is creating a function that computes the Red, Green and Blue values for each pixel as follows:

[red, green, blue] = f(x , y)

Where x and y are the co-ordinates of the pixel you are calculating in the image. By default, images are generated over for an (x,y) range of (0,0) to (1,1), with (0,0) being the top left corner. Interested reader smay note that (0,0) is conventionally top left in computer graphics but bottom left in mathematics. Don't ask me why :-)

As a simple example, you might want to create an image using the forllowing fomula:

[red, green, blue] = f(x , y) = [x, y, 0]

i.e. you want to use x to determine the red component, y to determine the green component and always set the blue component to zero. As the colour values x and y will change smoothly as you move across the image, this should give you a nice gradient-style blend of reds and greens.

In Clisk, you can view the image generated by this function as follows:

(show [x y 0])

Red and Green gradient on x-y plane

As it happens, the current position vector [x y z t] is very commonly used so you can use the shortcut pos to get the same result. Although the pos vector also includes z and t co-ordinates, both of these are zero by default so this produces the same result as [x y 0] or [x y 0 0].

(show pos)

(for those who are curious about the implementation, x, y, z and t are actually scalar functions of the current texture position, and pos is just a plain vector containing the symbols x, y, z and t)

Image generation DSL

You can create some interesting colours with formulae containing just x, y, z and t. However the real power of Clisk is that it enables you to build up complex image generation functions from a library of simple components, and methods to combine these in interesting ways.

The pre-defined checker function, for example, creates a checkerboard from any two other colours or functions:

(def checker-pattern (checker 0 1))    ;; 0 and 1 are shortcuts for black=[0 0 0] and white=[1 1 1]
(show checker-pattern)

Black and white checker pattern

The scale function enables you to scale a pattern appropriately. This allows to get a larger effective area of calculation - for example scaling by 0.25 (one quarter) will enable to to calculate the function over an effective (x,y) range of (0,0) to (4,4), so you will see 4x4=16 times as many features.

(show (scale 0.25 checker-pattern))

Black and white chessboard

The offset function allows you to twist an image using an offset provided by another function. The vnoise function is particularly useful for this:

(show  (scale 0.25 (offset vnoise checker-pattern) ))

Swirly chessboard

Vector functions can also be used to provide colour. For example, if we multiply (using v*) our chessboard by the vplasma function, we get a nice colourful patterned effect. Multiplication can also be applied to our offset to get a greater level of distortion.

(show  (scale 0.25 (offset (v* 6 vnoise) (v* vnoise checker-pattern)) ))

Swirly chessboard

Fun Effects

The gradient function calculates the gradient of another function. If you apply this to a plasma function, for example, it can be used to create a bumpy rock effect:

(show  (v+ [0.9 0.6 0.3] (dot [0.2 0.2 0] (gradient plasma ))))

Golden rock

The seamless function creates a seamless tileable 2D texture from any 4D texture. Again, the 4D noise functions are good to use as a source:

(show (scale 0.25 (seamless 0.25 noise)))

Golden rock

You can also imitate 3D shaded objects

(show (viewport [-1 -1] [1 1]  
      (v*
        (warp globe vplasma)      ;; colour vector plasma texture, samples on the surface of a globe
        (light-value [-1 -1 1] (height-normal globe)))))  ;; diffuse lighting using globe as heightmap

Plasma Globe

Clone this wiki locally