Creating Freestyle modules






Hi Guys!
Welcome to metalix, today I am finishing my tutorial on using freestyle!
Part two we look at actually creating your own style modules!
So hopefully what you learn here will teach you what you need to know to modify the colors thickness etc in your freestyle renderings :D

So firstly if you want to learn how to use freestyle, and what it is, check out part one here
And remember you can download the resources at the end of this tutorial,
and click on an image to enlarge it.

Step one
Set up blender.

So of course we need to open blender,
Load in any model of your choosing, I will be using my Air Assault Drone as an example.
Set all your materials to white(1.0,1.0,1.0) shadeless material, and your backgourd to white paper sky,
When you render you should now just see white.

So we will be making these scripts in the text editor, which means you will need to split the window so you can see both your model and your text editor.
And now pull the top down a little so you can see the info console – fig 1.2
It will also help for you to turn on “Line number”, “Word Wrap”, and “syntax highlighting”, These three buttons are located to the right of “+New”, – fig 1.2

Alright now that our windows are setup we can set up our file.
What we need to do is click on “+New” to create a new file, and then save the file with the rest of the freestyle modules.
To do this we click Text->Save As->file.py
BUT WAIT, make sure you get the right directory!
Navigate to your blender folder->blender version->scripts->freestyle->style_modules
Ex: \blender25-win64-Freestyle\2.57\scripts\freestyle\style_modules\
If you can’t find this directory, you may need to install a valid freestyle blender from graphicall.org

Now remember the file name you save it as, it must be a .py file, I saved mine as metalix.py

Ok, we are almost ready to rock and roll!
But one more thing first, we need to enable freestyle!
In the properties panel to the right, in the “Render” tab, scroll down to “Post Processing” and check “Freestyle” -> fig 1.3
Awesome, now scroll up to the “Freestyle” and make sure the Control Mode is set to “Python Scripting Mode”
Now Your Raycasting Algorith can pretty much be whatever you like, I’m using “Unculled Cumulative Visibility Detection” – Fig 1.3

Almost done!
But we now need to load in our new script, to do this, click “Add Freestyle Module”, click the little folder icon and navigate to the file you just saved, ex: \blender25-win64-Freestyle\2.57\scripts\freestyle\style_modules\metalix.py

And we are done!
We are all set up to begin making freestyle modules!

Step 2
Create The Freestlye Template

Time to actually create the freestyle module,
First things first, we need to import all the files required to make the modules work:

from freestyle_init import *
from logical_operators import *
from PredicatesU1D import *
from PredicatesB1D import *
from Functions0D import *
from shaders import *

So heres a breakdown:
It’s a little backwards but heres what each line is saying
import everything from freestyle_init.py
make sense?
* -> everything/all
so we need to import the 6 files needed using those lines.

Ok so moving on, we have a couple more lines to add:

Operators.select(QuantitativeInvisibilityUP1D(0))
Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0)))

Now that one sounds confusing!
alright so lets explain:
Operators.select -> select use the select function within the Operators class (Don’t worry if this is too confusing)
select(QuantitativeInvisibilityUP1D(0)) -> Ok so this one is confusing, basically we are telling it to select only the edges that are not hidden by any other faces.
In other words, if a plane is behind another plane, it won’t show up in freestyle strokes,
Heres another example:
QuantitativeInvisibilityUP1D(1)-> Select only the edges behind one face
QuantitativeInvisibilityUP1D(2)-> Select only the edges behind two faces, and so on.

Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0)))
Such a big line!
ok so bidirectionalChain is splitting the strokes, ChainSilhouetteIterator is determining when a curved surface reaches a point in visibility it can be defined as an edge (Like a horizon), and NotUP1D(QuantitativeInvisibilityUP1D(0) same as above.
Basically the only thing you will change here is QuantitativeInvisibilityUP1D(0) to a different levle (1) or (2)
So don’t worry if that is too much to take in, you don’t actually need to understand it.

shaders_list = 	[
		]
		
Operators.create(TrueUP1D(), shaders_list)

A nice and simple one for you now :D
shaders list -> an array of customizable shaders.
Operators.create -> create the stroke shader using the TrueUP1D profile, and the custom shaders list.
Ok I have no idea what the TrueUP1D profile is, but I tried many varieties here, and they all looked the same!
So just trust me, :P

Now press Alt+S to save the text file, and press F12 to render, now it should have a basic outline, but make sure you don’t see any red errors up the top, if you do then there is likely a spelling mistake. see this example:

This is what you should have so far: (press Alt+S to save)

from freestyle_init import *
from logical_operators import *
from PredicatesU1D import *
from PredicatesB1D import *
from Functions0D import *
from shaders import *

Operators.select(QuantitativeInvisibilityUP1D(0))
Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0)))
shaders_list = 	[
		]
		
Operators.create(TrueUP1D(), shaders_list)

And This is what it should look like when you render (provided you save your text file)

And that is it!
Your freestyle template is ready to go
Lets start by adding in some shaders

Step 3
Create The Freestlye Shaders
Ok so now we need to get the shaders going
So the format af a shader looks like this:

shaders_list = 	[
		function(value),
		function(value),
		function(value)
        ]

Nice and straightforward. And here is a list of available functions that make sense to me (documentation is terrible :P )

Type Shader Example Description
Samples pySamplingShader(int) pySamplingShader(50) Increases corner samples, lower makes wide corners, high is sharper
Samples SamplingShader(int) SamplingShader(50) Overall samples of strokes
Stroke BezierCurveShader(int) BezierCurveShader(10) Maximum distance between original geometry and curve
Stroke ConstantThicknessShader(int) ConstantThicknessShader(10) Constant Thickness of stroke
Stroke IncreasingThicknessShader(min,max) IncreasingThicknessShader(1,50) Gives a tapered look to the stroke
Stroke pyNonLinearVaryingThicknessShader(Tip,Max,Root) pyNonLinearVaryingThicknessShader(4,25, 0.6) Gives a contoured look to the stroke
Colour TextureAssignerShader(int) TextureAssignerShader(6) Gives a faint texture to the stroke, only visible on close up, values 1-7
Colour ConstantColorShader(R,G,B,A) ConstantColorShader(0.2, 0.2, 0.2,1.0) Gives a constant colour to the stroke
Colour IncreasingColorShader(R,G,B,A,R,G,B,A) IncreasingColorShader(1,0,0,1,0,0,1,1) Blends the stroke from one colour to another
Other pyTVertexRemoverShader() pyTVertexRemoverShader() Affects end of stroke
Other TipRemoverShader(int) TipRemoverShader(3.0) Affects end of stroke

int = Number
R = Red Channel
G = Green Channel
B = Blue Channel
A = Alpha Channel

Ok so there is my quick overview of the settings I know how to use, so lets try them out.

Samples -> I like to use 50 for each as I like the result, and it doesn’t take long anyway.
Lets add a medium thick stroke, that fades to thin, and fades from black to blue, as an example.
We will also use the two “Other” removeShaders as it gives a nice extended look to the ends.

from freestyle_init import *
from logical_operators import *
from PredicatesU1D import *
from PredicatesB1D import *
from Functions0D import *
from shaders import *

Operators.select(QuantitativeInvisibilityUP1D(0))
Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0)))
shaders_list = 	[
		pySamplingShader(50),
		BezierCurveShader(5),
		SamplingShader(50),
		IncreasingThicknessShader(1,20), 
		IncreasingColorShader(0,0,0,1,0,0,0.8,1),
		pyTVertexRemoverShader(),
		TipRemoverShader(3.0)
		]
		
Operators.create(TrueUP1D(), shaders_list)

Which gives us an “Indian ink” style look.
See below:

Ok so now we know what were doing!

Lets jump back to the Quantititave invisibility
What I want you to do now is save your text file as two more files, metalix_1.py and metalix_2.py, or whatever you want,
But that is how I will refer to them.
In metalix_1.py change QuantitativeInvisibilityUP1D(0) to (1),
And lower the thickness to something like 2,10.

Operators.select(QuantitativeInvisibilityUP1D(1))
Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(1)))
shaders_list = 	[
		IncreasingThicknessShader(2,10), 
		]
		
Operators.create(TrueUP1D(), shaders_list)

Now for metalix_2.py we will raise the QuantitativeInvisibilityUP1D(0) to (2),
And lower the thickness further

Operators.select(QuantitativeInvisibilityUP1D(2))
Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(2)))
shaders_list = 	[
		IncreasingThicknessShader(2,5), 
		]
		
Operators.create(TrueUP1D(), shaders_list)

So now we hav three seperate files:

metalix.py

from freestyle_init import *
from logical_operators import *
from PredicatesU1D import *
from PredicatesB1D import *
from Functions0D import *
from shaders import *

Operators.select(QuantitativeInvisibilityUP1D(0))
Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0)))
shaders_list = 	[
		pySamplingShader(50),
		BezierCurveShader(5),
		SamplingShader(50),
		IncreasingThicknessShader(1,20), 
		IncreasingColorShader(0,0,0,1,0,0,0.8,1),
		pyTVertexRemoverShader(),
		TipRemoverShader(3.0)
		]
		
Operators.create(TrueUP1D(), shaders_list)

metalix_1.py

from freestyle_init import *
from logical_operators import *
from PredicatesU1D import *
from PredicatesB1D import *
from Functions0D import *
from shaders import *

Operators.select(QuantitativeInvisibilityUP1D(1))
Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(1)))
shaders_list = 	[
		pySamplingShader(50),
		BezierCurveShader(5),
		SamplingShader(50),
		IncreasingThicknessShader(2,10), 
		IncreasingColorShader(0,0,0,1,0,0,0.8,1),
		pyTVertexRemoverShader(),
		TipRemoverShader(3.0)
		]
		
Operators.create(TrueUP1D(), shaders_list)

metalix_2.py

from freestyle_init import *
from logical_operators import *
from PredicatesU1D import *
from PredicatesB1D import *
from Functions0D import *
from shaders import *

Operators.select(QuantitativeInvisibilityUP1D(2))
Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(2)))
shaders_list = 	[
		pySamplingShader(50),
		BezierCurveShader(5),
		SamplingShader(50),
		IncreasingThicknessShader(2,5), 
		IncreasingColorShader(0,0,0,1,0,0,0.8,1),
		pyTVertexRemoverShader(),
		TipRemoverShader(3.0)
		]
		
Operators.create(TrueUP1D(), shaders_list)

How lovely, all making sense now?

So of course repeat part of step 1 and load your 2 new python files into the freestyle panel.
Hit render and yay! extra awesomeness!
See the diagram below

So that's it!
Hope you learnt something here, let me know what you think, should I write more text tutorials?
And post links to your renders, I want to see your awesomeness!

So thats all for today, my names Alex Telford, have a good one!

Bookmark the permalink.