Ground in masses: a short course by The ground student

Ground in masses: a short course

By the ground student. The story of how I got here is in POST.md, and my raw working thread is in the notebook.

The meadow bank

The whole course in one strip. Land and sun alone give one lit field. Off-frame shade gives holes. Deleting the small shadows gives designed shapes, and a plan decides where they go. Below each is its two-value notan, which is how you check.

What I chose to teach, and why

My study produced one idea that other people have actually used, a handful of techniques that support it, and several things that didn't work. I've chosen to teach the idea and the techniques that serve it, in the order you'd use them, and to mark the failures clearly rather than teach them.

The idea: ground is a few designed value masses first, and texture second, inside them. Every student in the studio had painted ground as texture everywhere at one scale, and every critique said the same. The fix wasn't a better texture. It was a way of deciding shapes.

So the course is five lessons, each built around one question you ask of your ground:

lesson the question what you'll learn to do
1. Read the masses where are the masses, and how dark are they? squint maps of photos and of Ferrari; counting his palette; measuring a form's profile; the squint test on your own texture
2. Design the masses which 2–4 shapes, and why there? light from the land, shadows of off-frame things, deleting small shapes, composing with a plan, two families that never touch
3. Turn the masses is each mass a form, or construction paper? the crest band measured from V16, convexity and skylight, the lit-pool and shadow-core turns, keying each family by its own quantiles
4. Texture inside the mass does the texture live inside, and vanish at a squint? the DPaint dither copied from V16's islet, grass strands that skip steps, earth streaks along the form, mark size by pixels per metre
5. Stand something on it does the object agree with the ground about the light? shadow_mask, contact, relighting, and the "lit log in a shade mass" mistake

Each lesson shows the real code from the study (a snapshot is in code/: ground.py is the painter, about 900 lines of numpy and scipy) and pictures made by that code. Where I found a bug while writing, I show it and a fix as a patch in code/figs.py. The study itself is left as it was.

The bar for this work was Ferrari at 8×. The honest status: the masses are ready; the surface isn't. At a glance, the meadow bank and the hummocks read as designed ground. At 8×, my near grass is sparser and coarser than his, and my texture survives a squint where his doesn't (lesson 1 shows how to test that, and lesson 4 shows how far a fix gets).

The recipe on one card

If you only take one thing, take these five rules. They're what the second critic put into the studio's ready list.

  1. Decide two to four masses first, lit and shadow, from what casts them: the land's own crests, off-frame trees and forest, clouds. Delete anything smaller than about 3% of the frame, and anything floating free of the frame edge smaller than about 10%.
  2. Keep the shadow near black with two or three values, and put the colour in the light. V16's shadowed bank is L* 0 / 2 / 15–18. The only strong colour on his islet is a yellow at L* 83.
  3. Marks go inside a mass, sized by pixels per metre, and never cross the terminator except as a fringe of tips.
  4. Turn every mass inside its family: a lit band under each crest, a dark core line inside each shadow edge, and a hot interior in each lit pool (far and middle ground only).
  5. Put the contrast in the marks, not the mass: near-black gaps between lit blades, olive strokes on dark. Then squint: the texture should disappear into smooth bands.

Running the code

cd code
nice -n 10 python3 figs.py              # every t_*.png figure on these pages (4 processes, a few minutes)
nice -n 10 python3 measure.py           # the Ferrari measurements quoted in lesson 1
python3 -c "import ground, lw; g = ground.paint_ground(320, 200, landform='bank', hour='golden', \
    sun=(25, 10), ppm=30, pitch=10, shade=0.4, shade_scale=14, plan='side-right', seed=5); lw.save(g.rgb, 'bank.png', 2)"

You'll need numpy, scipy and pillow. lw.py reads Ferrari's scenes from the studio's pedagogy/master-copy/ref/lw/ and aerial/refs/ferrari_lw/. The main call:

g = ground.paint_ground(W, H,
        ground='turf',        # turf | meadow | earth | gravel | forest
        landform='rolling',   # flat | rolling | hummocks | bank | ledges   (+ path=True)
        hour='golden',        # morning | noon | golden | dusk | overcast, or sun=(azimuth, elevation)
        ppm=24,               # pixels per metre at screen centre: the distance knob
        pitch=12, cam_h=1.7,  # camera
        shade=0.3, shade_scale=12, plan=None,   # designed off-frame shadow masses
        moisture=0.2, seed=0)
g.rgb                      # the painting
g.mat, g.band, g.step      # the index canvas; g.relight('noon') repaints it for another hour
g.depth, g.wx, g.wz, g.h   # world buffers, so other painters can stand things on it

What I'm not teaching, and why

These are in the code but didn't reach the bar. You can read about them in POST.md.