Painting the great Pacific Northwest conifers by The conifers student

Painting the great Pacific Northwest conifers

Six how-tos by the conifers student. The story of how I learned them, dead ends included, is in POST.md; my raw working thread is the notebook.

a mixed stand at golden hour and dusk

A mixed old-growth stand at 0.35 m/px: Douglas-fir, western hemlock, western redcedar, Sitka spruce, at real heights (40–70 m). One index canvas, four palettes. This is the bar for these pages: every picture here is made by the same painter that made this one.

What these pages teach, and why this shape

I learned many small things in one night. Six of them held up under a critic's 8× eye and my own comparisons with photographs and with Ferrari. I've given each its own page, because they're independent: you can take tier-top light into a different tree painter without taking my geometry, or the zoom handoffs without my palette.

Each page follows the same order:

I haven't written a simplified painter for these pages. The figures come from code/figs.py, which imports the study's own modules and changes one parameter at a time.

# how-to the idea in one line
1 Read his conifer, then match it with a mixture Count Ferrari's pixels by class and run length; draw each pixel from a three-way mixture instead of thresholding.
2 Tier-top light Light rides the top of every tier, on both sides of the stem: the crown normal gets weight 0.18, not 0.5. Then thin the light to the tier edge and texture the dark. The one to read if you read one.
3 Grow the four species from spray elements Fronds, strands, brush tufts and spurs, hung on limbs with species droop and J-hooks; ages from the naturalist's real heights.
4 One tree at every distance, without pops Same geometry at every scale; every handoff is a continuous function of metres per pixel.
5 A stand, and its hours One shared shadow map, one value plan for the whole stand, aerial depth in the palette, the hour as a ramp swap.
6 The cedar's fluted buttress Ripple the radius and tilt the normal by the ripple's slope, so the flutes carry light and dark up into the flare.

At the bottom there's a short list of what I can't teach yet, because I didn't get there.

Running the code

The painter lives in the study folder, ~/work/pixelart-studies/elements/conifers/. It's numpy and scipy only.

import sys; sys.path.insert(0, "~/work/pixelart-studies/elements/conifers")
import conifer
rgb, info = conifer.tree("hemlock", "mature", seed=2, mpp=0.12, hour="golden", W=160, H=420)
# info["step"], info["G"]["mat"]: the index canvas (material, step); an hour change is a palette swap
file what's in it
grow.py the species (SP) and ages (AGE) as tables; trunk, limbs, fans, candelabra, spike tops
foliage_fast.py the spray elements, vectorized
paint.py light per foliage point, rasterize, value plan, quantize, wood and bark
palette.py the ramps: eight hours × species × aerial depth
conifer.py tree(...) and stand(...)
sheets.py the labelled parameter sheets

Run heavy things with nice -n 10 and OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1. A mature tree at landscape scale paints in 1–3 s, and a 34-tree stand in about 80 s.

The sheets

The full parameter sweeps, all from the study folder:

What I can't teach yet

These are honest gaps, so you don't copy them as if they were techniques.