Transition
Function
This node is an editing node to mix or cut two clips together. It is unique in that it is really a shell to drive other functions which determine the mixing. Modifying it will also modify the timing of the second input.
The mixers are either a cut, which simply cuts to the second clip at the frame that it starts, or mixes the second clip in over a specified frame range. The duration of the mixing is determined by the overlap value, and it starts at the frame the second clip appears. If you modify the timing of the second clip, the overlap value will change as well.
Here, I have two clips:
Appending a Transition node to them both will offset the second input clip:
You can now append one effect to both clips by attaching it to the Transition node. So, how is this different from just compositing them with an Over node and offseting clip 2 in time? Because you can easily dial in the overlap value to determine how many frames they overlap. Here, I have increased the overlap value in Transition, which shifts the second node to the left as you increase it. You could also shift clip 2, and read the overlap value in Transition.
If you are on cut mode, the cut point will occur at the beginning of clip 2, not the end of clip 1.
There is a common third parameter available in all mixers except "cut" which is the mixPercent. It determines the timing for the mixing. For example, for dissolve, if mixPercent is at 20, you are at 20% of the second image mixed in, 80% of the first. You can tune a curve interactively in the interface to adjust timing.
You can create your own custom mixers in a startup .h file. You must do two things:
nfxDefMixer("horizontalWipe","HWipe()");
Here is an example from the include/nreal.h file for horizontalWipe:
image HWipe( image i1=0, image i2=0, float blur=0, int reverse=0, float mixPercent="HermiteV(x,1,[0,50,50]@0,[100,50,50]@100)" ) { Color1 = Color( max(i1.width,i2.width),
max(i1.height,i2.height), 1, 1, red, red, 1, 0); Crop1 = Crop(Color1, 0, 0, width, height); Pan1 = Pan(Crop1, mixPercent*width/100*(reverse?-1:1)); BlurMe = Blur(Pan1,blur,0,0); IMult1 = IMult(i1, BlurMe , 1, 100, 0); Invert1 = Invert(BlurMe , "rgba"); IMult2 = IMult(Invert1, i2, 1, 100, 0); IAdd1 = IAdd(IMult1, IMult2, 1, 100); return IAdd1; } nfxDefMixer("horizontalWipe","HWipe()");
Notice how mixPercent has the default curve going from 0,0 to 100,100 for mixPercent. Also, notice how the Color generator compares the two input resolutions to determine how large to be using the max function.
Here is how to make your own transition mixer. We will choose to do a radial wipe by scaling the radius of a RGrad. I begin with a simple tree feeding two FileIns into a KeyMix. Notice I have named the two clips i1 and i2 to help me later on:
Here is the effect I want, which can be achieved by increasing the radius up and down.
![]() |
![]() |
![]() |
I copy it in the Node View with Ctrl+C and open a text file in my $HOME/nreal/include/startup directory, pasting it in:
RGrad1 = RGrad(720, 486, 1, width/2, height/2, 1, min(width,height)/4, min(width,height)/4, 0.5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0); in1 = FileIn("myclip.1-39#.iff", "Auto", 0, 0); in2 = FileIn("myotherclip.1-39#.iff", "Auto", 0, 0); KeyMix1 = KeyMix(in1, in2, RGrad1, 1, "A", 100, 0); // User Interface settings SetKey( "nodeView.KeyMix1.x", "156.75", "nodeView.KeyMix1.y", "127", "nodeView.RGrad1.x", "317.4916", "nodeView.RGrad1.y", "198.6512", "nodeView.in1.x", "67", "nodeView.in1.y", "201.125", "nodeView.in2.x", "202", "nodeView.in2.y", "198.3111" );
I can now prune a lot of the data, keeping only that which I've made bold in the above bit, and format it as a macro. I also know I want to add the standard parameters of blur, mixPercent and reverse. I copy them from the nreal.h file's HWipe node (at the end of the file). Finally, I calculate the resolution of the RGrad by comparing the two input sizes. I've made the new bits bold in the example below:
image RadialWipe( image in1=0, image in2=0, float blur=0, int reverse=0, float mixPercent="HermiteV(x,1,[0,50,50]@0,[100,50,50]@100)" ) { RGrad1 = RGrad( max(in1.width,in2.width), max(in1.height,in2.height), 1, width/2, height/2, 1, min(width,height)/4, //This is the radius min(width,height)/4, //This is the falloff 0.5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0); return KeyMix(in1, in2, RGrad1, 1, "A", 100, 0); }
The maximum distance I have to to expand the RGrad can be calculated by measuring the distance from the center to a corner, which I can do with the distance() function ("Hey! Where'd he pull that one from?" - go to Functions By Class - Expressions). Once I've calculated this, I multiply it by the mixPercent. I also plug the blur value into the falloff parameter, with a check on the radius to see if falloff should equal 0 when radius equals 0. I also add the command to load it as a mixer in the Transition node:
image RadialWipe( image in1=0, image in2=0, float blur=0, int reverse=0, float mixPercent="HermiteV(x,1,[0,50,50]@0,[100,50,50]@100)" ) { RGrad1 = RGrad( max(in1.width,in2.width), max(in1.height,in2.height), 1, width/2, height/2, 1, mixPercent*distance(0,0,width/2,height/2)/100, radius==0?0:blur, 0.5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0);
return KeyMix(in1, in2, RGrad1, 1, "A", 100, 0); } nfxDefMixer("radialWipe", "RadialWipe()");
Now the tricky bit - reversing the mix. You might think multiplying by -1 would invert the transformation, but you'd be sadly wrong and given a last cigarette, blindfolded and shot. Instead, you often have to subtract the value from the maximum value that you expect, in the case the distance from the center to the corner. This is part of a conditional statement that tests to see if reverse is activated. I also invert the mask in the KeyMix to help it out.
image RadialWipe( image in1=0, image in2=0, float blur=0, int reverse=0, float mixPercent="HermiteV(x,1,[0,50,50]@0,[100,50,50]@100)" ) { RGrad1 = RGrad( max(in1.width,in2.width), max(in1.height,in2.height), 1, width/2, height/2, 1, reverse?distance(0,0,width/2,height/2)- mixPercent*distance(0,0,width/2,height/2)/100: mixPercent*distance(0,0,width/2,height/2)/100, radius==0?0:blur, 0.5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0); return KeyMix(in1, in2, RGrad1, 1, "A", 100, reverse); } nfxDefMixer("radialWipe", "RadialWipe()");
I save all of this as a .h file in my startup directory.
As a final touch, I open a ui .h file and add an on/off button for the reverse parameter:
nuxDefExprToggle("RadialWipe.reverse");
Now when you relaunch Shake, you have a new mixer in Transition available
to you.
Parameters
|
Type
|
Defaults
|
Function
|
overlap |
int
|
0 | The amount that the second clip is shifted earlier (to the left) to provide overlap of the two clips |
mixer | string | "cut" | Other default choices are "horizontalWipe", "verticalWipe" and "dissolve". However, you can add your own effects. |
blur | float | 0 | This appears for horizontal and verticalWipe, and is used to soften the wiping edge. |
reverse | int | 0 | This appears for horizontal and verticalWipe, and is used to flip the direction, i.e., from left-to-right to right-to-left. |
Synopsis
image Transition( image i1, image i2, int overlap, const char * mixer, .... );
Script
image = Transition( i1, i2, overlap, "mixer", .... );