Improvements of the Freestyle Python API as well as better integration of Freestyle into Blender were attempted in the last two weeks.
First, feature edge detection has been extended so that edges at material boundaries are detected as feature edges. The edges at material boundaries are enabled by turning on the “Material Boundaries” option in the Layers tab of the Render buttons. The following test render (using qi0.py) shows examples of edges at material boundaries. In style modules, edges at material boundaries can be tested with pyNatureUP1D(Nature.MATERIAL_BOUNDARY).
Second, new option “Crease Angle” has been added to the Layers tab of the Render buttons, to allow users to specify an angular threshold (between 0 and 180 degrees) for crease edge detection. An edge is considered a crease edge if the angle between two faces sharing the edge is smaller than the threshold. The default value is 134.43 degrees for backward compatibility. Note that a larger angle threshold leads to a larger number of crease edges and thus a larger memory consumption. The following test render (using qi0.py) shows the effects of different crease angles (i.e., the default value vs. 170 degrees).
To branch users: If you have .blend files made with an old Freestyle branch build, you may notice the Crease Angle value is set to 0. If that is the case, you need to manually set the default value (or some other appropriate value); otherwise you won’t get those crease edges that you previously had.
Finally, Freestyle’s mesh importer has been improved to make object names accessible from within style modules. ViewShape objects in the view map, as well as SShape objects that can be retrieved by ViewShape::sshape(), now have a getName() method that returns the name of the object from which each shape is created. For instance, visible feature edges of a specific mesh object (e.g., the default Cube) can be selected using a custom predicate as follows:
class ObjectNamesUP1D(UnaryPredicate1D): def __init__(self, names): UnaryPredicate1D.__init__(self) self._names = names def getName(self): return "ObjectNamesUP1D" def __call__(self, viewEdge): return viewEdge.viewShape().getName() in self._names upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ObjectNamesUP1D(["Cube"])) Operators.select(upred)
In the meantime, the dev team was working on the long-standing issue of SWIG/C++ dependency removal. Since the beginning of the Freestyle integration into Blender, lots of efforts have been made to eliminate the SWIG/C++ dependency from the Freestyle Python API, and the work is still ongoing. A major obstacle here is that it seems very difficult to completely remove the C++-style iteration syntax from the Python API. In December 2008, we implemented the Python iterator protocol in Stroke and StrokeVertexIterator as a pilot case. Initially, allowing Python-style iteration over vertices appeared a very good idea. After an in-depth review of the Freestyle code base (mainly written in C++), however, we found that C++-style iterators cannot be easily removed from the Python API simply because a large number of API functions (and a large amount of underlying C++ code) require them. Eliminating the C++-style iterators will require a considerable amount of modifications to the C++ code base that is fairly stable. Clearly, having both C++- and Python-style iterators constitutes a confusing inconsistency. The dev team is about to conclude that it is too time-consuming and not worth trying to completely exclude the C++-style iteration syntax from the Python API. We will further investigate this issue in the next weeks.