Two weeks ago i finished a small feature film project, with 50% of the VFX work being greenscreen shots. And there I realised that it is a bit of a shame that Nuke Studio does not have a keyer. Sitting in the timeline environment trying to figure if the shot is going to work or not. This usually ends up in having to go from real-time land, into comp land, which can be a bit tricky when dealing with 8 minute plates. And just the convinience of being able to get a rough idea of how its going to look and aid clients who can’t abstract from greenscreen temps.
Next week we have another project with alot of keying shots, and I thought it would be a great idea to spend some time up front, to get a proper solution to the problem. Speaking of solutions.. this appear to be the current “best pratice:
The new blend layers (introduced in Nuke 9.0v7) in Nuke Studio and Hiero enables use of masking and alpha channels. And while cropping like above seem like a desperate move, it does open up for just the right stuff we need.
If you want to create custom “Soft Effects”, you can only use the predefined GPU accalerated notes that allready appear in the softeffects tab. You cannot use merges, shuffels, expressions, blinkcript or other nodes you would typically use for this. So a traditional node based keyer is out of the question. Well… There is one node that is not in the Soft Effects tab, that works in Nuke Studio. It is the “GPUOp” node.
The GPUOp node is a unique node that only renders to the viewport (not to the node tree). Using openGL shading langaue it works nearly identically to the blinkscript node, giving you a script editor and executes in runtime. This gives us great power to add (view only) tools that is not possible with any combination of the other supported nodes.
So to solve my problem i decided to re-purpose a old keyer that i originally designed for beauty work.
The essence of the keyer is to basic steps:
To get a good chroma seperation i turn the input from RGB into YCbCr
//CONVERT INPUT INTO YCBCR SPACE float CY = IN*0.299+IN*0.587+IN*0.144; float CB = (IN*-0.159+IN*-0.332+IN*0.05)+0.5; float CR = (IN*0.5+IN*-0.419+IN*-0.081)+0.5;
I then use basic linear keying (could be optimized a bit)
//COMPUTE LINEAR KEY float CYKey = min(min(1.0,(1.0/(CYLowMax-CYLowMin))*CY-((1.0/(CYLowMax-CYLowMin))*CYLowMin)),min(1.0,(1.0/(CYHighMin-CYHighMax))*CY-((1.0/(CYHighMin-CYHighMax))*CYHighMax))); float CBKey = min(min(1.0,(1.0/(CBLowMax-CBLowMin))*CB-((1.0/(CBLowMax-CBLowMin))*CBLowMin)),min(1.0,(1.0/(CBHighMin-CBHighMax))*CB-((1.0/(CBHighMin-CBHighMax))*CBHighMax))); CBKey = smoothstep(0.0,1.0,CBKey); //removing this improves performence of keyer! float CRKey = min(min(1.0,(1.0/(CRLowMax-CRLowMin))*CR-((1.0/(CRLowMax-CRLowMin))*CRLowMin)),min(1.0,(1.0/(CRHighMin-CRHighMax))*CR-((1.0/(CRHighMin-CRHighMax))*CRHighMax))); CRKey = smoothstep(0.0,1.0,CRKey); //removing this improves performence of keyer!
I can then take the keys and multiply them with eachother, and add other controls like basic lift-gamma-gain, clamp, invert, spill supression and what not.
(i know its Y and not CY)