A discussion in the bf-blender-npr mailing list turned out to be productive with new ideas and artist-driven coding experiments. This blog article presents two experimental Python style modules for Freestyle in Blender as a result of the discussion. The scripts have been tested with Blender 2.70.

## Crease angle dependent thickness

Video clip: vimeo.com/91306354

This style module draws crease lines with variable line thickness depending on the angle between the two faces on both sides of each crease line segment.

from freestyle.chainingiterators import * from freestyle.predicates import * from freestyle.shaders import * from freestyle.types import Operators import math class CreaseAngleDependentThicknessShader(StrokeShader): def __init__(self, angle1, angle2, thickness1, thickness2): StrokeShader.__init__(self) self.__a1 = angle1 self.__a2 = angle2 self.__t1 = thickness1 self.__t2 = thickness2 def shade(self, stroke): delta_a = self.__a2 - self.__a1 delta_t = self.__t2 - self.__t1 fac = 1 / delta_a for v in stroke: fe = v.first_svertex.get_fedge(v.second_svertex) if not fe.is_smooth: angle = math.degrees(math.acos(-fe.normal_left.dot(fe.normal_right))) if angle < self.__a1: t = self.__t1 elif angle > self.__a2: t = self.__t2 else: t = self.__t1 + delta_t * (angle - self.__a1) * fac #print(angle, t) v.attribute.thickness = (t/2, t/2) upred = AndUP1D(QuantitativeInvisibilityUP1D(0), pyNatureUP1D(Nature.CREASE)) Operators.select(upred) Operators.bidirectional_chain(ChainSilhouetteIterator(), NotUP1D(upred)) shaders_list = [ SamplingShader(5.0), CreaseAngleDependentThicknessShader(70, 120, 5, 0), ConstantColorShader(0, 0, 0), ] Operators.create(TrueUP1D(), shaders_list)

## Curvature dependent contour line thickness

Video clip: vimeo.com/91383521

This style module draws contour lines with variable line thickness as a function of radial curvatures. In short, curvatures are a property of surface that tells you how quickly the surface bends. With the script below, thicker contour lines are drawn when the contours lie on more quickly bending areas of the surface, while thinner lines appear in more flat areas.

from freestyle.chainingiterators import * from freestyle.predicates import * from freestyle.shaders import * from freestyle.types import Operators import math class VariableContourThicknessShader(StrokeShader): def __init__(self, Kr1, Kr2, thickness1, thickness2): StrokeShader.__init__(self) self.__k1 = Kr1 self.__k2 = Kr2 self.__t1 = thickness1 self.__t2 = thickness2 def shade(self, stroke): delta_k = self.__k2 - self.__k1 delta_t = self.__t2 - self.__t1 fac = 1 / delta_k for v in stroke: c1 = v.first_svertex.curvatures c2 = v.second_svertex.curvatures if c1 is None and c2 is None: v.attribute.thickness = (0, 0) continue if c1 is None: Kr = abs(c2[4]) elif c2 is None: Kr = abs(c1[4]) else: Kr = abs(c1[4]) + v.t2d * (abs(c2[4]) - abs(c1[4])) if Kr < self.__k1: t = self.__t1 elif Kr > self.__k2: t = self.__t2 else: t = self.__t1 + delta_t * (Kr - self.__k1) * fac #print(Kr, t) v.attribute.thickness = (t/2, t/2) upred = QuantitativeInvisibilityUP1D(0) Operators.select(upred) Operators.bidirectional_chain(ChainSilhouetteIterator(), NotUP1D(upred)) shaders_list = [ #SamplingShader(1), VariableContourThicknessShader(0.001, 0.01, 0, 10), ConstantColorShader(1, 0, 0), ] Operators.create(TrueUP1D(), shaders_list)