......BACK....

SOURCE = http://withanar.blogspot.com/

 

ICE | Tutorial 1: Local versus Global Space for ICE calculations

Many Objects, Many Different SRT Spaces

When performing calculations in ICE, there will be times you want to pull in data from many different scene elements, including geometry surfaces, curves, nulls, etc. Each one of these objects may have a unique global SRT setting. Furthermore, the mesh or point cloud you are trying to drive with an ICE operator may have its own unique SRT settings.

For the person new to ICE, or the artist attempting to build a new custom operation to supplement the factory compounds, it can be difficult to sort out how to deal with SRT space. The following simple examples should help in this regard.

1. Coordinate space is always relative to the scene object hosting the operator
This is true not only for ICE operators, but for scripted operators, and point position array data on geometry. Incidentally, it is also true for particle rotation and scale values on clouds.

Whatever values are set in the array of point positions, they are multiplied by the SRT matrix of the host object. For example, if you get a sphere with radius of 1, and scale it up uniformly by 5 units, the radius will be 5.

The same would be true if you were controlling the positions of the points from inside an ICE Tree. You could place all the vertex points, mathematically, at a distance of 1 unit from center. But if the object has a different scale in it's center's SRT, the global position of those points will be modified accordingly.

How do you deal with different objects, each with potentially different SRT settings inputting data into a single operator?

When working in ICE, luckily, many of the Factory compiled nodes do this for you automatically. For example, if you use a [Raycast] node, or [Get Closet Location], or [UV to Location], it doesn't matter what the SRT's are for the objects driving the Geometry input for those nodes. The result coming out of that node is processed relative to the SRT of the object hosting the ICE operator.

1. Processing Point Positions from two objects with different SRT's using a factory ICE node


The following Jscript builds a simple ICE Tree where a sphere is hosting the ICE operator, and using a [Get Closest Location] node with a NURBS curve as Geometry input. Both the host sphere and the curve have been transformed away from origin.

//BEGIN SCRIPT
CreatePrim("Sphere", "MeshSurface", null, null);
Translate(null, -7.79244806469314, 7.23979894153846, 0, siRelative, siParent, siObj, siXYZ, null, null, null, null, null, null, null, null, null, 0, null);
CreatePrim("Circle", "NurbsCurve", null, null);
Translate(null, 7.4199007468592, 5.15796834461538, 0, siRelative, siParent, siObj, siXYZ, null, null, null, null, null, null, null, null, null, 0, null);
ApplyOp("ICETree", "sphere", siNode, null, null, 0);
AddICENode("GetDataNode", "sphere.polymsh.ICETree");
SetValue("sphere.polymsh.ICETree.SceneReferenceNode.reference", "circle", null);
AddICENode("GetDataNode", "sphere.polymsh.ICETree");
AddICECompoundNode("Get Point Position", "sphere.polymsh.ICETree");
AddICENode("$XSI_DSPRESETS\\ICENodes\\GetClosestLocationNode.Preset", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.GetClosestLocationNode.geometry", "sphere.polymsh.ICETree.SceneReferenceNode.value");
ConnectICENodes("sphere.polymsh.ICETree.GetClosestLocationNode.position", "sphere.polymsh.ICETree.Get_Point_Position.Value");
AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.SceneReferenceNode[2].source", "sphere.polymsh.ICETree.GetClosestLocationNode.location");
SetValue("sphere.polymsh.ICETree.SceneReferenceNode[2].reference", "PointPosition", null);
AddICENode("$XSI_DSPRESETS\\ICENodes\\SubtractNode.Preset", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.SubtractNode.first", "sphere.polymsh.ICETree.SceneReferenceNode[2].value");
ConnectICENodes("sphere.polymsh.ICETree.SubtractNode.second", "sphere.polymsh.ICETree.Get_Point_Position.Value");
AddICECompoundNode("Set Data", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.Set_Data.Value", "sphere.polymsh.ICETree.SubtractNode.result");
ConnectICENodes("sphere.polymsh.ICETree.port1", "sphere.polymsh.ICETree.Set_Data.Execute");
SetValue("sphere.polymsh.ICETree.Set_Data.Reference", "self.ICEopVectors", null);
DisplayPortValues("sphere.polymsh.ICETree.Set_Data.Value", true, 1, true, "", 0, 0, 0, 1, false, true, 0.62, 1, 0.62, 1, false, 0, 10000, 1, false, false, 0, 10, false, true, false, 100);
DeleteObj("sphere.polymsh.ICETree.SceneReferenceNode[1]");
SetValue("sphere.polymsh.ICETree.Name", "ICEtoCrv", null);
//END SCRIPT


Scene Result


ICE Tree

You can see in the scene result that the vectors from each point position of the sphere successfully point to their closest locations on the curve. This shows the point positions in the ICE tree have been calculated in the same relative SRT space.

If you run the script, you can see interactively that the relationship remains funtional, even if you scale, rotate, translate either the sphere or the curve.

Because the [Get Closest Location] node, and all the other factory ICE nodes deal with SRT space automatically, many users will go pretty far building custom effects in ICE without ever being aware of the SRT issue. Problems will only appear the first time they try and use the global position vector of a null.


2. Using a Null's Global Pos as Input (A Common Mistake)

What happens if we need to use a null to draw vectors relative to our point positions? Typically there are no problems if the operator host object is at scene origin, but as soon as the node is transformed away, things start to break.

A common example of this is the eyeball. We might build an operator for pushing eyelids off the cornea geometry which works fine when our rig is in rest position. But as soon as we start moving the character around the scene, the eyelid deformation goes crazy.

The next example demonstrates why:
//START SCRIPT
CreatePrim("Sphere", "MeshSurface", null, null);
Translate(null, -3.35968115523466, 4.58529230769231, 0, siRelative, siParent, siObj, siXYZ, null, null, null, null, null, null, null, null, null, 0, null);
GetPrim("Null", null, null, null);
Translate(null, 4.72511306859206, 3.09282461538462, 0, siRelative, siParent, siObj, siXYZ, null, null, null, null, null, null, null, null, null, 0, null);
ApplyOp("ICETree", "sphere", siNode, null, null, 0);
AddICENode("GetDataNode", "sphere.polymsh.ICETree");
SetValue("sphere.polymsh.ICETree.SceneReferenceNode.reference", "sphere", null);
AddICENode("GetDataNode", "sphere.polymsh.ICETree");
SetValue("sphere.polymsh.ICETree.SceneReferenceNode[1].reference", "null", null);
AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.SceneReferenceNode[2].inname", "sphere.polymsh.ICETree.SceneReferenceNode[1].outname");
SetValue("sphere.polymsh.ICETree.SceneReferenceNode[2].reference", "kine.global.pos", null);
AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.SceneReferenceNode[3].inname", "sphere.polymsh.ICETree.SceneReferenceNode.outname");
SetValue("sphere.polymsh.ICETree.SceneReferenceNode[3].reference", "PointPosition", null);
AddICENode("$XSI_DSPRESETS\\ICENodes\\SubtractNode.Preset", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.SubtractNode.first", "sphere.polymsh.ICETree.SceneReferenceNode[2].value");
ConnectICENodes("sphere.polymsh.ICETree.SubtractNode.second", "sphere.polymsh.ICETree.SceneReferenceNode[3].value");
AddICECompoundNode("Set Data", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.Set_Data.Value", "sphere.polymsh.ICETree.SubtractNode.result");
ConnectICENodes("sphere.polymsh.ICETree.port1", "sphere.polymsh.ICETree.Set_Data.Execute");
SetValue("sphere.polymsh.ICETree.Set_Data.Reference", "self.GlobalKineVectors", null);
DisplayPortValues("sphere.polymsh.ICETree.Set_Data.Value", true, 1, true, "", 0, 0, 0, 1, false, true, 0.62, 0, 0, 1, false, 0, 10000, 1, false, false, 0, 10, false, true, false, 100);
//END SCRIPT


Scene Result


ICE Tree


Our intention was to draw vectors that originate at each vertex point and end at the null. So we do what has always worked before, we pull in the global position of the null and subtract the point positions of the sphere.

The problem here is, the sphere has been transformed away from origin and so has the null to somewhere else. So their point positions exist in completely different SRT spaces. There is no factory ICE node resolving spatial differences for us here, therefore the results don't do what we were hoping.


3. Using a Null's Global Pos as Input (Converting SRT space)
This last example builds an ICE Tree that resolves the difference between object space.

In order to get our math to work, we have to get our position data all into the same SRT space first. As long as our results are set to the SRT space of the operator's host object, everything will function.
//START SCRIPT
CreatePrim("Sphere", "MeshSurface", null, null);
Translate(null, -4.03161738628159, 5.52392861538462, 0, siRelative, siParent, siObj, siXYZ, null, null, null, null, null, null, null, null, null, 0, null);
GetPrim("Null", null, null, null);
Translate(null, 4.59216311913357, 5.09237169230769, 0, siRelative, siParent, siObj, siXYZ, null, null, null, null, null, null, null, null, null, 0, null);
ApplyOp("ICETree", "sphere", siNode, null, null, 0);
AddICENode("GetDataNode", "sphere.polymsh.ICETree");
SetValue("sphere.polymsh.ICETree.SceneReferenceNode.reference", "sphere", null);
AddICENode("GetDataNode", "sphere.polymsh.ICETree");
SetValue("sphere.polymsh.ICETree.SceneReferenceNode[1].reference", "null", null);
AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.SceneReferenceNode[2].inname", "sphere.polymsh.ICETree.SceneReferenceNode.outname");
SetValue("sphere.polymsh.ICETree.SceneReferenceNode[2].reference", "PointPosition", null);
AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.SceneReferenceNode[3].inname", "sphere.polymsh.ICETree.SceneReferenceNode[1].outname");
SetValue("sphere.polymsh.ICETree.SceneReferenceNode[3].reference", "kine.global.pos", null);
AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.SceneReferenceNode[4].inname", "sphere.polymsh.ICETree.SceneReferenceNode.outname");
SetValue("sphere.polymsh.ICETree.SceneReferenceNode[4].reference", "kine.global", null);
AddICENode("$XSI_DSPRESETS\\ICENodes\\InvertNode.Preset", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.InvertNode.value", "sphere.polymsh.ICETree.SceneReferenceNode[4].value");
AddICENode("$XSI_DSPRESETS\\ICENodes\\SubtractNode.Preset", "sphere.polymsh.ICETree");
AddICENode("$XSI_DSPRESETS\\ICENodes\\MultiplyVectorByMatrixNode.Preset", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.MultiplyVectorByMatrixNode.matrix", "sphere.polymsh.ICETree.InvertNode.result");
ConnectICENodes("sphere.polymsh.ICETree.MultiplyVectorByMatrixNode.vector", "sphere.polymsh.ICETree.SceneReferenceNode[3].value");
ConnectICENodes("sphere.polymsh.ICETree.SubtractNode.second", "sphere.polymsh.ICETree.SceneReferenceNode[2].value");
ConnectICENodes("sphere.polymsh.ICETree.SubtractNode.first", "sphere.polymsh.ICETree.MultiplyVectorByMatrixNode.result");
AddICECompoundNode("Set Data", "sphere.polymsh.ICETree");
ConnectICENodes("sphere.polymsh.ICETree.Set_Data.Value", "sphere.polymsh.ICETree.SubtractNode.result");
ConnectICENodes("sphere.polymsh.ICETree.port1", "sphere.polymsh.ICETree.Set_Data.Execute");
SetValue("sphere.polymsh.ICETree.Set_Data.Reference", "self.ConvertedVectors", null);
DisplayPortValues("sphere.polymsh.ICETree.Set_Data.Value", true, 1, true, "", 0, 0, 0, 1, false, true, 0.62, 1, 0.62, 1, false, 0, 10000, 1, false, false, 0, 10, false, true, false, 100);
DisconnectICENodePort("sphere.polymsh.ICETree.SubtractNode.second");
ConnectICENodes("sphere.polymsh.ICETree.SubtractNode.second", "sphere.polymsh.ICETree.SceneReferenceNode[2].value");
//END SCRIPT


Scene Result


ICE Tree

The solution for this graph is to convert the point position data from the input null to the relative SRT space of the operator host object.

The formula for this is:
Multiply the global point positions of the data you want to convert from
by the inverted SRT matrix you want to convert to


There may be other times you want to convert everything to global space to do your vector calculations, then back to the relative space of the operator's host object. But the above formula should work most of the time, plus it's the more direct route, since the final output needs to be in the SRT space of the operator host object anyway.