Python Scripting¶
Python Scripting-läget erbjuder fullt programmerbara linjestilar. I detta kontrolläge skrivs alla stylingoperationer som Python-skript som kallas stilmoduler i Freestyle-terminologin. Inmatningen till en stilmodul är en vykarta (dvs. en uppsättning detekterade objektkanter) och utmatningen är en uppsättning stiliserade streck.
En stilmodul består av successiva anrop av fem grundläggande operatorer: urval, kedjning, delning, sortering och skapande av stroke. Selektionsoperatorn identifierar en delmängd av inmatade feature edges baserat på ett eller flera användardefinierade selektionsvillkor (predikat). De valda kanterna bearbetas med operatörerna för kedjning, delning och sortering för att bygga kedjor av funktionskanter. Dessa operatorer styrs också av användardefinierade predikat och funktioner för att avgöra hur funktionskanterna ska omvandlas till kedjor. Slutligen omvandlas kedjorna till stiliserade streck av stroke creation-operatorn, som tar en lista med användardefinierade stroke shaders.
Pythons stilmoduler lagras i blend-filer som textdatablock. Externa stilmodulsfiler måste först laddas i Textredigeraren. Sedan kan du välja en modul från listan över laddade stilmoduler med hjälp av menyn Select i en post i stilmodulsstapeln.

En skärmdump av en stilmodul cartoon.py som laddats i textredigeraren (vänster), samt Freestyle-alternativ i Python Scripting-läget i knapparna View Layers (höger).¶
Freestyle för Blender levereras med ett antal Python-stilmoduler som kan fungera som utgångspunkt för ditt eget skrivande av stilmoduler. Se även avsnittet om Freestyle Python API i referenshandboken för Blender Python API för en fullständig beskrivning av stilmodulskonstruktioner.
![]() |
![]() |
Moduler för skrivstil¶
En stilmodul är en koddel som ansvarar för stiliseringen av Freestyle-linjeteckning. En stilmoduls indata är en uppsättning feature edges som kallas view map (ViewMap). Utdata är en uppsättning stiliserade linjer som också kallas streck. En stilmodul är strukturerad som en pipeline av operationer som gör det möjligt att bygga streck från indatakanterna i vykartan.
Det finns fem olika typer av operationer (listade med motsvarande operatörsfunktioner):
Urval Operators.select()
Kedjning
Operators.chain(), Operators.bidirectional_chain()
Uppdelning Operatorer.sequential_split(), Operatorer.recursive_split()
Sortering Operators.sort()
Skapande av stroke Operators.create()
Den ingående vykartan fylls på med en uppsättning ViewEdge-objekt. Urvalsoperationen används för att plocka upp ViewEdges som är intressanta för artister baserat på användardefinierade urvalsvillkor (predikat). Chaining-operationer tar delmängden ViewEdges och bygger kedjor genom att sammankoppla ViewEdges enligt användardefinierade predikat och funktioner. Kedjorna kan förfinas ytterligare genom att de delas upp i mindre bitar (t.ex. vid punkter där kanterna gör en skarp sväng) och genom att en del av dem väljs ut (t.ex. för att bara behålla dem som är längre än en längdgräns). Sorteringsoperationen används för att ordna kedjornas staplingsordning så att en linje kan dras ovanpå en annan. Kedjorna förvandlas slutligen till stiliserade streck genom stroke creation-operationen som applicerar en serie stroke shaders på enskilda kedjor.
ViewEdges, Chains och Strokes kallas allmänt för endimensionella (1D) element. Ett 1D-element är en polylinje som består av en serie sammanhängande raka linjer. Hörnpunkter i 1D-element kallas i allmänhet för 0D-element.
Alla operatorer verkar på en uppsättning aktiva 1D-element. Den initiala aktiva uppsättningen är uppsättningen ViewEdges i den inmatade vykartan. Den aktiva uppsättningen uppdateras av operatörerna.
Markering¶
Selektionsoperatorn går igenom varje element i den aktiva mängden och behåller endast de som uppfyller ett visst predikat. Metoden Operators.select() tar som argument ett unärt predikat som fungerar på alla Interface1D som representerar ett 1D-element. Till exempel:
Operators.select(QuantitativeInvisibilityUP1D(0))
Denna urvalsoperation använder predikatet QuantitativeInvisibilityUP1D för att välja endast de synliga ViewEdge (mer exakt de vars kvantitativa osynlighet är lika med 0). Urvalsoperatorn är avsedd att selektivt tillämpa stilen på en del av de aktiva 1D-elementen.
Det noteras att QuantitativeInvisibilityUP1D är en klass som implementerar predikatet som testar linjens synlighet, och metoden Operators.select() tar en instans av predikatklassen som argument. Testningen av predikatet för ett givet 1D-element görs faktiskt genom att anropa predikatinstansen, det vill säga genom att anropa metoden __call__ för predikatklassen. Med andra ord, metoden Operators.select() tar som argument en functor som i sin tur tar ett Interface0D objekt som argument. Freestyle Python API använder functors i stor utsträckning för att implementera predikat, såväl som funktioner.
Kedjekoppling¶
Kedjeoperatorerna verkar på uppsättningen av aktiva ViewEdge-objekt och bestämmer topologin för de framtida stroken. Tanken är att implementera en iterator för att korsa ViewMap-grafen genom att marschera längs ViewEdges. Iteratorn definierar en kedjeregel som bestämmer nästa ViewEdge att följa vid ett givet vertex (se ViewEdgeIterator). Flera sådana iteratorer tillhandahålls som en del av Freestyle Python API (se ChainPredicateIterator och ChainSilhouetteIterator). Egna iteratorer kan definieras genom att ärva klassen ViewEdgeIterator. Chaining-operatorn tar också som argument ett UnaryPredicate som arbetar på Interface1D som stoppkriterium. Kedjningen stoppas när iteratorn har nått en ViewEdge som uppfyller detta predikat under marschen längs grafen.
Kedjandet kan vara antingen enkelriktat Operators.chain() eller dubbelriktat Operators.bidirectional_chain(). I det senare fallet kommer kedjningen att fortplanta sig i de två riktningarna från startkanten.
Följande är ett kodexempel på dubbelriktad kedjekoppling:
Operators.bidirectional_chain(
ChainSilhouetteIterator(),
NotUP1D(QuantitativeInvisibilityUP1D(0)),
)
Chaining-operatorn använder ChainSilhouetteIterator som chaining-regel och stoppar chaining så snart iteratorn har kommit till en osynlig ViewEdge.
Chaining-operatorerna bearbetar uppsättningen av aktiva ViewEdge-objekt i ordning. De aktiva ViewEdges kan sorteras tidigare med hjälp av metoden Operators.sort() (se nedan). Den startar en kedja med den första ViewEdge i den aktiva uppsättningen. Alla ViewEdges som redan har varit inblandade i kedjeprocessen markeras (i exemplet ovan ändras tidsstämpeln för varje ViewEdge som standard), för att inte bearbeta samma ViewEdge två gånger. När kedjan når en ViewEdge som uppfyller stoppredikatet, avslutas kedjan. Därefter startas en ny kedja från den första omarkerade ViewEdge i den aktiva uppsättningen. Denna operation upprepas tills den sista omarkerade ViewEdge i den aktiva uppsättningen har bearbetats. I slutet av kedjeoperationen sätts den aktiva uppsättningen till de kedjor som just har konstruerats.
Delning¶
Delningsoperationen används för att förfina topologin i varje kedja. Splittringen utförs antingen sekventiellt eller rekursivt. Sekventiell delning Operators.sequentialSplit() i sin grundläggande form, analyserar kedjan med en given godtycklig upplösning och utvärderar ett unärt predikat (arbetar med 0D-element) vid varje punkt längs kedjan. Varje gång predikatet är uppfyllt delas kedjan upp i två kedjor. I slutet av den sekventiella delningsoperationen sätts den aktiva uppsättningen kedjor till de nya kedjorna:
Operators.sequentialSplit(TrueUP0D(), 2)
I det här exemplet delas kedjan varannan enhet. I en mer utvecklad version används två predikat i stället för ett: Ett för att bestämma startpunkten för den nya kedjan och det andra för att bestämma dess slutpunkt. Denna andra version kan leda till en uppsättning kedjor som är disjunkta eller som överlappar varandra om de två predikaten är olika (se Operators.sequentialSplit() för mer information).
Rekursiv delning Operators.recursiveSplit() utvärderar en funktion på 0D-elementen längs kedjan med en given upplösning och hittar den punkt som ger det maximala värdet för funktionen. Kedjan delas sedan i två delar vid den punkten. Denna process upprepas rekursivt på var och en av de två nya kedjorna tills den ingående kedjan uppfyller ett användardefinierat stoppvillkor:
func = Curvature2DAngleF0D()
Operators.recursive_split(func, NotUP1D(HigherLengthUP1D(5)), 5)
I kodexemplet ovan delas kedjorna rekursivt vid punkter med den högsta 2D-krökningen. Krökningen utvärderas vid punkter längs kedjan med en upplösning på 5 enheter. Kedjor som är kortare än 5 enheter kommer inte att delas längre.
Sortering¶
Sorteringsoperatorn Operators.sort() ordnar staplingsordningen för aktiva 1D-element. Den tar som argument ett binärt predikat som används som en ”mindre än”-operator för att ordna två 1D-element.
Operators.sort(Length2DBP1D())
I det här kodexemplet använder sorteringen det binära predikatet Length2DBP1D för att sortera objekten Interface1D i stigande ordning med avseende på 2D-längd.
Sorteringen är särskilt användbar när den kombineras med kausal densitet. Den kausala densiteten utvärderar nämligen densiteten i den resulterande bilden när den modifieras. Om vi vill använda ett sådant verktyg för att ta bort streck när den lokala densiteten är för hög, är det viktigt att kontrollera i vilken ordning strecken ritas. I det här fallet skulle vi använda sorteringsoperatorn för att se till att de ”viktigaste” linjerna ritas först.
Skapande av stroke¶
Slutligen tar operatorn Operators.create() den aktiva uppsättningen kedjor som indata och bygger stroke. Operatorn tar två argument. Det första är ett unärt predikat som fungerar på Interface1D och som är utformat för att göra ett sista urval i uppsättningen kedjor. En kedja som inte uppfyller villkoret kommer inte att leda till en Stroke. Den andra inmatningen är en lista med shaders som kommer att ansvara för skuggningen av varje byggd stroke.
shaders_list = [
SamplingShader(5.0),
ConstantThicknessShader(2),
ConstantColorShader(0.2,0.2,0.2,1),
]
Operators.create(DensityUP1D(8,0.1, IntegrationType.MEAN), shaders_list)
I det här exemplet används predikatet DensityUP1D för att ta bort alla kedjor vars medeltäthet är högre än 0,1. Varje kedja omvandlas till en stroke genom att den samplas om så att den får en punkt var 5:e enhet och tilldelas en konstant tjocklek på 2 enheter och en konstant mörkgrå färg.
Användarkontroll på rörledningsdefinitionen¶
Stilmodulskrivning erbjuder olika typer av användarkontroll, även om enskilda stilmoduler har en fast pipelinestruktur. En är sekvenseringen av olika kontrollstrukturer för pipelinen, och en annan är genom definitionen av funktorobjekt som skickas som argument längs hela pipelinen.
Olika kontrollstrukturer för pipeline kan definieras genom att sekvensera operationerna för urval, kedjning, delning och sortering. Skapandet av en stroke är alltid den sista operationen som avslutar en stilmodul.
Predikat, funktioner, kedjande iteratorer och stroke shaders kan definieras genom att ärva basklasser och åsidosätta lämpliga metoder. Se referensmanualens poster för följande basklasser för mer information om de konstruktioner som kan skriptas av användaren.
Se även
Predikat, funktioner, kedjande iteratorer och stroke shaders kan definieras genom att ärva basklasser och åsidosätta lämpliga metoder. Se Freestyle python-modul
för mer information om de konstruktioner som kan skriptas av användaren.