Freestyle for Blender

Problems Coloring in Freestyle

Hi, I’ve been looking at Freestyle documentation in the WIKI and I still don’t know what I’m doing wrong to color my object in Freestyle. I’ve selected both “distance from camera” and "distance from object” but only the edges are being colored and not the object. Any help would be appreciated.


Hi Paint Guy,
AFAYK Freestyle only manages contour lines, hence it is normal that the modifications you make inside the “Line Style” tab are applied to the lines only. To change the color of the whole object you should tune the object material, as you would do normally in Blender.

As Robi says.
It can be beneficial to use the internal renderer or use cycles toon shader.

@@Paint_Guy

Your range min and max are too big to see the color change.
Also your visibility need to be set, else FS will include visible and hidden lines.
And as @robi said, color only for lines/strokes.

I’m writing a freestyle course, and a quote from it says

FreeStyle = LineArt

There is also color issue that was ironed out after the release of 2.69
http://lists.blender.org/pipermail/bf-blender-cvs/2013-November/060199.html
But I don’t think it was that, since you don’t play with the influence slider.

Thanks everyone. Robi. hi. didn’t realize that. Thanks. :slight_smile:

flokkievids,
The bug tracker reports from you have just been addressed. Many thanks for them.

The code quoted above seems okay to me. Note that (i) the Curvature2DAngleF0D function excludes 1D curves consisting of less than 3 vertices, and (ii) the vertex index starts from 0 and .isEnd() is true when the index is equal to the number of vertices.

The function description is intended to mean that it returns the angle between two edges AP and PB, where P is the vertex pointed by the given iterator, A is the previous vertex and B is the next vertex. I agree that the original description (by the initial Freestyle developers) is too technical, although it is considered technically more precise.

Removing code duplications in the areas you have identified was indeed a suggestion from code reviewers when the Freestyle branch was merged into the trunk. The work on this aspect was then left for future development due to the (still) limited time resources. I agree that it would be nicer to use Blender’s built-in functionalities where possible.

Using object names and groups is possible in the Freestyle Python API (see parameter_editor.py for code examples) and it is a matter of writing new predicates that test the conditions you want. If pyIsInOccludersListUP1D does not meet exactly your needs, then I would suggest defining a new predicate class using the API.

Yes, I watched the video of Ton’s keynote talk, and it was absolutely my pleasure to receive the applause by him and the audience (:

@TK

thanks for your detailed answers.

regarding Curvature2DAngleF0D.

thanks for your explanation. I see it should do what I thought it should but in practice it almost always returns 0.0, because the product of the normals is higher than 1.0 or smaller than -1.0. I would expect this functor to give an angle between 0 and 180 degrees, not 0.0.


Secondly, regarding those bug reports, it seems only a partial fix regarding only the it.object method.

the real problem for as far as i can see is that freestyle iterators can increment whilst they really shouldn’t, thus invalidating the object (the iterator itself) or at least every reference to it.object, also internal references by, in my case, it.is_incoming. since this property relies on the active object of the iterator, it.object will internally be referenced and using it.is_incoming in aforementioned cases still results in a crash.

In addition, if an iterator is at its end, which should mean its active element is the final vertex, the final vertex (instead of None) should be returned when it.object is called. one could get very strange errors if it.object returned None for no obvious reason.

Basically, the current fix causes all kinds of new problems and doesn’t really tackle the fundamental problem.

style module that still crashes (rev. 61240)
http://www.pasteall.org/47228/python

The Curvature2DAngleF0D functor gives you an angle in radians (instead of degrees). I don’t really see any problem in the Curvature2DAngleF0D implementation. The two normals for the dot product operation are normalized so that the result will be between -1 and 1. Although there are cases where the dot product is just a little bit out of this range due to numerical errors, such a case is also properly addressed in the present implementation.

I guess the reason why iterators’ .isEnd() method (.is_end property) can point one after the last element is to allow the following very frequent idiom:

if not it.is_end:
    do something
    it.increment()

This idiom seems quite straightforward to me. For the time being, there is a documentation bug in the description of the .is_end property (it is described that the property is true when the iterator points the last element, but this is not correct). I will fix it when the ongoing svn repository freeze is over.

I agree that returning None when .is_end is true was not a good idea. I would rather raise a RuntimeError to force API users to always check the .is_end property before .object() or .is_incoming is used. That is what the users are supposed to do. I was not aware of the reported crash with .is_incoming. I will fix it asap.

TK,

your proposed fix indeed seems the best for general cases (with the RuntimeError , that is), like


while not it.is_end:
    do something
    it.increment()

but it would give problems when using the next(it) method, also when used implicitly by for loops. therefore I would propose to let it.increment() be able to increment to len(it) + 1, but to limit next(it) to the exact number of items.


it = AdjacencyIterator(iter)
for ve in it:
   orientation = not it.is_incoming
   # do other stuff

the above idiom combines the strengths of using a for and a while loop. the it object is present but it.increment() doesn’t explicitly have to be called. you can also see here why the current implementation causes a crash.

flokkievids,
What is exactly wrong in the present implementation of next(it)? Do you experience crashes with explicit/implicit calls of the function?

TK,

I experience crashes with using a for loop (that implicitly calls next(it)) that iterates over and references the iterator inside of it. for instance:


winner = None
winnerOrientation = False
it = AdjacencyIterator(iter)


## case of TVertex
vert = self.next_vertex
if isinstance(vert, TVertex):
    mate = vert.get_mate(self.current_edge)
    for ve in it:
        if ve.id == mate.id:
            winner = ve
            winnerOrientation = not it.is_incoming
            break


It is kind of obvious as well. the for loop increments at the top and then continues (if StopIteration is not raised), the while loop increments at the bottom and then checks whether to continue. since StopIteration is raised on when
the active objects index is len(it) +1, the for-loops final iteration will have an undefined it.object.

Cartoon Crabs
Thanks TK for Freestyle

Attachments


patricia3d,
Nice crabs (:

flokkievids,
The discussed API changes have been just committed, to raise a RuntimeError instead of returning None.

I think the code for demonstrating a crash in it.is_incoming is an example of situations where the generic Python iterator protocol does not fit well with the Freestyle Python API. Basically you cannot reference an iterator object (‘it’) within a for loop when the iteration is done through the iteration protocol in the form “for vert in it: …” using implicit calls of next(it). The reason is simply because ‘it’ always points one after the object that the for loop is dealing with at each iteration step. A solution for this problem at the users side is a helper generator function to return a pair of it.object and it.is_incoming at each iteration.

def iter_adjacent_viewedges(it):
    while not it.is_end:
        yield (it.object, it.is_incoming)
        it.increment()

for ve, is_incoming in iter_adjacent_viewedges(it):
    if ve.id == mateVE.id:
        winner = ve
        winnerOrientation = not is_incoming
        break

For your information, another case of iterator API inconsistency is when UnaryFunction0D functors are used in loops. All UnaryFunction0D functors take as argument an Interface0DIterator object, which is usually instantiated as Interface0DIterator(it). Since ‘it’ must point the object being dealt with at a particular iteration step, the generic Python iterator protocol cannot be used in the form “for vert in it: …”. A solution in this case is again a helper generator. You can find many examples of it in parameter_editor.py.

Exactly for this reason I tend to feel like it was a mistake to have implemented the generic Python iterator protocol in the Freestyle Python API. In the beginning the iterator protocol appeared very nice and absolutely Pythonic. Then I realized the latter case of iterator API inconsistency. Maybe it is too late to remove the generic iterator protocol support from the API. Also it is true that there are many cases that the iterator protocol works just fine. So I would keep the API as it is now and warn users in the API documentation about this caveat. If you have some opinion in this regard, I would be more than willing to hear it.

TK

I see. It also clearly shows we need those helper functions, and that we really need to bundle and document them. the most straightforward solution would be creating a utils.py file (as discussed before) and import helper functions like


# preferably
from freestyle.utils.iterator import iter_adjacent_viewedges, ...

# or otherwise
from utils.iterator import iter_adjacent_viewedges

I am still very much a fan of keeping all freestyle-related code in one package (freestyle) instead of having a load of files that have to be imported separately, even though I see that the latter option is far easier to implement.

secondly, The ‘flaw’ in next(it) should , in my opinion, give an error, and never crash. errors can help improve your code, crashes are really frustrating.

flokkievids,

The crash with next(it) and it.is_incoming has been addressed in commit c592ebf5df4a. Now that we are in BCon1 for the upcoming 2.70 release, it is appropriate to do the module reorganization. I am thinking of the following structure.

freestyle - classes for internal data structures (e.g., viewmap components)
freestyle.iterators - iterators of all kinds
freestyle.predicates - unary and binary predicates for both 0D and 1D elements
freestyle.functions - functions for both 0D and 1D elements
freestyle.shaders - stroke shaders
freestyle.utils - helper generators

The reason why keeping predicates for 0D and 1D elements in one module is that all predicate classes have a suffix (e.g., U1D) indicating whether it is unary or binary and whether it works on 0D or 1D elements. There is no risk of name conflicts, so there is no much point to store *U0D, *U1D and *B1D in different modules. The same consideration applies to functions as well.

Comments on this restructuring plan are much appreciated.

TK

I agree on the structure idea. some comments:

  • you missed Nature and Noise. I would propose to keep freestyle.natures as a module and to get rid of freestyle.Noise in favour of mathutils.noise.
  • In your current proposal “dir(freestyle)” would still give quite a long list of objects. I would prefer to keep this list as small as possible. maybe adding freestyle.types for storing the core data structures would be an option?
  • what are your thoughts on integrating python- and c-defined objects (shaders, predicates, ect.)?

Continuing on my last comment, it would be very nice if style modules or rather modifiers could be registered like addons. I’m not quite sure whether this would be feasible (now), but in my opinion it would provide a real use for the freestyle API again: creating your own modifiers. using the restructured API they are quick to develop, yet flexible for the (non-programmer) artist.

Also, I would love to help with rewriting the shaders/functions/predicates in conform the new API.

finally, since this is becoming quite technical, we could continue this conversation on the new developer.blender.org freestyle project page.

The idea is to rename the present ‘freestyle’ module to _freestyle, and classify its contents (classes) into sub-modules by importing them from the submodules. Python classes also go into the submodules. In the end the new ‘freestyle’ module will have 28 classes for core data structures in addition to the proposed 5 sub-modules.

I like the idea of having ‘freestyle.types’ to keep the core data classes. Technically speaking, the Freestyle Python API is a set of Python classes (also referred to as types), so if we have ‘freestyle.types’, basically everything should go into there. Maybe module names such as ‘freestyle.types.iterators’ and ‘freestyle.types.predicates’ are a bit redundant.

If we store the core data classes in the ‘freestyle’ module, then we will have freestyle.Nature.SILHOUETTE and so on. I guess a separate ‘freestyle.natures’ module may also appear redundant.

What do you think about these aspects?

User-defined modifiers would be nice to have. I also plan to include in the 2.70 release an extended scripting support in the Parameter Editor mode. The idea is to allow users to write Python code segments in such a way that they can be integral part of style settings manipulated through the GUI.

I agree to move on to developer.blender.org Freestyle project to further discuss these and other future updates.

Hi T.K.
Just a small question, Is there any option in a single mesh that some faces should not be used with freestyle
Its just opposite of Edge Mark.
If you see my above image of my crabs, I don’t want Teeth to be used with freestyle. Whole body of my crabs excluding eyes, its a single mesh.

Use the freestyle-faces and have them set to ‘exclude’