I noticed that I have been using the "Make Selected Curves Dynamic" option more and more in many of my projects. I found it very powerful and can easily give me expected results for a range of applications. I decided to use it in a practice for creating some kind of direction anticipation engine in a dynamic vehicle rig, utilizing the hair's dynamic playback advantages. I'm going to try to achieve as many features as I can without compromising processing time and ultimately stepping away from the use of any type of MEL expressions. The following is a list of features I am aiming to accomplish in this practice:
Direction Detector - Automatically orient a vehicle's rotation to the direction it is travelling in.
Height Collision System - Automatically detect a vehicle's collisions and adjusting itself to climb over harsh terrain.
Balance Stabilizer - Automatically adjusts a vehicle's balance in case one tire may be higher than the other.
Suspension System - Active suspension system that smoothens and balances the vehicle.
Wheel Rotation - Automatically rotates the vehicle's tires depending on the distance and speed travelled.
When making a 1 degree curve dynamic and adding a maximum motion drag of 1 to its attribute so that the base of the tip of the curve drives itself, I noticed that the tail travels behind its tip accurately enough to solve its direction. I created a two joint skeleton on the tip and tail of the curve and found that I can use the dynamic curve to replace an iK spline's curve. Now I can use the tail joint's orientation to adjust its direction with correct aim constraints.
Instead of reading a surface's UV's and interpreting it in world space I decided to utilize something that may seem a bit unorthodox. If you assign a Toon outline to two polygons that are intersecting, you can disable everything except for keeping its intersection outline. This outline can be converted in to a polygon. To find out where its travelling in the Y axis, since its world translation remains the same no matter how much it moves, I decided to create a hair on the outline's surface so that I can use it's follicle information along its UV surface. I can read the follicle's translate to determine where the intersection between the two objects occur.
When tackling this issue, I went straight for a joint system with various point and aim constrains. I should have thought more about the situation before doing this because after some few hours and a number of different rigs, I found this system limited when applied to a 4-independent wheel vehicle. The rotation of the body must adjust itself in 4 different pivots since all 4 wheels will be calculated differently. So I trashed this idea after working on it with much help from a very close friend of mine, and creator of the popular MooM rig, Ramtin Ahmadi. The solution that was finally used consisted of a planar polygon placed over the bottom of the rig with clusters on all 4 corners constrained to the wheels. A follicle is placed in the middle of the plane and the rotation of this follicle is translated in to the rotation of the vehicle's chassis.
I feel that this aspect of the rig wasn't realized as well as I wished to have accomplished. I simply used a proxy object with soft bodies and parent constrained things accordingly.
Since I need an extra dimension (z), then I will simply add that to the formula. Additionally, since it has been animated, I now know where point 1 and point 2 is by taking its current position and position it was last at 1 frame before.. Finally, to calculate the speed of my rig so that I can translate that in to the rotation of the wheel, I wrote this very simple dynamics expression.
float $distx = main_CTRL_Crv.translateX - $lastx;
float $disty = main_CTRL_Crv.translateY - $lasty;
float $distz = main_CTRL_Crv.translateZ - $lastz;
float $distance = sqrt( $distx*$distx + $disty*$disty + $distz*$distz );
float $velocity = $distance / ( time - $time );
$lastx = main_CTRL_Crv.translateX;
$lasty = main_CTRL_Crv.translateY;
$lastz = main_CTRL_Crv.translateZ;
$time = time;
main_CTRL_Crv.Speed = $velocity;