An operator reads in data, performs some calculations, and then writes out data.
The input and output for an operator comes from other scene elements. For example, an operator can have an input connection to the local kinematics of one object, and an output connection to the local kinematics of another object.
function ApplyMyFirstOperator_Execute( ) { // Create an Operator object var newOp = XSIFactory.CreateObject("MyTestOp"); // Define the input and output ports newOp.AddInputPort("Camera_Root.kine.local"); newOp.AddOutputPort("Camera_Interest.kine.local"); // Make the connections newOp.Connect(); return newOp; }
Each operator defines input and output ports, and it is through these ports that the operator is connected to scene elements such as local kinematics properties.
Softimage supports creating custom operators through a special API that allows you to implement the main calculation in an Update callback and provide user interaction/customization via the property page API in the same plug-in.
The Update callback uses the OperatorContext or OperatorContext object to get the input values and then write to the output target:
function MyFirstOperator_Update( ctxt ) { // Get the input value from the first port (port indexing is 0-based) var trans = ctxt.GetInputValue( 0 ).Transform; // Perform some sort of operator on the transformations... // Apply the result to the target of the output port ctxt.OutputTarget.Transform = trans ; return true; }
Because the input port is connected to a kine.local, GetInputValue(0) returns a KinematicState or KinematicState object.
If the port was connected to an actual parameter, such as kine.local.posx, GetInputValue would return the X position value.
An operator may not necessarily know how many input connections there are. For example, there may be an input port for each selected object, or for each object picked by a user. To handle an arbitrary number of connections, we can get the CustomOperator or CustomOperator object from the context and then get the actual number of connections.
function MyFirstOperator_Update( ctxt ) { // Get the CustomOperator and use it to // find out how many inputs are connected var oOp = ctxt.Source ; // There is only one port group, containing all the inputs and // the single output var cntInputs = oOp.GetNumPortsInGroup(0) - 1 ; // Add all the input objects positions for ( var i = 0 ; i < cntInputs ; i++ ) { var oInputKinematicState = ctxt.GetInputValue( i /* port */, 0, 0) ; } }
So far, all the code we've looked at is for static operators whose connections never change after Connect() is called. If you want to build a dynamic operator that allows you to dynamically add and remove connections, see Static versus Dynamic Operators.
The recommended way to create custom operators is using the Self-Installed Custom Operator (often abbreviated as SICO) API, which is the focus of this chapter. There are other ways to build custom operators, such as runtime or legacy; however, the term custom operator in this chapter always refers to the self-installed type of custom operator, unless otherwise specified.
Furthermore, the term custom operator does not apply to Fx and Simulation operators (which are two examples of other types of operators in Softimage). For information about customizing Fx operators, see Custom Fx Operators. Simulation operators cannot be custom-built for use in Softimage but you can use custom operators to achieve similar effects.
Here is a basic overview of how to implement custom operators for Softimage:
Implement your algorithm inside the Update callback, which provides access to the custom operator, its connections, and any parameters defined for that operator through the OperatorContext or OperatorContext argument.
If you need to store any user data, implement the Init and the Term callbacks. These callbacks provide a means of storing user data when the operator is instantiated, and then releasing it when the operator is removed (for example, storing a pointer to a custom C++ object). The cached data is not persisted.
To set up custom parameters, you need to add them to the operator as part of the DefineLayout callback implementation. You can then format them with DefineLayout (just like Custom Properties).
There is no callback for creating the connection definition of the operator, or for resolving the connection. That is handled by the code that creates the operator, as described in Applying Operators in Softimage.
All callbacks take only a single argument. This argument is either a Context or Context object or an OperatorContext or OperatorContext object.
Most of the time, you should be able to use the Custom Operator Wizard to do much of the legwork before writing the actual implementation code.
For more information, see the Operator Callbacks reference.
You can build several types of custom operators:
Generators —operators that create mesh geometry.
Deformer —operators that change the positions of the points on the geometry
Constraining Operators —operators that influence the position of an object or drive the value of a parameter.
Topology Changes —operators that add or remove points (not fully supported)
A generator operator builds its own mesh; for example, it may be a new type of primitive that is programmatically generated, or it may be a mesh that contains the processed results of some other mesh or input.
A generator operator needs to be at the very bottom of the operator stack. Otherwise it won't successfully write to the geometry.
The typical method for applying a generator operator is to build a simple primitive, freeze it (to erase the Softimage generator operator), and then apply the custom generator. This properly installs the operator, and then deformation and other operators can be added above it.
You must have an input and output port (on the same group) attached to the Primitive or Primitive of the object you want to deform. You must specify the output port first.
A deformation operator never adds or removes points of the geometry, it just changes their positions. In other words it changes the shape but not the topology of the operator.
You can establish a constraint-like relationship between two or more elements similar to the built-in Softimage constraint (see Constraints vs. Custom (Scripted) Operators? for more information on the difference between true constraints and custom operators). For example, you could create a custom operator that calculates an object's position based on averaging two or more other scene elements.
Topology operators are similar to deformers except that they actually add or remove points from the geometry. An example of a built-in topology operator is Extrude Geometry Component. Unlike a generator operator, this type of operator is not at the bottom of the stack - instead it has an input port which reads some initial geometry and then outputs a new topology to that same geometry.
Softimage currently does not fully support custom topology operators. The problem is that any cluster or cluster property will not properly update when a topology operator adds or removes points that belong to the cluster. In the worst case Softimage may crash. Hence custom topology operators should only be used in the more limited scenario of objects that do not have any clusters. Once the geometry is ready it would be possible to freeze the object to remove the custom topology operators (but leave the result of their evaluation), then to add the clusters and other operators.