Blender 2.72: Freestyle NPR Rendering
Freestyle for Cycles
The Freestyle line rendering engine has been integrated into Cycles (D632) in addition to the integration into the Blender Internal (BI) in Blender 2.67. Freestyle provides Cycles with a variety of non-photorealistic (NPR) stylized line rendering options applicable to but not limited to cartoon animation, architectural visualization, product blueprints, and computer-generated sketches.
Most Freestyle options work in the same way for both Cycles and BI. Line textures in Freestyle for Cycles are defined by means of shader nodes (Freestyle for BI relies on the conventional texture mapping and influence panels). Two Freestyle-specific shader nodes have been added.
- Line Style Ouput node: Specifies how to mix the colors and alpha transparency of textures into the base color and base alpha transparency of line styles.
- UV Along Stroke input node: Gives access to UV maps (with and without stroke tips) defined along strokes. These UV maps become available only during the Freestyle rendering process. Hence the UV Along Stroke node cannot be replaced by the conventional UV Map input node which takes an existing UV map already defined as part of mesh data.
The following screen capture shows a typical shader node tree that maps a floral texture image along strokes. The UV Along Stroke input node retrieves UV maps defined by Freestyle along generated strokes, and feeds them to the Vector input channel of the Image Texture node. A texture image is selected in the Image Texture node, and its color is fed to the Alpha channel of the Line Style Output node. Since the Alpha Factor is set to one, the texture image replaces the base alpha transparency of the active line style (shown in the Freestyle Line Style panel). On the other hand, the Mix blend mode is selected in the Line Style Output node with the Color Factor set to zero, so that the gradient line color specified in the active line style is applied along strokes.
It is noted that the texture image (FS_floral_brush.png) shown in the screen capture is an example of Freestyle brush images with tips. Specifically, the upper half of the image is used as a seamless horizontal tile of the stroke body, whereas the parts in the lower half are tips (stroke caps) at both ends of the stroke.
- Freestyle preview rendering in the 3D viewport is not supported yet in Cycles.
- Material color/alpha/thickness modifiers work as expected only when the Material Attribute is set to Line Color (see the next section) or one of its RGB components.
Line color properties for BI and Cycles
A new Freestyle-specific color property named Freestyle line has been introduced in material ID data blocks. The rationale is that there were no material color properties commonly used by both Cycles and BI (except for the diffuse color of BI materials, which is also used by Cycles when shader nodes are disabled). The new color property provides users with a reliable way to specify line colors on a per-material basis, no matter what rendering engine is used for Freestyle renders.
In addition, another property named line color priority (shown next to the line color in the UI) has also been introduced in order to specify the ordering of competing line colors at material boundaries. A use case of the line color priority is detailed in a Freestyle development blog article (external link).
Freestyle Python API updates
The implementation of the Freestyle Python API has been significantly improved through a number of contributed code updates (D319, D545, D623, and D752). Freestyle comes with a number of predefined style modules written in Python that are intended to provide coder-artists with examples of Freestyle Python scripting. Hence the code readability of the existing Python scripts has been a major concern of Freestyle development. It is also shown that applying more Python-like coding practices to Freestyle style modules may lead to performance improvements in terms of rendering speed. These work elements were addressed by the contributed patch sets which underwent repeated reviews and careful revisions for better code readability and run-time performance.
User-visible API updates include:
- The built-in function reversed() when applied to a Stroke object returns a new iterator that iterates over stroke vertices backward from the end. It works in the same way with other Python sequence objects. This is in effect identical to Stroke.stroke_vertices_end().
- StrokeVertexIterator has now .incremented(), .decremented() and .reversed() methods that return a new incremented, decremented and reversed iterator object, respectively.
- The constructors of Interface0DIterator and StrokeVertexIterator now accept a Stroke object (in effect identical to Stroke.vertices_begin() and Stroke.stroke_vertices_begin(), respectively).
- These iterator classes also have a new .at_last property whose value is true if the iterators point the last element. This property is necessary to stop iteration when explicitly performed by applying the next() built-in function to the iterators.
The following Python code is a typical stroke shader that uses a function (Normal2DF0D for example) applied to individual stroke vertices. Note that the iteration over stroke vertices in the user-defined shade() method is written in the old syntax prior to the documented API changes.
class myNormalDependentStrokeShader(StrokeShader): def __init__(self): StrokeShader.__init__(self) self.getNormal = Normal2DF0D() def shade(self, stroke): it = stroke.stroke_vertices_begin() while not it.is_end: normal = self.getNormal(Interface0DIterator(it)) vertex = it.object ... # vertex attribute updates here ... it.increment()
With the extended Python API, the shade() method can now be much simplified as follows:
class myNormalDependentStrokeShader(StrokeShader): def __init__(self): StrokeShader.__init__(self) self.getNormal = Normal2DF0D() def shade(self, stroke): it = Interface0DIterator(stroke) for vertex in it: normal = self.getNormal(it) ... # vertex attribute updates here ...
It is also remarked that the next() function and an iterator's .object property cannot be mixed, since next() first increments the iterator and then returns the pointed object (except for the first element, which is returned without the increment operation).
To Thomas Dinges and Sergey Sharybin for code reviews of Freestyle line rendering in Cycles. Special thanks go to Folkert de Vries (flokkievids) for his contributions to Freestyle Python API updates.