#cloverfield
#r1b2
#ink
Cloverfield walkthrough

Cloverfield walkthrough

written by r1b2

31 Oct 2022250 EDITIONS
No active listing

Most of the time, my projects will start with a reference picture. This is the picture I took, during a walk in Chimney Bluffs National Park (upstate NY).

The reference image that started it all....
The reference image that started it all....

Zooming into the reference picture, it was apparent that there were several types of grasses coexisting. There were clovers, 2 types of grass blades and some plants with larger leaves. The project mostly consisted in modeling each of these.

The Shape class

For this project I used a class (unimaginatively called Shape), which really is little more than a wrapper around an Array of {x,y} points.

I'll show a few methods of the Shape class below. Drawing a shape is as simple as:

  draw(layer)
  {
    layer.beginShape();
    for (let p of this.pts) { layer.vertex(p.x, p.y); }
    layer.endShape();
  }

Of course I also have the option of using my ink-style signature drawing style, using a drawer class that draws lines by splitting them into many points, displacing the points slightly, varying the line weight and randomly adding analog effects like splatter:

  analogDraw(layer, drawer)
  {
    for (var i = 0; i < this.pts.length - 1; ++i)
    {
      drawer.draw(layer, this.pts[i], this.pts[i + 1]);
    }
  }

When drawing shapes you very often want to erase what's underneath - so you can draw shapes on top of each other without the bottom ones showing through. In order to do this, I set the layer in erase mode and draw the shape:

  eraseInside(layer)
  {
    layer.push();
    layer.erase();
    layer.noStroke();
    layer.fill(0);
    this.draw(layer);
    layer.noErase();
    layer.pop();
  }

One of the most powerful features of Javascript, is that functions are objects, and can be used as variables or parameters to other functions. For example, this code builds an array of points along a function f:

  function buildCurve(f, npts)
    {
        var pts = [];
        for (var i = 0; i < npts; ++i) 
        {
            var pt = f(i / (npts-1));
            pts.push(pt);
        }
        return pts;
    }

This is very useful to generate complex shapes. This for example, generates a circle with 24 points.

  var circle = new Shape(buildCurve((t)=>{x:Math.cos(2*PI*t), y:Math.sin(2*PI*t)}, 24));

Drawing clovers

Armed with this, all I need to draw a clover, is a function that will display a heart-like shape, use it to generate a Shape, and draw that Shape 3 times, with a 2*PI/3 rotation between each leaf.

WolframAlpha has a nice collection of heart functions. I used this one, with some tiny randomization of all the constant to get slightly different shapes each time:

x=16sin(t)3,y=13cos(t)5cos(2t)2cos(3t)cos(4t)x = 16\sin(t)^3, y = 13\cos(t)-5\cos(2t)-2\cos(3t)-\cos(4t)

Given this, the following code will draw a n leaves clover:

     var s = new Shape(buildCurve(cloverFunction, 64)); // 64 points heart shape

     for (var i=0;i<nleaves; ++i) // draw nleaves
     {
        s.eraseInside(drawingLayer);
        s.analogDraw(drawingLayer, drawer);
        drawingLayer.rotate(2*PI/nleaves);
     }

Here are a few of these:

Clovers are multiple heart shapes rotated by 2PI/3 (or PI/2 for 4 leaves clovers)
Clovers are multiple heart shapes rotated by 2PI/3 (or PI/2 for 4 leaves clovers)

They looked a little bit too perfect for my taste, so I eventually added a little bit of randomization to the rotation as well so they don't divide the circle so perfectly.

Drawing grass blades

For the grasses, I guess I could have used Bezier curves. I don't like Bezier curves, to be honest. They don't like me either. I always struggle to get them to look the way I want. So I used math curves again.

This desmos page shows the formula I used: 2 portions of a sine curve, displaced and scaled so they start and end at the same point.

In Javascript this becomes:

function grassFunc(x, k, a)
{
	var d = (x) => a*x*x*x*k+x*(1.0-k);

	if (x<0.5)
	{
		var t = 2*x*6*PI;
		var dt = 2*d(x)*6*PI;
		return {x: t, y: Math.sin(dt/4)+Math.sin(t/6)/3};
	}
	else
	{
		var x0 = 1-x;
		var t = 2*x0*6*PI;
		var dt = 2*d(x0)*6*PI;
		return {x: t, y:Math.sin(dt/4)};
	}
}

const k = rrnd(0,1);
const a = rrnd(0.05, 4);
var f = (x)=>(grassFunc(x,k,a));
var s = new Shape(buildCurve(f, 64));


Varying the displacement and scaling generates a lot of nice, organic looking blades, like in the picture below.

Grass blades use 2 portions of a sine curve
Grass blades use 2 portions of a sine curve

Drawing the larger leaves

The larger leaves came from WolframAlpha again, this time using the Cannabis curve with the constants slightly randomized.

Larger leaves using the Cannabis curve
Larger leaves using the Cannabis curve

SIMPLE LEAVES

There are also smaller leaves using the "folium" equation:

r=cos(θ)(4sin(θ)21)r = \cos(\theta)(4sin(\theta)^2-1)

Drawing daisies

These are actually very simple. The individual petals start their life with a circle Shape, that is stretched on one axis to turn into a thin ellipse. This ellipse is then drawn and rotated, just like for the clover leaves. There are just a lot more rotations (between 15 and 20, picked randomly).

Daisies = one circle and many ellipses
Daisies = one circle and many ellipses

Composition

With all the above elements done, all it takes is layering a lot of them to achieve beautifully complex results. Here is an example with about 500 of each.

The magic happens when you pile up many of them
The magic happens when you pile up many of them
A close-up.
A close-up.

In order to achieve more natural looking distribution of the elements, I used a system of "attractors" - for example for clovers, I pick a random point as the attractor center, and then position clovers by picking a random point in the canvas, and moving it towards the attractor center with a random weight. This has the effect of skewing the distribution of clovers around the attraction point.

Using an attractor to make more natural looking distributions
Using an attractor to make more natural looking distributions

I added a "background" drawing modes for all the elements. In this mode they are drawn with a dark fill. Then I layered a bunch of background elements, followed by a bunch of foreground ones.

The last step was to get a little more variety in the outputs. I used tried and true recipes:

A color version. Clovers, grasses, leaves... have their own shade of green, with small per-item randomization
A color version. Clovers, grasses, leaves... have their own shade of green, with small per-item randomization

There was also a rare "pink daisy" version that unfortunately, did not happen in any of the minted pieces. It is visible in an objkt collection of 13 1:1 pieces that I released afterwards.

The "Pink Daisies" variant
The "Pink Daisies" variant

Outtakes

While experimenting with the generator, I ended up with interesting pieces that unfortunately, were taking too long to generate. They are available as 1:1 objkt pieces as well, including 7 "Sunflowers" versions (where 100% of the sales and royalties go to Ukraine).

One of the outtakes with extra complexity over a "Zancan green" paper
One of the outtakes with extra complexity over a "Zancan green" paper
A "Sunflower" outtake, auctioned for Ukraine
A "Sunflower" outtake, auctioned for Ukraine

Closing words

I hope you enjoyed reading this. Cloverfield is one of these pieces where the outputs look very intricate, yet the generation itself is actually rather simple, and the complexity comes from layering a large number of elements.

stay ahead with our newsletter

receive news on exclusive drops, releases, product updates, and more

feedback