0

EDIT: I think it need to further clarify what I'm trying to do:

I have a forearm rig setup in Maya using a wire deformer to control the twist. The wire deformer is on top of a skinCluster. The wrist joint has an extra angle attribute called "twist" which is linked to a parent joint that is at the same location as the wrist but maintains the orientation of the elbow joint. The twist attribute is also connected to the wire's dropoffLocatorTwist[1] attribute. With the dropoff at 100, the wire twists the forearm to infinity, and the joints still represent the "pose" of the wrist and hand. To compensate for over-rotations from the skinCluster, I added a duplicate wrist-hand hierarchy and connected the twist to its rotate x. Connecting the worldInverseMatrix of the duplicate hierarchy to the skinClusters bindPreMatrix attributes effectively negates any rotation of the wrist/hand joints around the axis of the elbow bone.

Now I want to push it further. To make it less of a hassle for animators, I want to remove the extra twist attribute and interpolate between all three euler rotate values of the joint itself to generate a twist value. Assuming the animator is setting values either directly in the channel box or simply relatively rotating the wrist, those values can easily go over 1000pi (in degrees). IF the poly mesh is dense enough, the wire deformer can easily perform a twist along a curve to that magnitude without any artifacts. The problem is how to interpolate the euler rotations to get a single angle value accurately representing both the pose and the twist. I've tried interpolating with the curves tangent and wrist matrix by multiplying each euler value by the dot product of the tangent to the euler rotations accompanying row vector in the matrix, but that doesn't work fully:

twist=rx*(tangent dot row1 of matrix)+ry*(tangent dot row2 of matrix)+rz*(tangent dot row3 of matrix)

Particularly, it doesn't like rotations around the Y axis. Can anyone tell me why that is and how to properly decompose an euler rotation to a twist angle without constraining the twist to -pi <-> pi?

PREVIOUSLY ASKED:

I'm using Maya wire (curve) deformers and want to find a twist value along the tangent of the wire based off the euler rotation of a joint. Joints in Maya are really transform matrices, but are composed in a fashion that a user can input the maximum float value possible as a degree value for any euler rotation component. I want to take those euler values (x y z), and combine them in such a way that the result is a axis-angle rotation where the axis is the first row of the parent matrix (or the tangent to the wire), and the angle is an unbound twist value around that axis, allowing for unlimited flip-less twisting of a mesh. The problem is I can't find a way to interpolate the x, y, and z values so that the resulting angle only represents the twist and nothing else. To put it more simply, I want to find the 'x' rotation value for a euler rotation where the x-axis has been rotated and thus is now represented by 'y', 'z', or something in-between all three components. Is there any way to do this without losing the value of x to a lesser but equivalent value (ex 270 == 90, but we want 270)?

user2715943
  • 1
  • 1
  • 2
  • The problem is not caused by joints, but clusters. Clusters just transform points as vector moves. Vectors are the same after 360 degrees of rotation. IF you have enough joints in between it still looks right. But if you want to rotate more than 180 degrees per joint then the clusters can not handle this. This can be solved with other methods tough – joojaa Aug 26 '13 at 16:28

2 Answers2

3

This is a non-trivial problem for a couple of reasons.

First, Eulerization of a matrix can produce lots of valid solutions that won't interpolate correctly (if you've ever had to use the blankety-blank Euler Filter in the Maya graph editor, you know what I mean). There are an many of euler combinations that will produce a given Quaternion or rotation matrix. This means it's hard to create a deterministic solution that covers all possibilities.

Second, the tangent along a spline is a vector, but you can't turn the vector into the matrix without at least one other vector to spice the solution. If you're familiar with maya's Spline IK and the complexities of finding a decent frame of reference for the twist control you'll see the same issues here.

Third, and most important for this purpose: twist can't be expressed as a rotation in 3d space -it's a relative rotation in the non-euclidean space of the original curve that doesn't correspond to a consistent world space matrix.

If you want to work with twists you need to construct a frame-of-reference transform for any point on the curve you want to sample, and you need to provide it some kind of extra information to get it started. Since twist is relative, you need to provide a starting point to measure twist from. You'll notice that all native maya tools for working along curves (motion paths, spline IK) do this.

Creating the matrix is pretty simple. get a normalized vector for the curve tangent, and another for the 'up vector'. The up vector is something you'll have to define by convention - that's why all the maya tools that work off of curve geometry tangents require you to pick or provide one. If your curve lies more or less on the XZ plane, you could use the world up vector. If it's more or less vertical, you could use X or Z. However you get it, you need that normalized up vector. Your 'side' vector, the local z axis of your eventual matrix, is the cross product of the tangent vector and the side vector. Now replace the original up vector with the cross vector of the tangent and side vectors (otherwise your matrix will be sheared). Finally, you need the world space position of the point on the curve where you got your tangent.

Now assemble your matrix like this:

tangent.x  tangent.y  tangent.z  0
up.x       up.y       up.z       0
side.x     side.y     side.z     0 
pos.x      pos.y      pos.z      1

That creates a matrix at the sample point, with local x pointing along the curve tangent and local y more or less pointing at the original up vector. In the context of that matrix the twist axis is the local X rotation. It's easier to control twist by creating two transforms: a parent that uses this matrix to provide a frame of reference and a child which is locked on Y and Z and only rotates on X. The euler numbers from the tangent-frame matrix will not be a twist value - twiat in this context is a completely relative concept that can't be expressed in a single matrix!

Honestly, for this kind of thing it may be easier to solve with built in tools. I'd experiment with using a motion path to constrain a reference transform ( a joint or a locator) to the curve: Animation>Motion Paths>Attach to Motion Path. That will do what you're asking by default your X axis will be the tangent of the curve and Y will be world up. You can just parent a second joint to the first (locally zero'ed out) and it's local X will be the twist axis, and you can just lock the other two axes and use that value.

Depending on the shape of your curve, you can run into two different sets of issues. If your up vector is too close to the direction of the curve the solution is unstable. You may be able to fix that by choosing a different 'up' vector - for a vertically oriented curve you could use world Z instead of world Y. However if the curve loops in all 3 dimension there's no mathematically complete solution.

A second strategy is to use extruded geometry to provide an 'up' vector. If you extrude a line segment along your original curve, forming a ribbon with the original curve as the V=0 isoparm, then at any point along the curve you can use the U isoparm as the up vector. That way you can see and if necessary correct the twist along the curve to avoid flips and wobbles - which are otherwise going to be quite common in this situation. You can grab vectors off the surface by using the pointOnSurface command. As long as history is on for your extrusion you can edit or animate the original curve and this solution still works.

Update

In response to OP's further information:

1) I would not worry too much about very large rotations. As jooja points out, this has no precise meaning in the real world that you need to model -- and as a practical matter, only very special purpose characters will ever need it. The biological limit for twist rotations at the wrist is less than +/- 90 and at the shoulder it's even less. A cartoon character could go past that - but probably only in the context of something like a twisting rubber band special effect, not a generic rig.

2) Euler twist is relatively tame, even for 3-axis joints, as long as it is the first euler term (ie, the X in an XYZ rotation). If your arm were laid out without any extra joint orients along the first axis you could measure the accumulated twist by just tracking the first euler rotations (ie, for XYZ bones the chain is a straight length of joints with zero rotations laid out along local X). In that configuration it's easy to add stub bones to counteract the twist rotation with simple expressions or node-based math. You can spread the twist rotation across several bones to keep things smooth (although with modern dual-quaternion skinning this is less of an issue, and two or three bones around the shoulder and the wrist is probably enough). Since the bones are stubs, they don't have to do complex 3d math to figure out twist: a bone in the bicep that's spreading the twist from the shoulder, for example, just rotates something like (-.5 * x) compared to the x rotation of shoulder. You skin to the stub bones, rather than the main line bones, so you get the YZ rotations of the main bone but the modulated X twist of the stubs.

The main drawback to this arrangement is that your bind pose can't also be your zeroed pose: you need the local axes along the chain to be continuous in the 'untwisted' state -- which means your 0,0,0 at the shoulder is a rigid T pose aligned with world X, not the more relaxed posture you get with most models. Animators tend not to like those kinds of zero poses (and of course, if you're matching an existing model you don't have a choice). However you can used dagPose to provide alternate zero poses which are actually zeroed' but do put the character back into a neutral posture.

theodox
  • 12,028
  • 3
  • 23
  • 36
  • Also let me add rotations outside one revolution do not really exist in reality. They only exist because some outside observer is counting. If i leave a basketball on the yard and return threes no way of telling how many times it has rotated around itself when nobody was observing. The only thing that can be observed is change in angle within one 0-360 slice. In essence twist is trying to force an abstract idea of a property on space that space does not inherently have. This is easy to do with a simulation, but pain to animate. A curve has no knowledge of any reference it can not be solved. – joojaa Aug 26 '13 at 16:10
  • There appears to be some confusion to what I'm trying to accomplish, so I updated my question. Please review my edits. – user2715943 Aug 27 '13 at 23:01
  • You're using the wire deformer to counteract pinwheeling because of the twist through the wrist? Is this a fairly conventional humanoid character, or something more exotic? – theodox Aug 28 '13 at 00:28
  • And... you only care about the twist through the wrist? – theodox Aug 28 '13 at 01:32
  • For now, it's just a arm model, so yes. I'm using the wire deformer instead of the skin cluster to handle twist (to completely bypass candy-wrapper/flipping artifacts), and a separate hierarchy to counteract the pinwheeling. I'm hoping this can also be applied to other regions like the shoulder or the entire torso, but I haven't tried that yet. – user2715943 Aug 28 '13 at 02:47
  • Is the skinning conventional linear or DQS? – theodox Aug 28 '13 at 05:56
  • @theodox Actually it seems he is using neither – joojaa Aug 28 '13 at 06:43
  • One last question - why are the twists going way past 360 degrees? – theodox Aug 28 '13 at 15:47
  • I'm creating rigs for my portfolio and for creativeCrash (ie for the public) and I want to account for every feature an animator could ask for before they ask. I don't want to not get a job because I couldn't produce a rig to the animator's specifications... – user2715943 Aug 28 '13 at 21:09
0

3D graphics is not reality. Reality is really nasty when it comes to mathematical modeling. In this particular case the simplification done is that the surface models Maya and nearly all 3D application use do not in fact rotate anything at the end. See the surface is either discretisized entirely (polygons, voxels) or a continuous surface is simplified as a bunch of discrete control points (Splines). The nice thing about this is that its easy to manipulate since everything is just vector moves, even rotations. That's right there's really no rotation going on in the entire process, while some nodes are aware of rotation the end result after all is said and node and it sent tor the renderer has no idea of what the nodes did.

This is mathematically hard to define

So what your asking is what is something like:

"What is the total sum of rotation projected against one axis?"

Instead of:

"how to properly decompose an euler rotation to a twist angle without constraining the twist to -pi <-> pi?"

The later is much more harder to understand and ill defined mathematically. The basic answer to the later question is you can not. The former form is better defined but is still like asking how far did I walk today, knowing that I started in my bed and ended the day in my bed. The reason is that you do not know how I moved in between. So the real answer is actually the integral over time, which depends on all frames before, in other words you need a simulation to solve this. You need to make some assumptions and corner constraints that help you solve the problem.

The most trivial would be that you force one axis to simply always point along your twist direction. Then make that axis the the last evaluated Euler (actually Maya does not use Euler angles it uses a Tait-Bryan angles) Now the twist can be trivially assumed to be the sum of those individual channels. For this to work tough your rotation order need to match your direction so if its along x then the rotation order needs to be one that's starts with the letter x eg xyz.

The above operates under the assumption that the other angles are actually not rotated many revolutions. Certainly for the animator it does not really matter if its entirely correct just as long as it works out. And truly rotating other axes arbitrarily even if you wouldn't calculate twist WILL cause weird interpolation issues.

If this isn't sufficient then it gets a bit tedious as i need to draw pictures. Basically the problem is that a Euler or Tait-Bryan angle is not a good model for interpolating things, just point directions. The interpolation wobbles around so straight is a really weird jumble. Some of these have really unintuitive corner cases.

Clusters can not solve this

Thus each point can not go more than 360 degrees to return to origin. Since the points are connected it seems like it pops back to beginning. It is true that's the matrix calculation used has ultimately a similar limitation, but it does not matter the points movement is the limiting factor if you look at the individual point. Now then if you have a chain of points such that no point "rotates" about no more than say 45 degrees (less is better, more points is smoother) then you have no problems. But still it does not work out. Why?

Bones move positions of points with weighted vector moves called clusters because moving each individual point is lot of work. The net effect is that each joint span can only rotate about < 180 degrees. This is cause d by the vector move. Again not the matrix although certainly if the vector move could do this the matrix would be a limiting factor. So clusters can not do this but there is a thing called dual quaternionion interpolation which can be used instead of normal clusters. What this does is it actually stores 2 squats and interpolates between them. This can solve an entire 360 degree slice both ways with some gimmickry. Still quite far away from infinite twist (assuming sufficient amount for points to twist), tough better certainly.

Dual quat interpolation can do this, so maybe you should use dual quat skinning instead.

joojaa
  • 4,354
  • 1
  • 27
  • 45
  • I've now provided some sample math. – user2715943 Aug 27 '13 at 23:01
  • @user2715943 Its not nearly as simple as that. It is in fact INSANELY hard hire a mathematician. – joojaa Aug 28 '13 at 07:37
  • I am using dual quat skinning, but for joints oriented along the x-axis, I want to negate all rotateX influences and replace them with wire twisting. I can't simply lock the channel-especially for the wrist, as animators I'm sure would complain, and that still leaves the problem of when the y or z axis becomes x and therefore should be affecting the wire twist attribute. – user2715943 Aug 28 '13 at 21:18
  • @user2715943 Yes but mathematically this is not easy since weird things happen the other channels might counter rotate your twist half of the time and rotate along the other half. This is why you dont see rigs like this. Euler never claimed his method would represent anything useful just that you can orient things perfectly with this scheme. Not interpolate anything. But cant you just sum the axes, its not perfect? Animators would gauge your rig by eye. Anyway the creative crash forums might be a better place to discuss this since it has no answer. – joojaa Aug 29 '13 at 06:52