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 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.
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.
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 full parameter sweeps, all from the study folder:
These are honest gaps, so you don't copy them as if they were techniques.