Grains of Sand

A drawing method that I have become increasingly fond of is what I have named "sand painting". I sometimes—somewhat jokingly—refer to it as Monte Carlo drawing. Hopefully it will be possible to understand why when I have explained how it works.

I first discovered a variation of this method used by Tarbell in Substrate. It is even easier to see how it works in Sand Stroke. Most likely various forms of this have been used multiple other places as well.

Basically it works by drawing several, almost transparent, dots at random along a line. This is akin to spreading a fixed number of grains of sand along a line—hence the name. If you always use the same number of grains, this will have the effect of making the line appear dense whenever the points are close to each other. And, conversely, less dense when they are farther apart.

When I do sand painting it is usually a variation of the following:

  • Pick a number of grains, n.
  • Pick a color, and a corresponding transparency, rgba.
  • Pick two points, v and w.
  • Randomly draw n points (uniformly distributed) between v and w, using color rgba.
  • Move v and w slightly, then draw again.

Most drawing libraries will let you do something along these lines with fairly minimal effort. You only have to figure out how to draw transparent pixels (or boxes, or circles, etc.).

A more involved version of this method can be achieved by randomly drawing grains along a spline. This is the method used here, which is a Javascript implementation of my Sand Spline algorithm.

One thing you might notice when you start doing this is that in many drawing libraries there is a lower limit to the level of detail you can get. That is, if you try drawing with very high transparency it will stop working, or act strange.

The reason for this is that colors, and transparency, are frequently stored as integer values between 0 and 255 (including), so the values will be rounded to the nearest whole number every time. This rounding error will quickly accumulate in some cases.

If you just want to play around a little this shouldn't worry you too much. But a possible solution is to store color and transparency as floats (or doubles) between 0.0 and 1.0, and only convert to integers when you export. This might, however, require you to implement your own drawing tools.

cell a22f9c9
A more involved example using splines.

Finally, if you are interested, here is an example of the code used to generate the above image. The code relies on my snek framework. It also does sand painting along splines, instead of along straight lines.

The code assumes that you have initialized the system so that there are a number of small connected loops of vertices randomly distributed on the canvas. Each such vertex loop is part of its own group (grp). The complete code is here.

; snk is an instance of snek
; and sand is a sandpaint instance.
; repeat this many times
(loop for i from 0 below itt do
  (with-snek (snk :zwidth 60.0d0)
    ; for all vertices in snk
    (itr-all-verts (snk v)
      ; for all vertices, w, closer to v than 60:
      ; push them apart a little
      (map 'list (lambda (w) (force? snk v w -0.05))
                 (verts-in-rad snk
                              (get-vert snk v)
                              60.0d0)))

    ; for all vertex "rings"
    (itr-grps (snk g)
      ; for all neighbouring vertices:
      ; move a little closer to each other
      (itr-edges (snk e :g g)
        (force? snk (first e) (second e) 0.1))))

  ; for all vertex rings
  (itr-grps (snk g)
    ; sandpaint along a spline controlled
    ; by the vertex ring
    (sandpaint:pix sand
      (bzspl:rndpos
        (bzspl:make (get-grp-vert-vals snk :g g) :closed t)
        grains))))

  1. You can read a bit more about it here. The article mentions Flash, but this behaviour can be observed in, among others, Javascript Canvas and Python Cairo as well.
  2. I have implemented this type of drawing both in snek and in a Python library called fast-sand-paint. These are heavily tailored to my work, but maybe it will be helpful if you are looking to implement your own. Moreover, I suggest looking up alpha compositing, reading about Pre multiplied alpha, and looking at the Cairo documentation.