Der Strich
Bis hierher ist ein Gesicht eine Liste von Punktzügen. Was daraus eine Zeichnung macht, sind drei Entscheidungen im Stift – und alle drei hängen daran, dass jedes Bild neu gezeichnet wird.
macheStift bekommt eine Zeichenfläche, einen Seed, eine
Tintenfarbe, einen Maßstabsfaktor und einen Takt. Zurück kommen drei
Werkzeuge: zug, flaeche, punkt.
Mehr braucht der ganze Stil nicht. Alle Maße sind Einheitsmaße – der
Aufrufer hat die Fläche längst auf Kopfgröße skaliert, eine Breite von
0.024 sind also gut zwei Prozent der Kopfhöhe.
Jeder Strich ist eine Fläche
Kein ctx.stroke(). Ein Zug ist ein Band:
die Mittellinie plus die halbe Breite nach beiden Seiten, als ein
einziges gefülltes Polygon. Der Grund ist die Breite selbst – sie soll
sich innerhalb eines Zuges ändern: dünn beim Ansetzen, voll in
der Mitte, dünn beim Abheben.
Eine Linie in Canvas hat eine Breite, und zwar überall dieselbe. Wer
die Verjüngung trotzdem will, braucht einen stroke() je
Teilstück. Bei neun Köpfen mal vierzig Zügen mal sechzig Bildern in
der Sekunde ist das der Unterschied zwischen flüssig und zäh.
Die Druckkurve ist spitz: 0 heißt stumpfe Enden, 1 heißt
spitz auslaufend, voreingestellt sind 0.75. Der Sinus-Anteil ist
bewusst flach gehalten – eine Linie, die in der Mitte doppelt so dick
ist wie an den Enden, sieht nach Pinsel aus, nicht nach Stift.
Das Band ist auch der Grund, warum es flaeche() als
eigenes Werkzeug gibt und nicht nur einen geschlossenen Zug: eine
Fläche hat keine Breite, sie hat einen Rand. Was mit ihr im Druck
passiert, steht im Kapitel Der Druck.
Der Verzug hat einen Namen
Ein handgezeichneter Strich trifft seine Sollkurve nicht. Die naheliegende Umsetzung: ein Zufallsstrom, aus dem jeder Zug seine Abweichung zieht. Sie ist falsch, und zwar nicht ein bisschen.
Symptom: Beim Blinzeln ändert nicht das Auge seine Form, sondern das halbe Gesicht – Nase, Mund und Wangen springen für drei Bilder auf eine andere Zeichnung um.
Ursache: Der Verzug hing an der Aufrufreihenfolge. Ein geschlossenes Lid ist ein Zug statt vier; alles, was danach gezeichnet wird, zieht seine Zufallszahlen um vier Stellen versetzt und ist deshalb ein anderer Strich.
Lösung: Der Verzug hängt an einer SPUR –
einem Namen: "kontur", "auge-l". Gleicher
Name plus gleicher Seed ergibt in jedem Bild dasselbe Zittern, egal
was vorher oder gar nicht gezeichnet wurde.
Aus dem Namen wird über einen FNV-Hash ein Startwert, aus dem Startwert
ein Feld von 52 Stützwerten. Es liegt in einer Map am
Stift: dieselbe Spur wird je Bild mehrfach gebraucht, und ein Kopf hat
keine hundert davon.
Die Linie kocht
Eine Handzeichnung, die sich bewegt, ist ein Trickfilm: jedes Bild ist
eine eigene Zeichnung, und keine trifft die vorige genau. Also bekommt
jede Spur einen TAKT dazu –
TAKT_JE_SEKUNDE = 8. Innerhalb eines Takts steht alles
still, zwischen zwei Takten rutscht jede Linie ein wenig.
Der Takt kommt nicht aus dem Stift, sondern von oben – der Stil rechnet
ihn beim Zeichnen jedes Kopfes aus:
takt = Math.floor(zeit * TAKT_JE_SEKUNDE + d.taktVersatz).
Der taktVersatz ist je Kopf gewürfelt. Ohne ihn setzen
neun Köpfe im selben Moment neu an, und ein Blatt, das im Gleichtakt
zuckt, sieht aus wie ein Bildfehler.
Im Stift werden dafür zwei Ströme gemischt: einer hängt nur am Seed – die Hand –, einer auch am Takt – das Bild. Die Mischung ist 0.62 zu 0.5. Nur der Bild-Strom, und die Linie springt bei jedem Takt woandershin; nur die Hand, und sie steht.
Sechzigmal in der Sekunde neu gewürfelt wäre Rauschen, achtmal ist ein Stift. Der Regler zeigt beides.
koch hängt an der Länge
Nicht jeder Zug darf gleich stark kochen. Ein Mund, der achtmal in der
Sekunde Länge und Bogen wechselt, ist kein Stift mehr, sondern Unruhe.
Deshalb misst zug() zuerst die Länge der Bahn:
| Länge | koch | wer |
|---|---|---|
| unter 0.4 | 0 – nur die Hand | Mund, Braue, Nase, Stachel |
| 0.4 bis 1.2 | gemischt | Lidbögen, Ohren |
| ab 1.2 | 1 – voll am Takt | Kontur, Haarmasse |
Dieselbe Länge steuert auch die Stärke des Verzugs (kurz,
gedeckelt auf die halbe Amplitude): der Verzug ist ein Maß im
Kopfraum, und derselbe Betrag ist auf einer langen Kontur ein
Schlingern, auf einer kurzen Braue aber ein Sprung des ganzen Strichs.
Daneben gibt es ruhig als harten Schalter. Augenringe,
Schraffuren, Stirnfalten sind blass und fein – ihr Kochen läse sich
nicht als Zittern der Hand, sondern als Flackern des Bildes.
Die zweite Lage
Unter jedem Zug liegt derselbe Zug noch einmal: halb so breit, bei
32 % Deckung – und mit eigenem Verzug
(Spur name~, Amplitude 1.7-fach plus 0.004). Genau darin
liegt der Bleistift: die zweite Lage liegt nicht auf der
ersten, sondern daneben.
einlagig: true schaltet sie ab. Das gilt für Ränder von
Farbflächen und für Zierrat, wo die Doppelung nur Matsch wäre – die
blasse Unterlippe im Grinsen etwa ist ein Haar breit, eine zweite Lage
daneben macht daraus einen Fleck.
Vom Punktzug zur Bahn
Bevor überhaupt ein Band entsteht, wird der Punktzug zu einer
gleichmäßig abgetasteten Bahn: entdoppeln, dann
catmull, dann Abtasten nach Bogenlänge. Ein Mund aus drei
Punkten muss ein Bogen werden, kein Knick.
Symptom: Kurze Linien – Brauen, Mundwinkel – zittern an ihren Enden, obwohl der Verzug an einer festen Spur hängt und gar nicht kochen dürfte.
Ursache: Die Schrittsumme trifft den Endpunkt nur bis auf Rundung. Ob der letzte Schritt gerade noch passt oder gerade nicht mehr, kippt mit jeder winzigen Längenänderung – und der Zug ist von Bild zu Bild um bis zu einen Schritt länger oder kürzer.
Lösung: Der Endpunkt gehört immer dazu. Liegt der letzte gesetzte Punkt weiter als einen halben Schritt entfernt, wird der Endpunkt angehängt; sonst ersetzt er ihn.
Geschlossene Züge laufen 3,5 % über den Anfang hinaus. Die Stelle, an der die Hand angesetzt hat, bleibt sichtbar – ein Kreis, der exakt in sich zurückläuft, ist eine Ellipse aus dem Zeichenprogramm.
Schlingern und Kratzen
Der Verzug selbst kommt aus zwei Wellen: einer groben mit 12 Stützwerten (das Schlingern) und einer feinen mit 40, mit 0.35 gewichtet (das Kratzen). Beide werden kubisch interpoliert.
Nur das Schlingern sähe aus wie ein Gummischlauch, nur das Kratzen wie ein Kurzschluss.
Ein Punkt ist kein Kreis
Ein gefüllter Kreis ist die Stelle, an der eine Zeichnung am schnellsten
nach Vektorgrafik aussieht: ctx.arc trifft die Rundung
exakt, und genau das erkennt das Auge – bei einer Pupille, einer
Sommersprosse und einem Stoppelpunkt gleichermaßen.
Also geht punkt() denselben Weg wie jeder andere Zug: ein
leicht ovaler, gekippter Ring, mit dem Rauschen dieses Stifts verzogen,
darunter ein blasser Saum vom Ausbluten. Vier Details entscheiden:
| Detail | ohne |
|---|---|
eigene spur je Punkt |
zwei Pupillen mit derselben Beule an derselben Stelle – Zwillinge |
| Rand nicht geschlossen gerechnet | das Rauschen läuft von 0 bis 1 und trifft am Ende nicht den Anfang; dort sitzt die Ansatzstelle |
| Verzug gedeckelt am Radius (0.15 r, höchstens 0.007) | aus der Sommersprosse wird eine Amöbe |
ohneSaum für Punkte, die AUF etwas liegen |
der Glanzpunkt im Auge bekommt einen blassen Rand und sieht aus wie ein Fleck |
Ein Punkt kocht nicht. Er zieht seine Spur immer ruhig, ohne Takt. Eine Pupille, die je Takt woanders sitzt, ist ein Zittern, kein Strich.
Das feld ist die letzte Zutat: die vier Werte, die ein
Feld ohnehin führt (ex, ey, fx,
fy, siehe Raum). Ohne sie
zeichnet der Punkt im Bildschirmraum – die Lidbögen eines gedrehten
Kopfes stauchen sich, die Pupille darin bleibt ein voller Kreis und
steht seitlich über die Kontur hinaus. Weggelassen wird das Feld für
alles, was nicht auf dem Kopf liegt: eine Antennenkugel steht
im Raum, keine Wange trägt sie.
Eine Hand zeichnet groß mit demselben Stift
Ein Kopf in der Großansicht ist dreimal so groß wie im Raster. Wüchse der Strich einfach mit, wäre er dort dreimal so dick – ein Filzstift. Ganz gleich bleiben darf er aber auch nicht: derselbe Pixelstrich, der groß richtig ist, ist im Raster ein Haar. Der Kommentar unten sagt, wie der Faktor zwischen beidem vermittelt.
Exponent 0.4, geklemmt auf 0.62 bis 1.3, Bezugsgröße 95 – die Größe, in der ein Kopf im Raster steht. Im Raster ist der Faktor also 1, in der Großansicht sinkt er gegen die Klemme.
Der Faktor wird einmal beim Anlegen des Stifts gesetzt
(strichFaktor(at.mass)) und multipliziert danach jede
Breite. Kein Zeichenschritt muss davon wissen.