neighbourConstraint Node


User's Guide

Okay, we admit it: neighbourConstraint is a terrible name for this node. We're looking at creating a more fully-functioned version in the future and we promise that we'll give it a better name then.

The neighbourConstraint node is similar to Maya's animCurveUU node, but with the following additional features:

  • The curve's data points (e.g. keyframes) can be supplied by plugs, whereas Maya's animCurve nodes require the use of the setKeyframe command. This means that the data points themselves can be animated, which is useful when you want to use the node for something other than keyframe interpolation.

  • One node can drive multiple outputs which share the same set of data points, but interpolate different values. To frame this in terms of the animCurve node, it's as if one node could simultaneously take several different input times and generate separate output values for each one. Again, this becomes more useful when doing things other than keyframe interpolation, where there is typically just one time stream.

The neighbourConstraint node also has certain restrictions:

  • Only linear interpolation is performed. You cannot specify tangent types or set your own tangents.

  • Normally, when you connect two node plugs together, the input plug becomes locked, meaning that it cannot be changed in the Attribute Editor, Channel Box, or by using a setAttr command. However, Maya's animCurve nodes are different in that you can still change the input plug to which their outputs are connected. This is known as a passive connection. The neighbourConstraint node does not allow for passive connections (because Maya's API does not provide it), so you cannot change the value of an input attribute while it is connected.

  • The curve interpolated by a neighbourConstraint node will not appear in the Graph Editor.

As an example of the neighbourConstraint's use, suppose that we have a curve representing a river and a set of measurements of the current at different points along the river. For each measurement we have its position, which in this case would be its U parameter along the curve, and its value, which would be the speed of the current at that point:

Position (U)Current
05 knots
18 knots
36 knots
44 knots

We then have two boats travelling along the river. The current affecting each boat can be interpolated solely on the basis of the current at the sample immediately ahead of the boat, and the current at the sample immediately behind it. Any other current samples further up or downstream have no effect on that boat.

The diagram below shows the river with the sample points marked. For convenience, the two boats are represented by parameterDimension locators, which are shown in yellow. boat1 has been positioned at U value 0.3 while boat2 is at U value 2.5:

boats with locators

The current affecting each boat can be determined by creating a neighbourConstraint node and feeding the current samples into its input attributes, as follows:

    createNode -name "nc" neighbourConstraint;

    setAttr nc.inputs[0].inputPosition 0;
    setAttr nc.inputs[0].inputValue    5;

    setAttr nc.inputs[1].inputPosition 1;
    setAttr nc.inputs[1].inputValue    8;

    setAttr nc.inputs[2].inputPosition 3;
    setAttr nc.inputs[2].inputValue    6;

    setAttr nc.inputs[3].inputPosition 4;
    setAttr nc.inputs[3].inputValue    4;

In this example, the input positions and values are all constant, but they could also be driven by expressions or connections to other attributes. Furthermore, although we entered the samples into the inputs array in order of ascending position, this is not a requirement: they may be entered in any order and the neighbourConstraint node will sort them out correctly.

Next, we feed the positions of the boats into the neighbourConstraint node's targetPositions array, as follows:

    connectAttr boat1.uParamValue nc.targetPositions[0];
    connectAttr boat2.uParamValue nc.targetPositions[1];

Now we can retrieve the current affecting each boat from the corresponding element of the targetValues array:

    // Get the speed of the current affecting boat1.
    getAttr nc.targetValues[0];
    // Result: 5.9 //

    // Get the speed of the current affecting boat2.
    getAttr nc.targetValues[1];
    // Result: 6.5 //

Note that instead of directly setting the positions of the boats in the targetPositions array, we connected their uParamValue attributes to the targetPositions array. The advantage of this is that we can move the boats to new positions along the river and the neighbourConstraint node will automatically calculate the current affecting them at their new positions.

two boats on a river

In the diagram above, boat1 has been moved to position 1.1, just past the second current sample, and boat2 has been moved to position 3.5, exactly between the third and fourth current samples. If we once again query the neighbourConstraint node for the current affecting each boat at its new position, we get the expected results of 7.9 knots and 5.0 knots:

    getAttr nc.targetValues[0];
    // Result: 7.9 //

    getAttr nc.targetValues[1];
    // Result: 5.0 //

At this point, you might be wondering why we wouldn't just use an animCurveUU node instead, hooking the boat's U position to the node's input attribute and taking the current affecting it off of the node's.

One reason can be seen by noting that an animCurveUU node only has a single input and a single output attribute. So even though both boats are travelling the same river, with the same currents, you would need a separate animCurveUU for each one. The neighbourConstraint node, however, allows multiple inputs and outputs, so both boats can be handled by a single node.

For an even bigger advantage of the neighbourConstraint node, consider that at any given point along our river, the current remains constant. In the real world, however, currents vary depending upon a number of factors, such as recent rainfall, snowmelt and tides. So let's say that our animation includes a period of rainfall. Shortly after it starts raining, the current should begin to increase, eventually levelling off at some higher rate. Then, sometime after the rain ends, the current should slowly drop back to its original values.

Doing this with the neighbourConstraint node is a snap. Instead of specifying all of the node's inputValues as constants, we can create an expression node for each sample point along the river, and have those expressions calculate the resulting currents after taking rainfall into account. The outputs of the expression nodes can then be connected to the inputValue plugs for each sample point.

This is something that cannot be done with an animCurveUU node because you cannot connect other nodes to its keyTime or keyValue inputs. You have to use the setKeyframe command to change the sample values, which is not a workable solution when an animation is running.

One final note. Although we talk in terms of the positions of the sample points and targets, these need not be physical distances, or even parameter values, but can be any kind of numerical value, such as rotation, light intensity, etc. For example, you might use a neighbourConstraint node to model the glow given off by an electric stove element as it heats up. In such a case, the inputPositions would be various sample temperatures and the inputValues would be the intensity of the element's glow at those temperatures. The targetPositions might then be the current temperatures of several different elements on the stove and targetValues would contain the intensities of their respective glows, as calculated by the neighbourConstraint node.

Attribute Reference

A neighbourConstraint node's special attributes are found in the Attribute Editor under the Neighbour Constraint heading.

attribute editor

Long (Short) Name Type Default
minPosition (min) double 0.0 The minimum value for the range of possible positions. If a targetPosition is such that none of the inputs has an inputPosition less than it, then the neighbourConstraint node will behave as if there was an input at minPosition with a value of 0.0, thereby ensuring that the target still has a neighbour on that side.
maxPosition (max) double 0.0 The maximum value for the range of possible positions. If a targetPosition is such that none of the inputs has an inputPosition more than it, then the neighbourConstraint node will behave as if there was an input at maxPosition with a value of 0.0, thereby ensuring that the target still has a neighbour on that side.
inputs (i) compound array n/a There is one element in the inputs array for each constraining object.
inputPosition (ip)
double 0.0 Position of the constraining object. This must lie between minPosition and maxPosition, inclusive.
inputValue (iv)
double 0.0 The value of the constraining object.
targetPositions (tp) double array 0.0 The positions of each of the objects to be constrained. These must lie between minPosition and maxPosition, inclusive.
targetValues (tv) double array 0.0 The resulting constrained value for each of the target objects. The ith targetValue goes with the object whose position is in the ith element of targetPositions.

Support & Copyright Information

The neighbourConstraint node and its associated materials, which are collectively referred to as "this product", are copyright Gooroos Software, 1999-2004.

Gooroos Software provides this product as-is and assumes no liability for its use. You may freely redistribute it, but only in complete and unmodified form.

If you have any questions or problems with this product, please send email to Because this product is made freely available, we cannot guarantee you a response, but we will try to get back to you as time permits.

For more information on Gooroos Software and our other products, please visit our web-site at


Platform Size (beta)Linux 46K Download (beta)WinXP 527K Download 46K Download 526K Download 46K Download 297K Download 89K Download 289K Download

Installation Instructions

Return to Products