deform (lx_deform.hpp)

From The Foundry MODO SDK wiki
Jump to: navigation, search
There are security restrictions on this page


Contents

Deformation Interfaces

Deformer items link to the targets and overrides with the deformers graph. They can be grouped and organized with the deform-tree graph.

Falloff

A falloff is a scalar field, filling space with a weight value typically between zero and one.

(1) SDK: ILxFalloff interface
         LXxMETHOD( LxResult,
 Bounds) (
         LXtObjectID              self,
         LXtBBox                 *box);
 
         LXxMETHOD( float,
 WeightF) (
         LXtObjectID              self,
         const LXtFVector         position);
 
         LXxMETHOD( LxResult,
 WeightRun) (
         LXtObjectID              self,
         const float            **pos,
         float                   *weight,
         unsigned                 num);

(2) SDK: Declarations
 #define LXu_FALLOFF             "B7D1DEF8-1F45-4924-B518-E2F2A76D0259"

(3) User Class: Falloff method

Empty Falloff Python user class.

(4) PY: Falloff method
 pass

Falloff items all derive from a common type, a type of locator. Being a locator type allows all falloffs to act as influences and to perform direct deformations, even if a specific falloff type has no location. It also allows the falloff to present a Tool interface, so it can be evaluated as a falloff in a procedural modeling context.

(5) SDK: Declarations
 #define LXsITYPE_FALLOFF                "falloff"
 
 #define LXsICHAN_FALLOFF_FALLOFF        "falloffObj"
 #define LXsICHAN_FALLOFF_DEFORMER       "deformerObj"
 #define LXsICHAN_FALLOFF_FALLENAB       "enableFalloff"
 #define LXsICHAN_FALLOFF_DEFORMENAB     "enableDeform"
 #define LXsICHAN_FALLOFF_STRENGTH       "strength"
 #define LXsICHAN_FALLOFF_INVERT         "invert"
 #define LXsICHAN_FALLOFF_TOOL           "toolObj"

Bare Deformation

A deformation is basically a warping of space. Given an input point location and a weight value typically from 0 to 1, the deformation computes the offset of the point. The offset must approach zero as the weight approaches zero.

Flag bits indicate if a deformation is non-linear and/or rigid. Non-linear means that offsets don't lie on a simple line for different weight values but instead trace curves. Rigid means that the transform at weight 1 can be described by a 4x4 matrix.

(6) SDK: ILxDeformation interface
         LXxMETHOD( unsigned,
 Flags) (
         LXtObjectID              self);

(7) SDK: Declarations

For rigid deformations, this method returns the matrix for unity weight.

(8) SDK: ILxDeformation interface
         LXxMETHOD( LxResult,
 Transform) (
         LXtObjectID              self,
         LXtMatrix4               xfrm);

These three methods compute the offset from a starting position at a given weight value. OffsetF() takes a single point and a weight; OffsetRun() takes vector arrays for faster computation, and the weight array pointer can be null to indicate unity.

(9) SDK: ILxDeformation interface
         LXxMETHOD( void,
 OffsetF) (
         LXtObjectID              self,
         const LXtFVector         position,
         float                    weight,
         LXtFVector               offset);
 
         LXxMETHOD( void,
 OBSOLETE) (
         LXtObjectID              self);
 
         LXxMETHOD( LxResult,
 OffsetRun) (
         LXtObjectID              self,
         const float            **pos,
         const float             *weight,
         float                  **offset,
         unsigned                 num);

(10) SDK: Declarations
 #define LXu_DEFORMATION         "F5705327-7382-47C5-8D7B-AF2CC18B3E8A"

(11) User Class: Deformation method

Empty Deformation Python user class.

(12) PY: Deformation method
 pass

Deformation items indicate their deformation object channel through a server tag on their package.

(13) SDK: Declarations
 #define LXsPKG_DEFORMATION_CHANNEL      "deformation.channel"

Influence

Influences define weighted deformations over specific domains. Each influence does two things -- it provides all the information necessary to perform the deformation, and it allows deformations to be composed. Thus it may completely control the deformation of the target domain, or it may be under the control of another influence driving its weights.

Item types provide a mesh influence through an object reference channel, the name given by a server tag. An optional tag can also define default mesh influence flags.

(14) SDK: Declarations
 #define LXsPKG_DEFORMER_CHANNEL         "deformer.channel"
 #define LXsPKG_DEFORMER_FLAGS           "deformer.flags"
 #define LXsPKG_DEFORMER_CREATECMD       "deformer.create"

If defined, the flags string is a "+" character followed by a set of single letters.

NO_WEIGHT
Given by 'W', this indicates that the mesh influence has no weights. All the points are equally weighted at 100%.
NO_OFFSET
Given by 'O', this indicates that the influence does not define it's own offsets. Instead offsets need to be provided by a deformation.
IS_FALLOFF
This is an internal flag which indicates that the mesh influence is derived from a falloff plus locator deformation.
IS_MESHOP
This is an internal flag which indicates that the mesh operation is performing a procedural modeling operation.

(15) SDK: Declarations

Deform Influence

A deform influence describes a collection of elements and how they might move. The flags indicate if the deformation has internal weights, offsets and/or a per-element transform.

(16) SDK: Types
 typedef void *           LXtDeformElt;

Flags are the same flags assigned to the deformer item type, plus a runtime flag to indicate if linear interpolation should be used.

(17) SDK: ILxDeformer interface
         LXxMETHOD( unsigned,
 Flags) (
         LXtObjectID              self);

(18) SDK: Declarations
 #define LXfDEFORMER_USE_LINEAR  0x100

All the elements affected by this deformer exist in partitions. This method enumerates the elements in a specific partition.

(19) SDK: ILxDeformer interface
         LXxMETHOD( unsigned,
 PartitionCount) (
         LXtObjectID              self);
 
         LXxMETHOD( LxResult,
 EnumeratePartition) (
         LXtObjectID              self,
         LXtObjectID              visitor,
         unsigned                 part);

The element pointer can be read out during enumeration. For a mesh partition the element must be a LXtPointID, and for and item partition the element must be an ILxUnknownID for the item. For deformers that support items, the items are all assumed to be in partition zero.

Elements in a partition can be further segmented by numeric ID which is also returned from this method. All the elements in a run will come from the same segment.

(20) SDK: ILxDeformer interface
         LXxMETHOD( LXtDeformElt,
 Element) (
         LXtObjectID              self,
         unsigned                *segment);

As an alternative to enumerating elements, the client can set a specific element ID and partition before quering for attributes.

(21) SDK: ILxDeformer interface
         LXxMETHOD( LxResult,
 SetPartition) (
         LXtObjectID              self,
         unsigned                 part);

The query methods get data about specific elements given their element ID. Weight() gets the degree of influence on the element, and Offset() gets the weighted offset for the deformation. Both of these get an input position that may be the real input position or may be a hypothetical.

(22) SDK: ILxDeformer interface
         LXxMETHOD( float,
 Weight) (
         LXtObjectID              self,
         LXtDeformElt             elt,
         const LXtFVector         pos);
 
         LXxMETHOD( void,
 Offset) (
         LXtObjectID              self,
         LXtDeformElt             elt,
         float                    weight,
         const LXtFVector         pos,
         LXtFVector               offset);

The "Run" versions of the interfaces operate on arrays of elements, positions and weights. OffsetRun() can be called with a null 'weight' pointer to get offsets with all unity weight.

(23) SDK: ILxDeformer interface
         LXxMETHOD( LxResult,
 WeightRun) (
         LXtObjectID              self,
         unsigned                 segment,
         const LXtDeformElt      *elt,
         const float            **pos,
         float                   *weight,
         unsigned                 num);
 
         LXxMETHOD( LxResult,
 OffsetRun) (
         LXtObjectID              self,
         unsigned                 segment,
         const LXtDeformElt      *elt,
         const float            **pos,
         const float             *weight,
         float                  **offset,
         unsigned                 num);

(24) SDK: Declarations
 #define LXu_DEFORMER            "F029A563-A937-4DB2-992E-1592081F64CC"

The user class offers enumeration methods using C++ visitors.

(25) User Class: Deformer method
         LxResult
 EnumPartition (
         unsigned                 index,
         CLxImpl_AbstractVisitor *visitor)
 {
         CLxInst_OneVisitor<CLxGenericVisitor>  gv;
 
         gv.loc.vis = visitor;
         return EnumeratePartition (gv, index);
 }

Empty Deformer Python user class.

(26) PY: Deformer method
 pass

The modifier's Evaluate() method can return codes indicating the type of changes that happened. IDENTICAL means no change at all and previous cached results will be reused. NEWOFFSET means that offsets changed, but the set of affected element and the weights are the same. NEWWEIGHT means that the set of element is the same but the weights have changed. DIFFERENT (same as the default 'OK') means that the set of elements may have changed.

(27) SDK: Declarations

Mesh Influence

A mesh influence is a specific sub-type of deform influence that operates on points in meshes. The partition of the mesh influence is different meshes.

The mesh influence interface can be found in two contexts. The first is by reading the influence channel of an item that affects meshes. In that case it will be polymorphic with the deform influence interface, and each mesh in the list is a partition in the deform.

The mesh influence interface may also be found on items. If it is then that item affects direct control over a set of meshes. An item without a mesh influence interface that nonetheless generates a mesh influence object on its influence channel is an "any mesh" influence. It will be automatically wrapped as a deform influence acting on linked meshes.

Meshes are given by a count and indices. MeshByIndex() actually gets the mesh item affected.

(28) SDK: ILxMeshInfluence interface
         LXxMETHOD( unsigned,
 MeshCount) (
         LXtObjectID              self);
 
         LXxMETHOD( LxResult,
 MeshByIndex) (
         LXtObjectID              self,
         unsigned                 index,
         void                   **ppvObj);

(29) User Class: MeshInfluence method
         bool
 GetMesh (
         unsigned                 index,
         CLxLoc_Item             &item)
 {
         LXtObjectID              obj;
 
         if (LXx_FAIL (MeshByIndex (index, &obj)))
                 return false;
 
         return item.take (obj);
 }

This returns the partition index for the given mesh index, since they may not match exactly.

(30) SDK: ILxMeshInfluence interface
         LXxMETHOD( unsigned,
 PartitionIndex) (
         LXtObjectID              self,
         unsigned                 index);

Before reading out values, the client sets the actual mesh and transform based on the index of the mesh item. Once set these don't change unless the mesh or transform are changed.

(31) SDK: ILxMeshInfluence interface
         LXxMETHOD( LxResult,
 SetMesh) (
         LXtObjectID              self,
         unsigned                 index,
         LXtObjectID              mesh,
         LXtObjectID              item);
 
         LXxMETHOD( LxResult,
 SetTransform) (
         LXtObjectID              self,
         unsigned                 index,
         LXtMatrix4               xfrm);
 
         LXxMETHOD( LxResult,
 MeshChange) (
         LXtObjectID              self,
         unsigned                 index,
         LxResult                 change);

(32) SDK: Declarations
 #define LXu_MESHINFLUENCE       "D70AA410-75BB-480E-90E2-17E2059EB40B"

Empty MeshInfluence Python user class.

(33) PY: MeshInfluence method
 pass

Item Influence

Analogous to MeshInfluence, except that there's no concept of a partition. It's just a list of items. The list is accessed with a visitor.

(34) SDK: ILxItemInfluence interface
         LXxMETHOD( LxResult,
 HasItems) (
         LXtObjectID              self);
 
         LXxMETHOD( LxResult,
 Enumerate) (
         LXtObjectID              self,
         LXtObjectID              visitor);
 
         LXxMETHOD( LxResult,
 GetItem) (
         LXtObjectID              self,
         void                   **ppvObj);
 
         LXxMETHOD( LxResult,
 AllowTransform) (
         LXtObjectID              self,
         unsigned                 index,
         unsigned                *flags);

(35) SDK: Declarations
 #define LXu_ITEMINFLUENCE       "2141BD0B-DEFC-4A92-A4A5-30760C09F18B" 
 #define LXfITEMINF_POSITION      0x01
 #define LXfITEMINF_ROTATION      0x02
 #define LXfITEMINF_SCALE         0x04
 #define LXfITEMINF_PROBEWEIGHTS  0x08

(36) User Class: ItemInfluence method
         LxResult
 Enum (
         CLxImpl_AbstractVisitor *visitor)
 {
         CLxInst_OneVisitor<CLxGenericVisitor>  gv;
 
         gv.loc.vis = visitor;
         return Enumerate (gv);
 }
 
         bool
 CurItem (
         CLxLoc_Item             &item)
 {
         LXtObjectID              obj;
 
         return LXx_OK (GetItem (&obj)) && item.take (obj);
 }

Empty ItemInfluence Python user class.

(37) PY: ItemInfluence method
 pass

Deformer Groups

Deformer group items can be parents to other deformers in the deformTree hierarchy. A deform group is itself a deformer that performs a composite deformation of the child deformers.

(38) SDK: Declarations

The ILxGroupDeformer interface allows clients to read out the blended weights affecting each point in the group. The DeformerCount / ByIndex() methods allow the client to see the members of the group. PointEffect() takes a point in one of the target meshes and returns lists of member deformer indicies and their weights. If the provided buffers are too small this returns LXe_SHORTBUFFER.

(39) SDK: ILxGroupDeformer interface
         LXxMETHOD( unsigned,
 DeformerCount) (
         LXtObjectID              self);
 
         LXxMETHOD( LxResult,
 DeformerByIndex) (
         LXtObjectID              self,
         unsigned                 index,
         void                   **ppvObj);
 
         LXxMETHOD( LxResult,
 PointEffect) (
         LXtObjectID              self,
         unsigned                 meshIndex,
         LXtPointID               point,
         unsigned                *deformer,
         float                   *weight,
         unsigned                *count,
         unsigned                 max);

(40) SDK: Declarations
 #define LXu_GROUPDEFORMER       "4BC04F3F-29FC-4EA3-B090-10280331C757"

(41) User Class: GroupDeformer method
         bool
 GetDeformer (
         unsigned                 index,
         CLxLoc_Item             &item)
 {
         LXtObjectID              obj;
 
         if (LXx_FAIL (DeformerByIndex (index, &obj)))
                 return false;
 
         return item.take (obj);
 }

The user class allows the effect at each point to be read safely into a vector of composite elements.

(42) User Class: GroupDeformer method
 class CDeformerWeight {
     public:
         unsigned                 deformer;
         float                    weight;
 };
 
 typedef std::vector<CDeformerWeight>    DeformerWeightArray;
 
         LxResult
 PointEffectList (
         unsigned                 meshIndex,
         LXtPointID               point,
         DeformerWeightArray     &list)
 {
         LxResult                 rc;
         unsigned                *ibuf;
         float                   *fbuf;
         unsigned                 i, n;
         size_t                   len;
 
         list.clear ();
 
         len = 16;
         while (1) {
                 ibuf = new unsigned [len];
                 fbuf = new float    [len];
 
                 rc = PointEffect (meshIndex, point, ibuf, fbuf, &n, static_cast<unsigned>(len));
                 if (rc != LXe_SHORTBUFFER)
                         break;
 
                 delete[] ibuf;
                 delete[] fbuf;
                 len *= 2;
         }
 
         if (LXx_OK (rc))
                 for (i = 0; i < n; i++) {
                         CDeformerWeight  dw;
 
                         dw.deformer = ibuf[i];
                         dw.weight   = fbuf[i];
                         list.push_back (dw);
                 }
 
         delete[] ibuf;
         delete[] fbuf;
         return rc;
 }

Empty GroupDeformer Python user class.

(43) PY: GroupDeformer method
 pass

A deformer folder is just a grouping construct. Deformers that are children of a folder are still applied bottom to top at the location of the folder. The enable state of the folder can disable all children as well.

(44) SDK: Declarations
 #define LXsITYPE_DEFORMFOLDER           "deformFolder"
 
 #define LXsICHAN_DEFORMFOLDER_ENABLE    "enable"

Weight Map Deformers

A subset of deformer items get their weights from weight maps. This interface allows the weight map for the deformer to be displayed and edited in the 3D view.

(45) SDK: ILxWeightMapDeformerItem interface
         LXxMETHOD( LxResult,
 GetMapName) (
         LXtObjectID              self,
         LXtObjectID              chanRead,
         char                    *buf,
         unsigned                 len);
 
         LXxMETHOD( LxResult,
 GetColor) (
         LXtObjectID              self,
         LXtObjectID              chanRead,
         LXtVector                col);

(46) SDK: Declarations
 #define LXu_WEIGHTMAPDEFORMERITEM       "A9C81E0B-20F0-4D8B-838B-B593EAF3DFB8" 
 #define LXeDEFORM_AUTO_COLOR    LXxGOODCODE(LXeSYS_DEFORM, 12)

(47) User Class: WeightMapDeformerItem method

Empty WeightMapDeformerItem Python user class.

(48) PY: WeightMapDeformerItem method
 pass

Standard Deformers

The itemInfluence item type (really Item Deformer) serves as the container influence object for deforming items.

(49) SDK: Declarations

Deformer Service

(50) SDK: Declarations
 #define LXa_DEFORMERSERVICE     "deformerservice"
 #define LXu_DEFORMERSERVICE     "8267068C-FDBB-430A-8230-BE64F72CE3E3"

(51) SDK: ILxDeformerService interface
         LXxMETHOD(  LxResult,
 ScriptQuery) (
         LXtObjectID              self,
         void                   **ppvObj);

The DeformerFlags() method returns the LXfDEFORMER_* flags for the item, or NOTFOUND if this is not a deformer. DeformerChannel() returns the channel index for the evaluated deformer object.

(52) SDK: ILxDeformerService interface
         LXxMETHOD(  LxResult,
 DeformerFlags) (
         LXtObjectID              self,
         LXtObjectID              item,
         unsigned                *flags);
 
         LXxMETHOD(  LxResult,
 DeformerChannel) (
         LXtObjectID              self,
         LXtObjectID              item,
         unsigned                *index);

(53) User Service Class: DeformerService method
         bool
 IsDeformer (
         ILxUnknownID             item)
 {
         unsigned                 flags;
 
         return DeformerFlags (item, &flags) != LXe_NOTFOUND;
 }

Compute the merge of two change states.

(54) SDK: ILxDeformerService interface
         LXxMETHOD(  LxResult,
 MergeChangeState) (
         LXtObjectID              self,
         LxResult                 c1,
         LxResult                 c2);

Given a deformer, get the set of meshes that it influences. The MeshCount() interface will return LXe_FALSE if the deformer is currently inactive as result of being part of a deformation group.

(55) SDK: ILxDeformerService interface
         LXxMETHOD(  LxResult,
 MeshCount) (
         LXtObjectID              self,
         LXtObjectID              defItem,
         unsigned                *count);
 
         LXxMETHOD(  LxResult,
 MeshByIndex) (
         LXtObjectID              self,
         LXtObjectID              defItem,
         unsigned                 index,
         void                   **ppvObj);

(56) User Service Class: DeformerService method
         bool
 GetMesh (
         ILxUnknownID             defItem,
         unsigned                 index,
         CLxLoc_Item             &item)
 {
         LXtObjectID              obj;
 
         if (LXx_FAIL (MeshByIndex (defItem, index, &obj)))
                 return false;
 
         return item.take (obj);
 }

Given a group deformer item and a channel read object (for evaluation, not action) this returns the group deformer interface.

(57) SDK: ILxDeformerService interface
         LXxMETHOD(  LxResult,
 GroupDeformer) (
         LXtObjectID              self,
         LXtObjectID              dgroup,
         LXtObjectID              chanRead,
         void                   **ppvObj);

(58) User Service Class: DeformerService method
         bool
 GetGroupDeformer (
         ILxUnknownID             dgItem,
         ILxUnknownID             chanRead,
         CLxLoc_GroupDeformer    &dgObj)
 {
         LXtObjectID              obj;
 
         if (LXx_FAIL (GroupDeformer (dgItem, chanRead, &obj)))
                 return false;
 
         return dgObj.take (obj);
 }

Given a deformer, this returns the deformation item. If this is a locator deformer then it returns LXe_TRUE, otherwise FALSE.

(59) SDK: ILxDeformerService interface
         LXxMETHOD(  LxResult,
 DeformerDeformationItem) (
         LXtObjectID              self,
         LXtObjectID              defItem,
         void                   **ppvObj);

(60) User Service Class: DeformerService method
         bool
 GetDeformerDeformationItem (
         ILxUnknownID             deformer,
         CLxLoc_Item             &deformerItem,
         bool                    &isLocator)
 {
         LXtObjectID              obj = NULL;
         LxResult                 rc;
 
         rc = DeformerDeformationItem (deformer, &obj);
         if (LXx_FAIL (rc))
                 return false;
 
         isLocator = (rc == LXe_TRUE);
         return deformerItem.take (obj);
 }

Some events can cause the set of items that are targets for deformations to change implicitly. If that happens, a client can call this method to cause the deformation system to update.

(61) SDK: ILxDeformerService interface
         LXxMETHOD(  void,
 InvalidateTargets) (
         LXtObjectID              self,
         LXtObjectID              scene);

The LXtDeformElt type can represent a point or an item (so far). For points the value is the same as the LXtPointID for the point. For items it's a special pointer that can be converted to and from an item ILxUnknownID using these functions.

(62) SDK: ILxDeformerService interface
         LXxMETHOD(  LXtDeformElt,
 ItemToDeformElt) (
         LXtObjectID              self,
         LXtObjectID              item);
 
         LXxMETHOD(  LXtObjectID,
 DeformEltToItem) (
         LXtObjectID              self,
         LXtDeformElt             elt);

Empty Deformer service Python user class.

(63) PY: DeformerService method
 pass