I posted this on Blender Artists a couple of days ago and was encouraged by a few to repost it here. I have criticisms of the underlying philosophy of how Blender’s constraints are handled, but I’m not sure the best way to deliver those criticisms. If I’ve overstepped any bounds, I apologize. The following is a straight repost (with two new footnotes):
It seems to me that the basic philosophy and architecture of Blender’s constraints is flawed. This leads to counterintuitive behavior that confounds “beginners” (really, anybody without a relatively advanced understanding of 3D math) and creates unnecessary limits even on people who do have an understanding of this math. The problems that are created are often pernicious, easily missed until you inspect your interpolations carefully.
Let’s start by looking at how Blender currently handles constraints. I haven’t inspected the code-- this understanding is gained only by seeing what Blender does. I could easily be making some mistakes.
We start with f-curve values, modify/replace by drivers, then turn those into a 4x4 transformation matrix. When a constraint is evaluated, that transformation matrix is converted first into a different space as necessary (world vs bone local vs etc) and is then converted into Euler rotation, translation, and scale triplets. Blender then does some simple addition on these components (or recently, in the case of some scaling operations, multiplication) then converts the updated rotation/translation/scale triplets into a new matrix. Then we look at the next constraint and repeat.
There are two main problems with handling things in this fashion. The first is aliasing – the fact that for any particular orientation, there exist multiple Euler rotation triplets. This isn’t just considering values outside the -180,180 range, and it’s not limited by the angle evaluation order. What that means is that when we convert Euler rotations to matrices and then back to Euler rotations, we don’t get the same values that we put in. In many cases, the individual values of the Euler rotation components are not at all what we expect, even though the complete orientations, composed of the entire triplet, are exactly the same. (And, particularly, when we scale these individual components by some influence multiplier, and take into account funky Euler angle interpolation, we don’t get anything remotely like what we wanted or expected.)
The second problem is that Blender is just replacing the matrix. In some cases, many cases, that’s fine. Where it breaks down is when we have skew: an object or bone with local rotation that has inherited non-uniform scale. Skewed transformation matrices do not have distinct scale vs. rotation components. When we create new matrices out of decomposed scale + rotation, parts of the original transformation are inappropriately discarded.
How should Blender be doing this? It should never be decomposing matrices into components. Constraints should not create numbers that are added to components. Instead constraints should be creating transformations that are matrix multiplied into existing transformation matrices (1).
Rather than addressing this fundamental problem with how constraints are handled, Blender versions have tried to apply band-aid fixes to individual issues on a case-by-case basis. The naive initial approach is the reason scale needed to have a multiplicative version added, it’s the reason that copy rotation offset mode needed to be redone-- none of that would have been an issue if Blender were applying constraints as matrix multiplications (2). It’s responsible for continuing constraint issues, some of which would qualify as bugs, some of which would qualify as feature requests, and most of which would fall into the wide, vague area between the two.
It’s entirely possible I’ve made some mistakes in thinking about this. I’m far from an expert myself. Any kind of response is welcome. Honestly, when it comes to constraints, I’ve just been holding my breath until we get node-based rigging, figuring that given sufficient tools, I can fix these problems myself. At the same time, I keep seeing more work done on these constraints, but the fixes never seem to be made with an understanding of the underlying problem, and so I’ve been increasingly concerned that developers don’t recognize the real issue.
I could certainly go into detail on how these problems impact nearly any (bone) constraint, and offer suggested changes to turn these constraints into matrix transformation operations. I think that in many cases, it’s pretty obvious to anybody conversant enough with 3D math, and if I tried to describe all of the impacts and fixes, it might end up being a short book.
(1) You just don’t try to create orientations by adding up Euler angles. Euler angles are not 3 independent values. Component math does not give the kinds of orientations that people expect. Imagine trying to handle parenting relationships like this instead of via matrix multiplications!
(2) A really good example of a band-aid fix that I originally missed is the recent addition of new ways to measure angles in some constraints (like the “order” field in 2.83’s copy rotation constraint.)