Freestyle integration into Blender

April 9, 2014

Experimental variable line thickness shaders

Filed under: Update — The dev team @ 2:24 AM

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

crease_thickness_tn

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

contour_thickness_tn

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)

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: