Value provider (output knobs)

Sometimes a node has an intermediate calculation that it wishes to expose to users. For example, NUKE’s 3D nodes find it useful to provide an “output knob” for the transformation matrix that has been calculated from the translate/scale/rotate knobs.

In order to allow this, NUKE lets you set a “ValueProvider” on certain knobs (namely those inheriting from the Array knob type). ValueProvider differs from standard knob linking in the sense that it provides a Model-View type interface, so that the value of the new knob is actually directly dependent on the ValueProvider and thus the source data, as opposed to both knobs maintaining storage and state, and simply updating each other when they change.

As such, a ValueProvider linked knob is ‘OUTPUT_ONLY’ both in terms of the knob flag, and in that an end user is only able to view the value and not change it. Let’s take a look at some of the details.

void knobs(Knob_Callback f)
{
  Float_knob(f, &_c, "output");
  SetValueProvider(f, this);
}

The object pointed to by the second parameter of SetValueParameter has to be an implementation of the ArrayKnobI::ValueProviderI class. In the example above it is assumed that the Op itself is an implementation of ValueProviderI. It needs to implement the following methods:

bool ArrayKnobI::ValueProviderI::provideValuesEnabled(const DD::Image::ArrayKnobI* None, const DD::Image::OutputContext& oc) const

This is given the pointer to the knob in question, and an OutputContext and should return true if the ValueProviderI wishes to provide the value at this context, or false if the internal value from the ArrayKnob should be used.

std::vector<double> ArrayKnobI::ValueProviderI::provideValues(const ArrayKnobI* arrayKnob, const DD::Image::OutputContext& oc) const

This function is called if provideValuesEnabled() has returned true already. It is given the arrayKnob and the context and should return a vector corresponding in size to the number of elements in the ArrayKnob (e.g. 1 for a Float_knob, 2 for an XY_knob), etc. It should calculate the values to be displayed/exposed, and return them. For example:

virtual std::vector<double> provideValues(const ArrayKnobI* arrayKnob, const DD::Image::OutputContext& oc) const {
  std::vector<double> values;
  values.push_back(knob("a")->get_value_at(oc.frame(), oc.view()) * knob("b")->get_value_at(oc.frame(), oc.view()));
  return values;
}

If multiple knobs are using the same value provider then it can distinguish between them from the first parameter. Note that when provideValues() is called on an object which is also an Op, you cannot rely on the state of that Op being valid or up-to-date for the passed-in-context. This is why this function fetches the knob values itself, making sure to specify the time and view from the OutputContext. Note additionally that provideValues cannot take its source from, for example, image data and so forth.

The NDK contains a ‘ValueProviderOp’ sample which demonstrates a simple case using a ValueProvider to link a Color_knob and a MultiFloat_knob. If you’re looking to link non-axis knob types then you may want to check out the The knob_changed() method section.

Previous topic

Creating custom knobs

Next topic

Advanced