Wednesday, July 4, 2012

Driving Cycles Materials

It has come to my attention that in recent weeks that many of you out there have been trying to assign drivers to properties of Cycles materials, with a few bug reports appearing in the tracker in as many days. Yesterday, I took a short break from some of my other projects to try and find a fix for these problems, so now:


A live version of the image above can be found on BlendSwap (link will be added when available), and Pasteall. This blend is based on Bicycle (low Poly) by Brandon Farley, originally released under (CC-BY)

The following content has been adapted from the commit-log for these changes:

The Problem
As many of you (or at least those who frequently follow this blog) will know, we've had problems with Blender's "depsgraph" (or dependency graph) for ages now. In short: it is getting a bit long in the tooth as it is unable to cope with the wide range of dependencies which we can set up these days. For example, while we can (in theory) create relationships between many different types of datablocks, the depsgraph is only able to cope with those that exist between objects and their data. More specifically, "there's a link between OB1 and OB2" or "there's a link between OB3 and OBD3", and now "OB1 changed so OB2 needs changing too".

As it turn out, until now, there was never any code for making drivers on materials get recalculated when their dependencies were changed. However, since changing material colors with drivers is something that is quite common, a workaround was introduced to ensure that materials could still be driven (albeit with the relevant drivers rooted at object level). This worked well enough so far with traditional materials - though it was sometimes clunky and confusing for some users - and would have been ok to tide us over until the depsgraph refactor.

The introduction of Cycles changed this, much like it has with in many other ways. Now that artists use Cycles to render, they'll need to drive the material colors through the nested nodetree (and other things nested deeply within that). However, unlike in the past, it is much more difficult to generate hacks to create the relevant paths needed to work around the problem. But even then, the paths are also much more fragile and/or sensitive to changes in the node setups, while being practically impossible to edit by hand (as the identifier structures for nodetrees are actually quite complicated, with very little correspondence between the visuals and internal representation at times).

The Solution
Clearly the old solution of trying to hack around the problem by rerouting paths was no longer adequate. So, it was time to bite the bullet and actually try forcibly hacking in some semi-plausible support for updating material drivers within the constraints of the depsgraph system currently in place.

It turned out to be a two-part fix:
1) The first part adds a recursive driver calculation step to the BKE_object_handle_update() (which gets called whenever the depsgraph has finished tagging object datablocks for updates), which goes through calculating the drivers attached to the object (and the materials/nodetrees attached to that). This case gets handled everytime the object is tagged as needing updates to its "data" (OB_RECALC_DATA).

2) When building the depsgraph, every dependency that the drivers there have are treated as if they were attached to object.data instead. This should trick the depsgraph into tagging OB_RECALC_DATA to force recalculation of drivers, at the expense perhaps of modifiers getting recalculated again.

I've also removed the path rerouting hack put in place for materials since it's no longer needed. However, for now, the texture slots hack still remains (more work needed still on that).

There are some implications about these hacks that you'll need to be aware of:
  • Certain setups may end up getting slower than they are now, since now we need to check on every node and/or nested material within nodetrees attached to objects when their data (i.e. geometry) gets recalculated. This will be most noticeable on objects with complex geometry which may have previously not been animated but will now get updated, and for really complex node trees.
  • Unlike in a proper depsgraph, material drivers may not end up running before/after other object data drivers in the order that you'd like. There's no way around that though, and is not unlike any of the other limitations in place currently.
  • Be very careful about "re-entrant" setups (i.e. the material that hosts the nodetree is itself included in the nodetree). The initial implementation does not account for this yet.

2 comments:

  1. The dependency graph is DEFENITELY something one should consider redesigning.

    ReplyDelete
  2. Sorry, I forgot that you put much time into this.
    You did great work and it will help some artists with syncing animtion better, maybe even with music.

    ReplyDelete