Third Party Fuses/PreCalc and Process

From VFXPedia

Jump to: navigation, search

Contents

Anatomy of a Request

Once a fuse is rendered, a cascade of requests and event calls is triggered. You can easily monitor this by placing print() statements into Process() and other functions. The Debug Fuse, which doesn't do much on its own, is a good template for this.

The request that makes a tool render its output is handled by the Process() function. However, there's also a so-called precalc request which is executed before each render request and which can be handled by the PreCalcProcess() function.

This is what is happening to your tool once it gets rendered (disclaimer: this is not written by eyeon themselves so it might not be completely accurate).


PreCalcProcess

The first thing arriving at your fuse is the so-called precalc request. With it, Fusion wants to know what kind of image (size, DoD, bit depth, channels) it can expect and send downstream. No pixel processing will take place yet at this point. In order not to waste memory, the image objects being passed around mustn't contain any image data, just information about height, width, available channels and so on. These "dummy images" are created by using the IMG_NoData = true attribute when an image object is created.

By default, you won't notice the precalc request, since Fusion takes care of it for the most simple use case automatically: If you don't change anything about the input image dimensions and format, all that is needed is passing a dummy image from the main input to the Fuse's output. This will be taken care of if your Fuse just contains a regular Process() function.

When do you need custom precalc handling?

  • The output image won't match the main input in size, depth or number of channels.
  • You want to modify the DoD (output DoD doesn't equal input DoD).
  • You want to add or modify metadata.
  • You have more than one output (another image or - more common - an auxiliary number or point output that other tools can connect to).


In these use cases, you have two options to handle the precalc request. The first is to override the PreCalcProcess() function by simply adding one besides the regular Process() function:

function PreCalcProcess(req)
-- it's expected from you to pass valid data to every output there is.
-- an empty function like this will cause the render to fail.
-- output images have to be created with IMG_NoData = true
end

This is an example for a function that returns values for two additional outputs. These have to be calculated correctly (other tools might depend on them), while the output image is just a dummy object.

function PreCalcProcess(req)
   local img = InImage:GetValue(req)
 
   -- of course you would need to calculate proper return values here...
   OutAnotherPosition:Set(req, Point(0.5,0.5))
   OutAnotherNumber:Set(req, Number(180))
   -- output image with no data
   local out = Image({IMG_Like = img, IMG_NoData = true})
   OutImage:Set(req, out)
end


The second option is to define REG_NoPreCalcProcess = true in the FuRegisterClass call. This will call your Process() function for the precalc request and you won't have to implement a separate PreCalcProcess() handler. Usually, the same calculations will have to be performed for both kinds of request (e.g. determining the size of a modified DoD) so this will save you from duplicating lots of code. Most of the time you only need one or two if-statements that skip the actual pixel processing for precalc requests. This can be done by querying the request object. The IsPreCalc() method will return true for precalc requests and false otherwise.

Note: If your fuse has a PreCalcProcess() function, it will be called even if REG_NoPreCalcProcess is true. The tag only controls the behavior of the default handler if no such function is present.

Also, don't forget to add IMG_NoData = true to every image object you create in response to a precalc request. The elegant solution is this statement:

local outimg = Image({ IMG_Like = inputimg, IMG_NoData = req:IsPreCalc() })


There won't be a region of interest for precalc requests, since Fusion wants to know the maximum image size / DoD that the fuse could return. After the precalc requests have been handled throughout the flow, Fusion will request real image data from tools based on the current region of interest (which can differ from the image format if a RoI is set in the viewport, a tool has been restricted by a mask or a downstream tool requires data from outside the image dimensions). The dashed DoD rectangle in the viewers, however, is based on the DataWindow of the output image that has been created by PreCalcProcess(), not by the one that ultimately gets rendered in Process().

Process

The Process() function handles regular render requests as well as precalc requests if REG_NoPreCalcProcess has been set to true. It is already described here.


CheckRequest

Each tool that is about to be rendered (during precalc or regular requests), will collect all its input values, which not only means its upstream images but also numbers and slider values from the GUI or various modifiers which might be connected to a tool's input controls. By default, upstream images will get rendered before the current tool can render and all of the input controls have been queried before the Process() function is called. However, Fusion gives you the ability to interfere with this.

Inputs are queried in batches defined by their priority, where inputs of higher priority will be requested first and all inputs that have a lower priority won't be available yet. Define the input's priority by adding INP_Priority = <a number> to your input declarations. By default, an input has a priority level of zero. Just before each priority level is queried, the CheckRequest() function will be called. Its parameter is the Request object for the request that is about to happen. If you add such a function to your fuse, you can intercept a request to an upstream tool or any input control and modify or cancel that request. The Debug Fuse demonstrates this by printing debugging statements to the scripting console.

This technique is used in the Mix example of the C++ SDK, where the CheckRequest handler is used to prevent Fusion from rendering an upstream branch that will not be used in the final output (thus saving a lot of processing time). To cancel a request, call the request object's SetInputData() method and assign nil to an input.

Another use for this function is to modify the area that will be requested from upstream images (in case your Fuse is supposed to support DoD). If you don't interfere with CheckRequest(), Fusion will request the same area from upstream tools that is requested from your fuse. This makes sense if all you do is calculate pixels. But if you transform or resize an image in your fuse, you will almost definitely need a larger or different area of pixels. For example, if your Fuse scales the input image down to 50%, the area that needs to be requested from upstream will have to be twice as large. Have a look at the clMerge Fuse that ships with Fusion for details or check out the Overscan or BetterCornerPin Fuses. Note: This usage of CheckRequest() requires Fusion 6.31 or later.