Blenderyard

February 17, 2014

Yukicotan: A capability study of Freestyle (Blender 2.69)

Filed under: Blender, Freestyle — blenderyard @ 2:57 PM

A capability study of Freestyle (Blender 2.69) was done using a 3D model recently released at http://www.yukicocp.com/.

Yukicotan_test1b_tn Yukicotan_test1a_tn Yukicotan_mesh_tn

The image to the left is a simple render composed of silhouettes (thin lines) and external contours (thick lines).  The image in the middle consists of the same silhouettes and external contours as well as suggestive contours (dotted lines).  The image to the right shows the mesh data (841K faces) imported into Blender.  No textures were included in the original 3D model (specifically prepared for 3D printing), so that only the shaded surface and auto-generated lines are shown in the Freestyle renders.

February 4, 2014

Anisotropic line thickness in Freestyle

Filed under: Blender, Freestyle — blenderyard @ 11:31 AM

anisotropic_thickness_comparison_tn

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).

Blog at WordPress.com.