[Bf-taskforce25] PyConstraints V.2 - Proposal + Unresolved Issues

Joshua Leung aligorith at gmail.com
Tue Jul 28 04:20:03 CEST 2009


Hi Cessen.

On Mon, Jul 27, 2009 at 8:20 AM, Nathan Vegdahl <cessen at cessen.com> wrote:

> Dunno if this is the right time to bring this up, but I have been
> thinking of some other ways that pyconstraints could be improved as
> well:
>
> 1. The ability to specify what spaces (local, world, etc.) the
> constraint can operate in.  This would let the writer of the
> pyconstraint limit the constraint to the spaces where it makes sense,
> reducing user confusion.  For example, my foot-roll constraint only
> really makes sense in local space.
>
This should be easy to do... maybe just an extra getSpaces() callback (or
even just a defined prop) will do...


> 2. The ability to read the length of bones from inside the constraint.

With PyConstraints v1 you can already do something like this (it won't be
totally correct for the owner bone, since the length changes incurred by
previous constraints in the stack won't be included yet). In the doTarget()
function, you have access to the actual targets, from which you can extract
the relevant lengths and save them in some constraint properties (not
exposed to user via UI).


> 3. The ability to do the constraining on the local transforms
> themselves, rather than on a transform matrix.  For example: getting
> the actual quat components of bones as input, and being able to output
> directly to the quat components of the constrained bone.  This isn't
> important for translation or scale, but using transform matrices to
> pass and transform rotations is extremely lossy, and limits the
> rigging schemes that can be developed (I've had to abandon potentially
> useful schemes due to these limitations).
>
> I suspect that #3 would be huge pain to do?  Because it implies
> substantial changes in how Blender handles rotations in general.  And
> there are also a lot of complexities it would add, especially in terms
> of handling mixed rotation representations (quat vs euler vs etc.).
> But if it's possible, it would be extremely useful, and would unlock a
> lot of possibilities in rigging.
>
Hrm... I know that the old constraint system did this for 'local space', but
the way(s) that this was represented in the UI was quite confusing. Some
constraints would have to be executed at different times, 'breaking' the
stack metaphor of the constraints stack, as you could not really rely on
anything to be blended or to occur in the order you saw it in. At the time,
I chose to unify and rectify this situation so that constraints operated on
a single type of data only, and that they would always be evaluated in the
order presented, instead of some having to be accumulated (secretly) at
another point.

Having had time to think this over a bit more while the servers were down, I
think that perhaps we could incorporate a _third_ level of these sorts of
controls (on top of animation+drivers and constraints) that would sit
between drivers and constraints. Like drivers, these would get evaluated
directly on the bones instead of working on matrices, so that you could deal
with rotations directly as you say. Also, you would not be able to 'read'
the results of constraints and/or pose-space transforms resulting from
parenting, etc. However, unlike drivers, they can affect more than one
channel at a time, which I guess is one of the major reasons why drivers may
not be considered to be sufficient for this purpose.
Such a system would also be a good place for the orphaned 'strip modifiers'
from the old NLA-system to get moved to. Although those were implemented to
be stored on NLA-Strips, they were actually running on the level proposed
here. So we could say that introducing such a level would be the perfect
place to put these and also what you were interested in having.

Having said all that though, I'm a bit hesitant about introducing yet
another layer of controls like this for rigging stuff. A major concern is
that adding such a layer will just lead to more layers like this being added
in the future (i.e. full-body IK/ragdoll/<insert really fancy new tech
here>), overloading the rigger with heaps of sub-systems they have to learn
in order to create useful setups of the complexity described. But, the
existing systems (drivers - single value for a particular channel,
constraints - matrices on the 'final result') don't really fit the use-cases
you're mentioning, without their (currently 'clear') purpose becoming quite
'muddled' and 'hazy' like a cottonball that's picked up heaps of dried
leaves and gunk as it rolls around.


>
>
> On Sun, Jul 26, 2009 at 5:38 AM, Joshua Leung<aligorith at gmail.com> wrote:
> > Hi all,
> >
> > With the new style of coding py-extensions for Blender 2.5 coming in
> (with
> > the new PyAPI), it's about time that we had a look at refreshing the way
> > PyConstraints are coded.
> >
> > Firstly, an theoretical example of how a new PyConstraint could look
> like...
> >
> > class MyPyConstraint (bpy.types.pyconstraint):
> >     __name__ = "Dummy Test";
> >     __description__= "A silly constraint that makes use of and showcases
> > several features that would need to be used.";
> >     __num_targets__ = 1;
> >
> >     # evaluate the constraint for the given matrix and target matrices
> >     def doConstraint (self, eval_matrix, target_matrices):
> >          # get location parts
> >          loc= eval_matrix.translationPart();
> >          locT= target_matrices[0].translationPart();
> >          # and other parts of matrix
> >          obrot = obmatrix.toEuler()            # Rotation
> >          obsca = obmatrix.scalePart()        # Scale
> >
> >          # snap to grid, then add target location on top + a custom
> factor
> >          for i in xrange(3):
> >             loc[i]= floor(loc[i]+0.5) + locT[i] + self.factor;
> >
> >          # Convert back into a matrix for loc, scale, rotation
> >          mtxloc = Mathutils.TranslationMatrix(loc)
> >          mtxrot = obrot.toMatrix().resize4x4()
> >          mtxsca = Mathutils.Matrix([obsca[0],0,0,0], [0,obsca[1],0,0],
> > [0,0,obsca[2],0], [0,0,0,1])
> >
> >          # Recombine the separate elements into a transform matrix.
> >          outputmatrix = mtxsca * mtxrot * mtxloc;
> >          return outputmatrix;
> >
> >     # manipulate matrix of target before giving it to the doConstraint()
> > callback
> >     doTarget(self, target_object, subtarget_bone, target_matrix):
> >           return target_matrix;  # for this constraint, do nothing
> >
> >     # draw custom settings for constraint as part of constraints panel
> >     def drawSettings (self, layout):
> >           # add a single button for this custom factor
> >           layout.itemR(self, "factor");
> >
> >
> > -----------------------
> >
> > As can be seen, it takes into account several of the new PyAPI style
> issues:
> > - subclassing RNA-defined base types   (bpy.types.pyconstraint)
> > - layout engine is used to include the buttons defined in drawSettings()
> at
> > the end of panel for instances of the constraint
> > - name and num-targets can be defined in the way above, or by some other
> > means (details to be confirmed)
> > - custom properties can be directly accessed from the constraint instance
> > like regular properties (due to RNA)
> >
> > However, I think it is important to still maintain a few other
> > characteristics
> > - constraint instances still must reference text buffers/datablocks
> instead
> > of some magical global list that is maintained at startup... The main
> > benefit here is that in productions where multiple versions of the
> > constraints may be used, you don't need to register all the pyconstraints
> > for every machine that you work on, leading to problems with version
> > control...
> > - keeping the text buffers, we can also easily edit the scripts and test
> > without having to click on too many 'refresh' buttons
> >
> > The example above is incomplete in some ways though. Notably, there needs
> to
> > be some way of checking for (and initialising) missing but required
> custom
> > properties - probably a initSettings() call that checks if a setting
> exists
> > already (creating a new prop if non-existant) that gets called at certain
> > points? Getting this feature working is currently dependent on having
> > bpy/RNA methods available for doing this (TODO #1)
> > Also, the way of specifying the number of targets required indicated
> above
> > may not work that well in practice?
> >
> > Technical issues
> > - supposing that we compiled scripts containing such code, how would we
> go
> > about executing the constraints that are defined in this way? How are
> > changes such as number of targets going to cause changes?
> >
> >
> > Anybody have any comments on the proposed PyConstraints 2? (More
> > importantly, would be answers to the technical issues raised)
> >
> > Regards,
> > Joshua
> >
> > _______________________________________________
> > Bf-taskforce25 mailing list
> > Bf-taskforce25 at blender.org
> > http://lists.blender.org/mailman/listinfo/bf-taskforce25
> >
> >
> _______________________________________________
> Bf-taskforce25 mailing list
> Bf-taskforce25 at blender.org
> http://lists.blender.org/mailman/listinfo/bf-taskforce25
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.blender.org/pipermail/bf-taskforce25/attachments/20090728/a685e286/attachment.htm 


More information about the Bf-taskforce25 mailing list