14 April, 2011

Making Animatable Pivot: Part 2

In the first part, we looked at the basics of how pivot works and what is the main challenge in making pivot animatable. In this part we take a look at the implementation detail to build a system which will calculate movement around given pivot point. Here is the hierarchy I am using for this system.

   |_ pivot_loc
   |_ object_rot

Instead of step by step tutorial, I will try to describe main logic of how it works. First, let's examine our goal and see what kind of result we are looking for. Here is an image that shows the initial status and what we expect after rotating the cube. 

If we rotate the cube right now in our current initial state, then what we get is shown in the image below. It's what you would expect since our pivot is parented under the cube. But this is not what we want.

So how do we go from our initial state to the final result? There are different ways to solve this problem. Here, we look at one way to do it, which may not necessarily be the easiest.
First thing we need to keep in mind is that our pivot is parented under the cube, that means our pivot is operating under cube's coordinate space (V.IMP.). Now, let's see the steps to get the final result. 

#1) We move the pivot point so that it lies on the origin. (Keep in mind, this origin is in our cube's space)  
Why do we do this? So we can apply rotation matrix which always rotates around (0,0,0)

#2) Now, we apply the rotation, which will be around the origin by default. 
See it already looks closer to the result we want! 

#3) Then we reverse the first step. We move everything back so that pivot goes to it's original location.
And we have our final result!

The matrix equation to get the above result is:
shift = pivot_loc.inverseMatrix * object_rot.matrix * pivot_loc.matrix
(this can be a bit confusing if compared to original equation in first post, because we are taking a bit different approach here)

Now prepare the network to calculate the object movement around pivot using above matrix equation. Plug object's rotation into object_rot which will be our rotation matrix. Once you have the matrix calculation network ready, plug the final .matrixSum to a decomposeMatrix node's .inputMatrix attribute. What we will get here (in .outputTranslate) is the translation value that the object should move to get the pivoting movement around pivot_loc. Just to test the result you can plug .outputTranslate attribute of decomposeMatrix node to netPivotShift node and see how it works. Give it a try, it's fun! :)

Phew! That took the whole brain out of me! Now, remains the offsetting logic. Let's keep it for the next post to give my brain processor some rest :)

09 April, 2011

WIP: Unsuccessful attempt at rolling an egg(unknown type)

I can think of two ways to implement rolling egg.
1. Use aim constraint to point in the direction of movement and have rolling axis as your up vector. The object can then roll about this up vector. I will implement this approach later.
2. Calculate rolling rotation around the rolling axis using matrix calculations. 
!These approaches do not simulate the actual physics.!
I am currently working on 2nd approach. Here are some notes for both the approaches:

# First one will follow a path and will need some work to blend the direction changes so the object orientation does not jump.  
# First method is more like driving a car so the object's front/rear side follows the direction of movement, egg however may or may not follow this kind of movement. 
# Second method adds the rotation on top of the current rotation, so egg starts rolling in the direction of movement without any jump in it's orientation.
# First one will rely on expression only for small amount of work, hence reliable undo operations.
# Second method depends mainly on expression to avoid cycle and use of getAttr, setAttr is required. This leads to non-user friendly undo. 

The main difficulty in 2nd method is in getting the rotation around the rolling axis. I understand the theoretical part of it, but I am having a bit difficult time implementing it. May be I am doing something wrong, but it's hard to debug it at this stage. Here is what I am doing:

- Find the direction of movement
- Find rolling axis using cross product
- Find a matrix difference between so that z-axis of egg rotation matrix matches rolling axis (Diff)
- Do this operation to rotate egg around rolling axis by R
  F = Egg * Diff * R * Diff(-1)
- In above equation we first take the current egg rotation and then multiply it by "Diff" matrix to align z-axis with rolling axis. Then apply the rotation amount around z-axis and then just apply inverse of Diff matrix.

And here is the result.
You can see that in the beginning it rolls fine, but when direction changes rotation does not follow the rolling axis.

03 April, 2011

Making Animatable Pivot: Part 1

First concept here to understand is the rotation operation and how it is affected by pivot point. Here is a post I wrote on my blog last year to understand how pivot works.

First we will look at how rotation around pivot point is calculated in simple steps.
1. Translate the object from its current location to the pivot point location
2. Rotate the object
3. Translate the object back to its place from pivot point location

What the last step does is that it moves the object in the rotated transform axis. Hence it moves the object to the final location which gives the effect of rotation around given pivot point. Mathematically here is what we will do using matrices to get the final result:
F = T * R * T'
T = translation matrix to move from current position to the pivot position
R = rotation matrix
T' = inverse matrix of T

This was just the first step, in calculating the rotation around arbitrary point. However, the main challenge is to make pivot point animatabale.

If you have rotated the object first and then try to change the pivot location, the object will move as well. What happens here is that the object already had some rotation applied to it based on previous pivot position. Now, we change the pivot location which will cause the final matrix to be recalculated based on existing rotation and new pivot point. This results in object shifting to a new location. This seems quite obvious, but in many cases it is unwanted. Maya deals with this problem by storing an offset value in ".translateRotatePivot" attribute when you are moving the pivot point. This stops object from shifting.
But the problem with Maya's approach is that all the rotation calculations are always based on single pivot location. So even if object does not move while moving pivot point, it does affect all the previously keyframed transform values.

So to solve this problem we calculate the offset at each change of pivot location and then store this offset which can be animated on a pivot control. I will write about this in detail in my next post.