Static Public Member Functions

MHairSystem Class Reference

This reference page is linked to from the following overview topics: Overview of example plug-ins.


Search for all occurrences

Detailed Description

Interface with Maya's Dynamic Hair System.

MHairSystem provides an interface with Maya's Dynamic Hair System.

At present, this interface only supports the ability to override the geometry collision component of hair. There is currently no support for overriding the other hair collision components (i.e. implicit object collision and hair self collision).

The rationale for providing a hair collision API is to allow the user to override Maya's internal algorithm which is a high-performance simulation. There is an example plug-in provided in the Developer's Toolkit called hairCollisionSolver.cpp.

#include <MHairSystem.h>

List of all members.

Static Public Member Functions

static MStatus registerCollisionSolverCollide (MHairSystemCollisionSolverCollideFnPtr)
 Register the user-supplied collision solver `fnPtr' with Maya.
static MStatus registerCollisionSolverPreFrame (MHairSystemCollisionSolverPreFrameFnPtr)
 Register the user-supplied pre-frame method `fnPtr' with Maya.
static MStatus unregisterCollisionSolverCollide ()
 De-register any user-defined collision solver that might have been registered via registerCollisionSolverCollide().
static MStatus unregisterCollisionSolverPreFrame ()
 De-register any user-defined pre-frame callback that might have been registered via MHairSystem::registerCollisionSolverPreFrame.
static MObject getCollisionObject (const MObject hairSystem, const int index, MStatus *status)
 Returns the requested collision object from the hair system.
static MStatus getCollisionObject (const MObject hairSystem, MObjectArray &objects, MIntArray &logicalIndices)
 Returns all collision objects for the hair system.
static MObject getFollicle (const MObject hairSystem, const int index, MStatus *status)
 Returns the requested follicle from the hair system.
static MStatus getFollicle (const MObject hairSystem, MObjectArray &follicles, MIntArray &logicalIndices)
 Returns all follicles for the hair system.
static void setRegisteringCallableScript ()
 Mark this MHairSystem object as one that will be passed callbacks defined in script.
static bool registeringCallableScript ()
 Return true if this MHairSystem object has its callbacks defined in script.
static const char * className ()
 Returns the name of this class.

Member Function Documentation

MStatus registerCollisionSolverCollide ( MHairSystemCollisionSolverCollideFnPtr  fnPtr) [static]

Register the user-supplied collision solver `fnPtr' with Maya.

This method will be invoked per-hair times the number of iterations specified by the hairSystem node and the method can be used to perfrom several functions:

  1. Implement a user-defined collision detection on all collision objects associated with the hairSystem node.
  2. Adjust the hair position to react to any detected collision.
  3. Perform global hair processing functions, such as freeze, smoothing, etc. These functions can be performed independently of whether or not a collision occurred.

The effect of registering a collision solver is to override Maya's internal solver, thus ALL hair to object collision detection will now route into your callback. To revert to Maya's internal solver, de-register the solver using unregisterCollisionSolverCollide(). Also note that exatly one collision solver can be registered. If a second solver is registered, it overrides the previous definition.

The hair that gets passed into your collision solver is defined by three parameters: the desired position where Maya's hair system wants the hair to be at the current time, the previous position (where the hair was at the last frame), and the width of the hair. These three parameters are represented as arrays. The first element in each array corresponds to the root of the hair, and the remaining elements are the points along the hair with the tip as the last element. Maya has the ability for the user to lock the root and or tip so that they cannot be moved. This locking is specified by the `startIndex' and `endIndex' parameters. A pair of hair points forms what is termed a "hair segment", and each segment is thus a moving cylinder in which each end can have a different width.

The goal of your collision solver is to detect any collisions between the hair as it moves linearly from previous towards its desired position and any collision objects. As the hair is moving and the collision objects are moving, the collision calculation is a complex time-based equation. If you take into consideration that the hair has variable width, things are even more complicated.

Since you have full access to computing and reacting to the collision, you can make assumptions (such has collision objects can't move) then you can get speed improvements over Maya's built-in solver. You can also go the other way: implementing very accurate continuous-time collision detection.

Parameters:
[in]fnPtrPointer to a function which implements the user's collision solver algorithm.

The MHairSystemCollisionSolverCollideFnPtr type is defined as follows.

  • const MObject hairSystem The hair system shape node.
  • const int follicleIndex The follicle we are processing. The value can be passed into getFollicle() to obtain the follicle node.
  • MVectorArray &hairPositions An array of desired positons where the hair system would like the hair to be for the current frame. The entries are ordered such that the first entry corresponds to the root of the hair and the last entry to the tip. If you detect a collision between the hair and a collision object, update the hairPositions values appropriately.
  • MVectorArray &hairPositionsLast An array of positions at the previous time. Use hairPositions[i] minus hairPositionsLast[i] to determine the velocity to use. If a desire to change the velocity is needed, alter positionsLast to place the hair to enact the new desired velocity. Note that the hair solver likes damped collisions: attempting to simulate rebound effects may not work effectively.
  • const MDoubleArray &hairWidths The width along the hair. The entries correspond one-to-one with the entries in the hairPositions and hairPositionsLast array. In effect, each hair segment is a cylinder with a potentially different width at each end.
  • const int startIndex The first element in the hair arrays we are allowed to alter. This will be 0 unless the root is locked.
  • const int endIndex The last element in the hair arrays we are allowed to alter. This will be hairPositions.length()-1 unless the tip is locked.
  • const double curTime The current time in seconds.
  • const void *privateData If you set up a pre-frame callback via MHairSystem::registerCollisionSolverPreFrame then this is the private data you would have returned from your callback. Passing back private data is optional: the only advantage is to save the user the cost of retrieving the private data through other methods.
Returns:
  • MS::kSuccess Successfully registered the callback.
  • MS::kFailure A callback was already registered. Use MHairSystem::unregisterCollisionCollide() first to de-register the current callback before registering a new one.
Examples:
hairCollisionSolver.cpp.
MStatus registerCollisionSolverPreFrame ( MHairSystemCollisionSolverPreFrameFnPtr  fnPtr) [static]

Register the user-supplied pre-frame method `fnPtr' with Maya.

This method will be invoked at the start of each frame.

Note that this method is optional. You only need to define this method if you want to perform pre-frame initialisation. One strategy is to perform expensive pre-preprocessing once per frame so that it can be utilised during your collide() callback. If there is more than one collision geometry associated with the hair system, be sure to store the pre-processed data so that it can be referenced in the order the objects are returned via the getCollisionObject() call.

Note: if you decide to define private data, you will need to manage it somehow. You will need to be able to find the data again to reuse at the next frame and delete it when the collision object is removed from the hairSystem's collision list. The best way to do this is to implement a listener method which watches for changes to the hair system's collision object list attribute and clean up your private data as appropriate.

Parameters:
[in]fnPtrPointer to a function which implements the user's pre-frame algorithm.

The MHairSystemCollisionSolverPreFrameFnPtr type is defined as follows.

  • const MObject hairSystem The hair system shape node.
  • const double curTime The current time in seconds.
  • void **privateData Allows the user to return a private data pointer to be passed directly into their collision solver callback. The intent is to provide an efficient way to pass your private data into the collision solver (for example, if you store your private data on a typed attribute on the hairSystem node, using the privateData pointer allows you to avoid looking up the plug value in your high-traffic collision solver).
Returns:
Examples:
hairCollisionSolver.cpp.
MObject getCollisionObject ( const MObject  hairSystem,
const int  index,
MStatus ReturnStatus 
) [static]

Returns the requested collision object from the hair system.

Parameters:
[in]hairSystemThe hair system.
[in]indexWhich collision object to retrieve. The objectIndex parameter passed into your pre-frame callback or collision solver callback can be specified here.
[out]ReturnStatusStatus code.

Status codes

Returns:
The requested collision object, or the NULL object if not found.
Examples:
hairCollisionSolver.cpp.
MStatus getCollisionObject ( const MObject  hairSystem,
MObjectArray objects,
MIntArray logicalIndices 
) [static]

Returns all collision objects for the hair system.

Parameters:
[in]hairSystemThe hair system.
[out]objectsReturns the collision objects in the same order that index-based getCollisionObject() returns them.
[out]logicalIndicesLogical indices of each collision object returned.
Returns:
MObject getFollicle ( const MObject  hairSystem,
const int  index,
MStatus ReturnStatus 
) [static]

Returns the requested follicle from the hair system.

Parameters:
[in]hairSystemThe hair system.
[in]indexWhich follicle to retrieve. The follicleIndex parameter passed into your collision solver callback can be specified here.
[out]ReturnStatusStatus code.

Status codes

Returns:
The requested follicle, or the NULL object if not found.
MStatus getFollicle ( const MObject  hairSystem,
MObjectArray follicles,
MIntArray logicalIndices 
) [static]

Returns all follicles for the hair system.

Parameters:
[in]hairSystemThe hair system.
[out]folliclesReturns the array of follicles in the same order that the index-based getFollicle() returns them.
[out]logicalIndicesLogical indices of each follicle returned.
Returns:
const char * className ( ) [static]

Returns the name of this class.

Returns:
The name of this class.

MHairSystem MHairSystem MHairSystem MHairSystem MHairSystem MHairSystem MHairSystem MHairSystem MHairSystem MHairSystem
MHairSystem MHairSystem MHairSystem MHairSystem MHairSystem MHairSystem MHairSystem MHairSystem MHairSystem MHairSystem