Freestyle integration into Blender

October 23, 2012

Development updates on October 23

Filed under: Update — The dev team @ 9:09 PM

Development in the Freestyle branch for the last two months was kind of quiet but still includes several important bug fixes and improvements in rendering stability and quality.  Here is a short summary of code base updates from a technical perspective.

Code base updates

1. Experimental fix for incorrect view edge visibility

Given a 3D scene populated with mesh objects, Freestyle generates a data structure called view map consisting of view edges.  Each view edge is basically a polyline, i.e., a series of connected straight edges (referred to as FEdges) originated from the input mesh objects.

The problem addressed here is an ages old issue that the visibility of view edges in the view map may be incorrect. The main cause of this issue is that view edges are constructed from a series of FEdges without testing the visibility of individual edges being concatenated.  In a subsequent processing stage the view edges are split into pieces if two view edges intersect with each other in the 2D image coordinate system.  The visibility of the view edges is then computed by taking account of occluding faces in the 3D scene.  In many cases this procedure results in correct line visibility, but not always (that is the problem).

A simple solution experimentally implemented here is not to chain FEdges at all.  Instead, view edges are constructed from at most one FEdge now.  This leads to better line visibility results, but at the cost of a much larger view edge count, which may impose a performance penalty in the following processing stages.  For now this solution is only applied to sharp FEdges (roughly corresponding to edges in the input mesh data; specifically, silhouette, crease, border, edge mark, contour, external contour, and material boundary).

A better solution would be to reorder the three steps of view edges construction mentioned above, i.e., first splitting FEdges at 2D intersection, computing the visibility of the FEdges, and then concatenating them to build view edges.  This solution will require a bigger refactoring, and thus is left for future work at the moment.

2. Performance improvements of temporary scene generation for stroke rendering

Two-dimensional strokes (e.g., silhouette and crease lines) are automatically generated from a given 3D scene and superimposed on top of the Combined pass.  For this purpose, a temporary scene populated by mesh data representing the 2D strokes is created and rendered with the Blender Internal (BI).

Individual strokes are translated into distinct mesh objects, resulting in a large number of mesh objects. This is especially true when chaining is disabled and strokes are made of at most one view edge.  Because of the aforementioned change in the view map construction, the view map is likely populated by a large number of view edges (e.g., on the order of ten thousand).  As a result, the temporary scene generation may take an appreciable amount of time.  This issue was reported by a branch user with a fairly complex 3D scene that results in more than 11000 strokes.

In a discussion of this issue in the bf-committers mailing list, Joshua Leung (aligorith) kindly provided the dev team with insightful performance analysis results concerning the generation of many mesh objects at once.  As a matter of fact, mesh objects are full Blender objects and not intended to be a lightweight data structure for quick throwaway geometry generation in a time-critical loop.  A solution suggested by Joshua is to extend the BI to render stroke meshes through a new lightweight data structure specifically designed for that purpose.  Another possible direction is to rely on an external 2D rendering engine as discussed earlier.  Because of other priority tasks in the branch development, these solutions are kept for future options.

For now, a quick attempt was made to optimize the performance of temporary scene generation directly based on the performance analysis results by Joshua.  The following plots compare the performance of stroke mesh generation before (left) and after the performance optimization (right).


The performance improvement is significant with the average time per stroke 15 times shorter than the non-optimized timing result.  Still it can be seen that the elapsed time per mesh object tends to increase over time (because of a linear search over existing objects in the scene to make object names unique).  Additionally, there is some non-linear time component, whose source is unknown at the moment and further performance analysis is required.

3. Additional improvements

  • Fix for OCIO-based color management not working properly with Freestyle.
  • New button to make a copy of the active modifier in the Parameter Editor mode.  Code contribution by flokkievids, thanks!

User artwork showcase

An active user base is a key for a successful free software project.  In this sense the Freestyle integration project is very well supported by an increasing number of computer graphics artists all over the world.  Here is a mini gallery of selected artwork by three branch users.

“Fries” by Rylan Wright (RONIN) is a funny stop motion animation clip showing a conversation between two friends of him trying to figure out what to have for lunch.

The following fan-art image of Japanese Anime “Kei-On!” is done by Mohe & Shiratama (Moonlight Jellyfish).  Their modeling and rendering workflow is illustrated in this blog article (in Japanese).

“Japanese Railway’s 140th Anniversary” by mato.sus304 is a series of cool scenery shots showing trains in urban areas.  A making-of blog article about the production workflow of this movie clip is available here (in Japanese).

Thank you RONIN, Mohe & Shiratama, and mato.sus304 for using Freestyle for the excellent artwork!



  1. I just built freestyle from source to test it out, and one thing I noticed pretty quickly is that the input for adding multiple render layers is missing, is that intentional? Is there a way to have objects use different line styles with out rendering them separately? Say you want one object to be outlined in blue and another in orange, is that possible with out rendering them separately?

    Comment by ichabocole — November 17, 2012 @ 1:35 AM

    • The Layers panel has been moved from the Render tab to its own tab (called Layers tab), based on the code review of the Freestyle branch by Brecht and the following discussions. The new Layers tab appears when you click the button next to the Render tab button. See the following bf-committers thread for more informaton on the rationale of the changes.

      Comment by The dev team — November 17, 2012 @ 1:56 AM

  2. Any updates since October?

    Comment by Barts — February 7, 2013 @ 1:31 PM

    • Since the first round of branch code review by core developers, most updates in the Freestyle branch have been addressed to the requests and suggestions from the review results. There are many user-visible changes, as well as internal fixes and code style clean-ups. Remarkably a large fraction of recent updates were contributed by Bastien Montagne. Because of a major lack of spare time, I have to focus on coding so as to meet time conditions toward a potential inclusion into the 2.67 release. I will post a blog update as soon as possible.

      Comment by The dev team — February 7, 2013 @ 11:23 PM

      • I think it might be a good time for another update. It’s been half a year since the last one.

        Comment by Barts — April 18, 2013 @ 11:52 AM

  3. Hello.
    I have modified the SVGWriter to work in parameter editor mode by changing the file.

    Hope you find some use for it.

    Regards Gustav Svensson

    The changes in were as follows:

    Added to imports:
    import bpy
    import os
    from Freestyle import *

    Defined: (note the added -tag)
    _SVGHEADER = “””\

    _SVGPATH = “””\

    _SVGFOOTER = “””\


    Added the class:
    class SVGWriter(StrokeShader):
    def __init__(self):
    scene = Freestyle.getCurrentScene()
    w = scene.render.resolution_x
    h = scene.render.resolution_y
    output_dir = bpy.path.abspath(scene.render.filepath)
    if not os.path.exists(output_dir):
    i = 0
    while (os.path.exists(os.path.join(output_dir, “output” + str(i) + “.svg”))):
    i = i + 1
    f = open(os.path.join(output_dir, “output” + str(i) + “.svg”), “wt”)
    self.width, self.height = w, h
    self.file = f
    self.file.write(_SVGHEADER % (w, h))
    def shade(self, stroke):
    points = []
    for v in iter_stroke_vertices(stroke):
    x, y = v.getPoint2D()
    points.append(“%.3f,%.3f ” % (x, self.height – y))
    points = ”.join(points)
    attr = v.attribute()
    r, g, b = attr.getColorRGB() * 255
    color = “#%02x%02x%02x” % (r, g, b)
    width = attr.getThicknessRL()
    width = width[0] + width[1]
    self.file.write(_SVGPATH % (color, width, points))
    def close(self):

    Some minor changes in the above class:
    – autoincrements for files as in parameter mode multiple linesets can be used (one svg file is created for each
    – iter_stroke_vertices in foor-loop, I had some weird bugs…
    – maybe some more, not sure…

    Usage in the end of the file:
    SVGwriter = SVGWriter()
    # create strokes using the shaders list
    Operators.create(TrueUP1D(), shaders_list)

    Comment by Gustav Svensson — March 30, 2013 @ 11:14 AM

    • Noted that the _SVG definitions didn’t paste properly. A new try to add their content.



      Comment by Gustav Svensson — March 30, 2013 @ 11:17 AM

      • Third try:
        _SVGHEADER = “””\
        <?xml version=”1.0″ encoding=”utf-8”?>
        <!DOCTYPE svg PUBLIC “-//W3C//DTD SVG 1.0//EN”
        <svg xml:space=”default” width=”%d” height=”%d”><g>
        _SVGPATH = “””\
        <path fill=”none” stroke=”%s” stroke-width=”%d” d=”M %s” />
        _SVGFOOTER = “””\

        Comment by Gustav Svensson — March 30, 2013 @ 11:19 AM

      • I would love to use your modification, Gustav! Since wordpress appears to mess up your code, would you be willing to email the code and instructions? Or upload the file somewhere?

        Comment by Paul McCollam — January 30, 2014 @ 3:12 AM

  4. Hi TK,

    Not sure if you’re still checking this, but I wrote about Freestyle inclusion with Blender on a Polish website:

    Congrats of finally getting there!

    All the best,


    Comment by barts706 — July 16, 2013 @ 12:13 PM

  5. I’ve been requested to fix my code but unfortunately I don’t have easy acces to it but with some python skills shouldn’t it be to hard to fix the above code…

    Comment by Gustav Svensson — March 26, 2014 @ 7:45 PM

RSS feed for comments on this post. TrackBack URI

Leave a Reply

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

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

Google+ photo

You are commenting using your Google+ 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 )

Connecting to %s

Blog at

%d bloggers like this: