The image above shows the effects of anisotropic line thickness implemented in Freestyle for Blender in the form of a custom style module written in Python. The idea is to increase line thickness when the stroke travels in a specific direction (expressed by the angle of the tangent line from the X axis evaluated at individual stroke vertices). Here the mapping from the stroke traveling direction to line thickness was expressed by pairs of angle and thickness values to allow artists to place thickness peaks at arbitrary directions (hard-coded in the script for now), and linear interpolation was used to ensure smooth thickness changes. In the test renders above, the anisotropic thickness shader was applied only to external contours. Other lines have a constant thickness.
The full listing of the style module used for the test renders is as follows:
from freestyle import *
from logical_operators import *
from shaders import *
import math
class AnisotropicThicknessShader(StrokeShader):
def __init__(self):
StrokeShader.__init__(self)
def shade(self, stroke):
if True:
angles = [-180, -135, -90, -45, 0, 45, 90, 135, 180]
thickness = [1, 5, 1, 5, 1, 5, 1, 5, 1]
if True:
angles = [-180, -120, -60, 0, 60, 120, 180]
thickness = [1, 5, 1, 5, 1, 5, 1]
if not True:
angles = [-180, -90, 0, 90, 180]
thickness = [1, 5, 1, 5, 1]
if not True:
angles = [-180, -45, 45, 135, 180]
thickness = [1, 1, 5, 1, 1]
if not True:
angles = [-180, 0, 180]
thickness = [1, 5, 1]
f = Normal2DF0D()
it = stroke.stroke_vertices_begin()
while not it.is_end:
n = -f(Interface0DIterator(it)) # normal
a = math.atan2(n[1], n[0]) # angle in radians
a = a / math.pi * 180 # angle in degrees
# linear interpolation
for i in range(1, len(angles)):
if angles[i-1] <= a <= angles[i]:
break
r = (a - angles[i-1]) / (angles[i] - angles[i-1])
t = thickness[i-1] + r * (thickness[i] - thickness[i-1])
it.object.attribute.thickness = (t/2, t/2)
it.increment()
upred = AndUP1D(ExternalContourUP1D(), QuantitativeInvisibilityUP1D(0))
Operators.select(upred)
Operators.bidirectional_chain(ChainSilhouetteIterator(), NotUP1D(upred))
shaders_list = [
SamplingShader(2),
AnisotropicThicknessShader(),
pyMaterialColorShader(0.5),
]
Operators.create(TrueUP1D(), shaders_list)
The script was tested with Blender 2.69 (may require code updates for Blender 2.70 and later).