set cut_paste_input [stack 0] version 12.2 v5 push $cut_paste_input Dot { name Dot8 note_font_size 44 selected true xpos -2234 ypos 4931 } set N3129d000 [stack 0] push 0 Dot { name Dot9 label denoise note_font_size 20 selected true xpos -2338 ypos 4855 } set N34298c00 [stack 0] push 0 Dot { name Dot10 label plate note_font_size 20 selected true xpos -2624 ypos 4866 } set N34298800 [stack 0] push $N3129d000 Group { inputs 3 name DasGrain help "DasGrain makes regraining as simple as clicking a few buttons.\n\nFollow the steps in the Help tab and you'll have a perfect regrain in no time!" onCreate "import random\n\ntestimonials = \[\n \"Such an elegant solution, love it!\",\n \"Your gizmo is beyond expectation\",\n \"Totally awesome!\",\n \"DasGrain is officially the best thing ever\",\n \"It's really working!\",\n \"Das bringt Tränen in meine Augen\",\n \"DasGrain is the salvation we waited for\",\n \"I save a lot of time, and definitely my nerves :)\",\n \"It's alright\",\n \"My new favourite node, thanks!
Having said that, ...\"\n ]\n\nnode = nuke.thisNode()\nnode\['testimonial'].setValue('


«%s»
— anonymous

' % random.choice(testimonials))\nnode\['box'].setFlag(nuke.NO_ANIMATION)" knobChanged "n = nuke.thisNode()\nk = nuke.thisKnob()\n\nif k.name() == 'box':\n this_frame = nuke.frame()\n n\['sample_frame'].setValue(this_frame)\n\nif k.name() == 'scatter':\n n\['divider04'].setVisible(k.value() == False)\n n\['divider05'].setVisible(k.value() == True)" tile_color 0x7f7f7fff selected true xpos -2128 ypos 5012 addUserKnob {20 DasGrain_tab l DasGrain} addUserKnob {41 output t "regrained comp it is what it sais\nplate grain plate minus degrained plate\nnormalised grain check if the normalization worked. It should be as even as possible. This is what you want to output if you want to prerender a grain plate. Later you can plug it into the external grain input of another DasGrain\nadapted grain check if the adaptation worked. Output this if you want to further manipulate the grain (who knows what the sup is gonna come up with...). After, simply plus it to your comp (at that point the comp has to be in the camera colorspace, as set in the Analyze tab).\ngrain QC check if voronoi seams are visible (→ edgeblend), or the scattered grain looks different to the original plate grain (→ maybe bad sample area or wrong luminance degrain amount)" T Output.output} addUserKnob {4 meta l "metadata from" t "Chances are you want to use the metadata from the plate, but who am I to assume :)" M {COMP PLATE}} addUserKnob {26 spacer01_1 l " " T " "} addUserKnob {20 GrainGroupBegin l "" +STARTLINE n -2} addUserKnob {20 Analyze_tab l Analyze} addUserKnob {26 text l Colorspace} addUserKnob {41 project_colorspace l project t "set this to the project color space" T OCIOColorSpace1.in_colorspace} addUserKnob {22 python_button l "What's this all about?" -STARTLINE T "nuke.message(\"Regraining in other color spaces than the camera native linear space can lead to unexpected behaviour.\\n\\nFor example converting Alexa plates to ACEScg might introduce negative values due to ACEScg's smaller gamut. In that case converting back to ARRI Linear ALEXA Wide Gamut will probably help.\\nJust set project to ACEScg and camera to ARRI Linear ALEXA Wide Gamut.\\n\\nThis might be transferable to other cameras, but I've only tested with Alexas.\\n---------\\nBypass by setting both knobs to the same value.\")"} addUserKnob {41 camera_colorspace l camera t "set this to the camera native linear space" T OCIOColorSpace1.out_colorspace} addUserKnob {26 text_2 l " " T " "} addUserKnob {26 level l "Degrain amount"} addUserKnob {78 luminance t "Leave this at 1 if you're working on a completely degrained plate.\n\nIn case you decided to leave some luminance grain in the degrained plate (use the DegrainHelper node for this!), set this to the same value as in the DegrainHelper in order to compensate.\n\nIf the luminance degrain amount was set to 0.8, this needs to be set to 0.8 as well.\n\nYou need to select a mask of all elements that cover the plate, otherwise the grain of whole comp will be too strong " n 1} luminance 1 addUserKnob {26 divider01 l " "} addUserKnob {41 degrain_amount_mask l "degrain amount mask" t "Use this channel from the mask input to specify in what area of the comp the missing luminance grain needs to be compensated." T Multiply1.maskChannelMask} addUserKnob {41 invert_mask l invert -STARTLINE T Multiply1.invert_mask} addUserKnob {26 spacer02 l " " T " "} addUserKnob {26 divider02 l Analyze} addUserKnob {3 number_of_frames l "number of frames" t "Set the number of sample frames to be spread across the input range.\n\nMore frames lead to higher accuracy.\n\nIf there are particularly bright or dark frames, set them manually in the knob below to make sure they are part of the analysis.\n\nIf you want to set all sample frames manually, set this to 0 and add the frames in the knob below."} number_of_frames 10 addUserKnob {1 additional_frames l "additional frames" t "Set additional frames like this:\n\n1001,1020,1053 (single frames)\n1020-1040 (frame ranges)\n1020-1040x4 (frame ranges with step)"} addUserKnob {3 sample_count l "sample count" t "The samples are spread across the sample range (which gets calculated automatically) based on the AlexaV3LogC curve. This results in more samples in the dark areas and less samples in the brights.\n\nMore samples lead to a more detailed response curve (while the accuracy is limited by the quality of the degrain)."} sample_count 20 addUserKnob {22 analyze l Analyze t "this is where the magic happens" T "import base64\nthis = nuke.thisNode()\n\n\ndef _sample_count(this):\n \"\"\"returns the sample count\"\"\"\n\n sample_count = int(this\['sample_count'].value())\n\n if sample_count <= 0:\n raise RuntimeError('Enter a sample count greater than 0')\n\n else:\n return sample_count\n\n\ndef _generate_frame_list(this):\n \"\"\"converts the frames submitted by the user into a list\"\"\"\n\n frame_list = \[]\n number_of_frames = int(this\['number_of_frames'].value())\n additional_frames = this\['additional_frames'].value()\n\n if number_of_frames < 1 and additional_frames is '':\n raise RuntimeError('Either set the number of frames > 0\\nor define additional frames')\n\n first_frame = max(this.input(1).firstFrame(), this.input(2).firstFrame())\n last_frame = min(this.input(1).lastFrame(), this.input(2).lastFrame())\n\n if number_of_frames > 0:\n distance = (last_frame - first_frame) / (number_of_frames)\n frame = first_frame + distance / 2\n\n for x in range(number_of_frames):\n int_frame = int(round(frame))\n if int_frame not in frame_list:\n frame_list.append(int_frame)\n\n frame += distance\n\n frange = nuke.FrameRanges(additional_frames.split(','))\n\n for r in frange:\n for f in r:\n if f >= first_frame and f <= last_frame:\n if f not in frame_list:\n frame_list.append(f)\n\n frame_list.sort()\n\n return frame_list\n\n\ndef _setup_for_multiframe(frame_list):\n \"\"\" arranges all sample frames next to each other, starting at frame 0\n and sets the frame number knob of the FrameBlend node\"\"\"\n\n time_warp = nuke.toNode('TimeWarp1')\n time_warp\['lookup'].clearAnimated()\n time_warp\['lookup'].setAnimated()\n anim_list = \[]\n\n for n, frame in enumerate(frame_list):\n anim_list.append(nuke.AnimationKey(n, frame))\n\n anim = time_warp\['lookup'].animation(0)\n anim.addKey(anim_list)\n\n frame_blend = nuke.toNode('FrameBlend1')\n frame_blend\['endframe'].setValue(len(frame_list)-1)\n\n\ndef _generate_sample_list(sample_count, sample_range, sample_radius):\n \"\"\"generate a list of sample values spread equally between the\n min and max values of the sample range\"\"\"\n\n sample_list = \[]\n\n for item in range(0, sample_count):\n sample_list.append(float(item) / sample_count * (sample_range\[1] - sample_range\[0]) + sample_range\[0] + sample_radius)\n\n return sample_list\n\n\ndef _get_sample_range(channel, channel_list, frame_list):\n \"\"\" samples the minimum and maximum values of the given frame range and\n sets the sample range to those values\"\"\"\n\n curve_tool = nuke.toNode('CurveTool_Range')\n min_knob = curve_tool\['minlumapixvalue']\n max_knob = curve_tool\['maxlumapixvalue']\n\n min_knob.setAnimated()\n max_knob.setAnimated()\n\n curve_tool\['channels'].setValue(channel)\n\n nuke.execute(curve_tool, nuke.FrameRanges(frame_list))\n\n index = channel_list.index(channel)\n min_list = \[key.y for key in min_knob.animation(index).keys()]\n max_list = \[key.y for key in max_knob.animation(index).keys()]\n\n min_value = min(min_list)\n max_value = max(max_list)\n\n min_knob.clearAnimated()\n max_knob.clearAnimated()\n curve_tool\['minlumapixdata'].clearAnimated()\n curve_tool\['maxlumapixdata'].clearAnimated()\n\n return \[min_value, max_value]\n\n\ndef _sample_it(keyer, curve_tool, sample, sample_radius):\n \"\"\"analyze the grain level per channel and sample value in the sample range\"\"\"\n\n keyer\['temp_expr0'].setValue(str(sample - sample_radius))\n keyer\['temp_expr1'].setValue(str(sample + sample_radius))\n\n intensity_knob = curve_tool\['intensitydata']\n intensity_knob.clearAnimated()\n intensity_knob.setAnimated()\n\n nuke.execute(curve_tool, nuke.frame(), nuke.frame())\n sample_values = intensity_knob.value()\n intensity_knob.clearAnimated()\n\n return sample_values\n\n\ndef check_inputs(this):\n if this.input(1) is None:\n raise RuntimeError('no plate connected')\n\n if this.input(2) is None:\n raise RuntimeError('no degrained plate connected')\n\n def format_tuple(node):\n return node.format().width(), node.format().height(), node.format().pixelAspect()\n\n if format_tuple(this.input(1)) != format_tuple(this.input(2)):\n raise RuntimeError(\"Format missmatch: Make sure the formats of plate and degrained plate match.\")\n\n\ndef start(this):\n \"\"\"let's do this!\"\"\"\n\n check_inputs(this)\n\n with this:\n frame_list = _generate_frame_list(this)\n _setup_for_multiframe(frame_list)\n sample_count = _sample_count(this)\n\n blank = base64.b64decode('cmVkIHtjdXJ2ZX0KZ3JlZW4ge2N1cnZlfQpibHVlIHtjdXJ2ZX0=').decode('ascii')\n\n lut = nuke.toNode('Sampler1')\['lut']\n lut.fromScript(blank)\n\n channel_list = \['red', 'green', 'blue']\n\n keyer = nuke.toNode('Expression2')\n copy = nuke.toNode('Copy2')\n\n curve_tool = nuke.toNode('CurveTool')\n pixel = curve_tool\['ROI'].value()\[2] * curve_tool\['ROI'].value()\[3]\n\n task = nuke.ProgressTask('Analysing...')\n step = 100.0 / 3 / sample_count\n progress = step\n\n time_warp = nuke.toNode('TimeWarp1')\n frame_blend = nuke.toNode('FrameBlend1')\n\n time_warp\['disable'].setValue(False)\n frame_blend\['disable'].setValue(False)\n\n for channel in channel_list:\n task.setMessage('\{\} range'.format(channel))\n\n copy\['from0'].setValue('rgba.\{\}'.format(channel))\n\n sample_range = _get_sample_range(channel, channel_list, frame_list)\n sample_radius = (sample_range\[1] - sample_range\[0]) / sample_count / 2\n sample_list = _generate_sample_list(sample_count, sample_range, sample_radius)\n\n for sample in sample_list:\n if task.isCancelled():\n return\n\n task.setProgress(int(progress))\n\n sample_values = _sample_it(keyer, curve_tool, sample, sample_radius)\n\n task.setMessage('\{\} channel at \{\}'.format(channel, round(sample, 2)))\n\n if sample_values\[3] * pixel >= 10:\n lut.setValueAt(sample_values\[0] / sample_values\[3], sample_values\[1] / sample_values\[3], channel_list.index(channel))\n\n progress += step\n\n time_warp\['lookup'].clearAnimated()\n time_warp\['disable'].setValue(True) # hopefully prevents slowing down the comp\n frame_blend\['disable'].setValue(True) # hopefully prevents slowing down the comp\n\n del task\n\n\nstart(this)\n" +STARTLINE} addUserKnob {26 divider03 l " "} addUserKnob {41 analysis_mask l "analysis mask" t "Use this channel from the mask input to control what area of the plate will be analyzed.\n\nUsefull if the degrain is obviously bad in some areas." T ChannelMerge1.A} addUserKnob {6 invert_1 l invert -STARTLINE} addUserKnob {20 Adjust_tab l Adjust} addUserKnob {22 whatsthis l "What am I looking at?" T "nuke.message(\"After the analysis you'll see the sampled grain response curves here. On the x-axis is the brightness of the image and on the y-axis the grain intensity. Grain increases with brightness, so the slope of the curves should always be positive (they should always go up ↗).

The quality of the curves depends entirely on the quality of the degrain. If the curves look wrong (for example they go up and down), try to improve the degrain first. If they still look wrong and the resulting regrain doesn't work well enough, you can try to improve the curves here by deleting/correcting all points that don't follow an upwards trend.

You can also extend the curves (again: with an upwards trend) if the comp has values that don't exist in the plate.

Note: The curve is used for both the normalization as well as the adaptation of the grain, so it doesn't give direct control of the grain intensity.\")" +STARTLINE} addUserKnob {41 lut l "" +STARTLINE T Sampler1.lut} addUserKnob {20 Replace_tab l Replace} addUserKnob {6 external_grain l "use external grain" t "Use external grain from a second DasGrain, with the output set to 'normalised grain', to replace masked area.\nConnect it to the 'external grain' input of this DasGrain (it's a bit hidden on the left side of the node)." +STARTLINE} addUserKnob {26 divider04 l Scatter +HIDDEN} addUserKnob {26 divider05 l Scatter T "Make sure you're sampling an area without any plate detail."} addUserKnob {6 scatter l activate t "Activates the scatter function. It generates a new grain based on the plate grain in the sample box using a Voronoi noise." +STARTLINE} scatter true addUserKnob {41 useGPUIfAvailable l "Use GPU if available" -STARTLINE T VoronoiScatter.useGPUIfAvailable} addUserKnob {15 box l "sample box" t "Define an area that is used as a source for the scatter function. The plate grain in this area should be as even as possible, without any visible detail."} box {4780 535 5180 735} addUserKnob {3 sample_frame l "sample frame" t "The frame at which the grain is being sampled. Is set automatically once the sample box is changed." +DISABLED} sample_frame 1264 addUserKnob {4 stereo l "stereo behaviour" t "randomize offset per view: same voronoy pattern for all views, but different offset\n\nrandomize pattern per view: different voronoy pattern for every view" M {none "randomize offset per view" "randomize pattern per view" ""}} addUserKnob {26 spacer06 l "" +STARTLINE T " "} addUserKnob {6 overlay l "overlay cell pattern" t "Overlay the cell pattern of the voronoy noise. Useful to check where the seams are and if distortion or blending is necessary." +STARTLINE} addUserKnob {7 cell_size l "cell size" t "Cell size of the scatter. Shoudn't be too small, as lower grain frequencies might break.\nCan't be too big either, to prevent it from breaking the border of the samplebox (will error if it does)." R 5 100} cell_size 40 addUserKnob {26 spacer07 l "" +STARTLINE T " "} addUserKnob {20 concealer l "edge concealer" n 1} concealer 0 addUserKnob {26 concealer_help l " " T "If you can see the voronoi pattern in the grain QC output,\nincrease the edge blend size."} addUserKnob {3 edge_blend_size l "edge blend size" t "Set the output to grain QC. If you see the cell seams, increase the edge blend size to conceal them.\n\nThis is a bit hacky and slow."} addUserKnob {26 tip l "" -STARTLINE T "sloooow - keep this below 3 if possible"} addUserKnob {26 distortion_help l " " T "\nDistortion might help as well, if somehow the straight\nseams are visible (you might want to toggle the overlay\nwhile adjusting)."} addUserKnob {7 amplitude R 0 50} addUserKnob {7 frequency R 0 50} frequency 15 addUserKnob {20 endGroup n -1} addUserKnob {26 divider06 l "" +STARTLINE} addUserKnob {41 replace_mask l "replace mask" t "Use this channel from the mask input to specify where you want to use scattered grain instead of the adapted plate grain." -STARTLINE T Merge9.maskChannelMask} addUserKnob {41 invert_mask_1 l invert -STARTLINE T Merge9.invert_mask} addUserKnob {20 GrainGroupEnd l "" +STARTLINE n -3} addUserKnob {20 Help_tab l Help} addUserKnob {26 basic_setup l "" +STARTLINE T "Basic setup"} addUserKnob {26 ""} addUserKnob {26 explanation l "" +STARTLINE T "Bold steps are always necessary"} addUserKnob {26 steps l "" +STARTLINE T "
1. This should be the only regrain node in your comp.
2. Connect plate, degrained plate and comp.
    The comp should be done on the degrained plate!

3. Set the luminance degrain amount.
4. Press the Analyze button.
5. Correct the response curves in the Adjust tab.
6. Move the sample box to an area without any plate detail and activate scatter.
7. If necessary, activate edge blend and/or distortion to conceal seams."} addUserKnob {26 in_depth l "" +STARTLINE T "
For an in depth explanation of the steps, read the tooltips and check out this video:
https://vimeo.com/284820390"} addUserKnob {26 pushthebutton l "" +STARTLINE T "

If the result is not as expected and you don't know why, push this button:"} addUserKnob {22 troubleshoot l Troubleshoot t HEEEEEEELP T "import base64\n\nmessages = \[]\n\nthis = nuke.thisNode()\n\n#########################\n\nif this.input(0) is None or this.input(1) is None or this.input(2) is None:\n messages.append(\"ERROR Plate, degrained plate and comp need to be connected to the appropriate inputs.\")\n\n#########################\n\nelse:\n\n def format_to_tuple(g):\n \"\"\"returns (1024, 786, 2.0)\n \"\"\"\n return (g.format().width(), g.format().height(), g.format().pixelAspect())\n\n format_set = set(\[\n format_to_tuple(this.input(0)),\n format_to_tuple(this.input(1)),\n format_to_tuple(this.input(2)),\n ])\n if len(format_set) != 1:\n messages.append(\"WARNING Format missmatch: Make sure formats of plate, degrained plate and comp match.\")\n\n if (this.input(1).firstFrame() != this.input(2).firstFrame()) or (this.input(1).lastFrame() != this.input(2).lastFrame()):\n messages.append(\"WARNING The frame ranges of plate and degrained plate don't match. Double check that they belong together.\")\n\n#########################\n\nmessages.append(\"Double check that plate and degrained plate haven't been modified in any way (paint, despill, etc).\")\n\n#########################\n\nif this\['luminance'].getValue() == 1:\n messages.append(\"Are you working on a completely degrained plate? If not, you might have to set the luminance degrain amount.\")\n\n#########################\n\nblank = base64.b64decode('cmVkIHtjdXJ2ZX0KZ3JlZW4ge2N1cnZlfQpibHVlIHtjdXJ2ZX0=').decode('ascii')\n\nwith this:\n Sampler = nuke.toNode('Sampler1') \n if Sampler\['lut'].toScript() == blank:\n messages.append(\"ERROR You haven't pressed the Analyze button yet!\")\n\n#########################\n\nclass BadThings(Exception): pass\n\ndef thingy():\n with this:\n Sampler = nuke.toNode('Sampler1')\n list = this\['lut'].toScript().replace('\}','').split('\\n')\n for item in list:\n sample_value = 0\n for value in item.split(' '):\n try:\n value == float(value)\n if value < sample_value:\n raise BadThings(\"WARNING Check and fix the response curves. Their slopes should always be positive (the curves should always go up ↗).\")\n \n else:\n sample_value = value\n except ValueError:\n # Ignore non-numeric things like x-values of \"x5.46\" and channel names like \"red\{\" etc\n pass\ntry:\n thingy()\nexcept BadThings as e:\n messages.append(str(e))\n \n#########################\n\nif this\['scatter'].value() == True:\n if this\['box'].getValue() == \[100.0, 100.0, 500.0, 300.0]:\n messages.append(\"WARNING Scatter has been activated, but the sample box is still in its default position. Are you sure that's a good area to sample?\")\n\n#########################\n\nmessages.append(\"Did you copy/paste DasGrain from another script? Make sure to reanalyze and to reset the sample area if you are using scatter.\")\n\n#########################\n\nif len(messages) > 0:\n nuke.message(\"Things worth checking

\"\n \"%s


If any of this doesn't make sense to you, it might be worth checking out the video on vimeo.\" % (\n \"
\".join(\"%s: %s\" % (i+1, m) for i, m in enumerate(messages))))\n" +STARTLINE} addUserKnob {26 dont_despair l "" +STARTLINE T "
If it still doesn't work and you're about to flip the table, send me a mail.
I'm happy to help! :)"} addUserKnob {20 Info_tab l Info} addUserKnob {26 dasname l "" +STARTLINE T "DasGrain v1.8
"} addUserKnob {26 text_1 l "" +STARTLINE T "DasGrain makes regraining as simple as clicking a few buttons.
Follow the steps in the Help tab and you'll have a perfect\nregrain
in no time!"} addUserKnob {26 ""} addUserKnob {26 info l "" +STARTLINE T "Last change: 2021-03-07\n\n"} addUserKnob {26 name_1 l "" +STARTLINE T "Fabian Holtz"} addUserKnob {26 mail l "" +STARTLINE T "holtzf+nuke@gmail.com"} addUserKnob {26 testimonial l "" +STARTLINE T "


«Your gizmo is beyond expectation»
— anonymous

"} addUserKnob {26 ""} addUserKnob {26 credit l "" +STARTLINE T "
VoronoiScatter based on Ivan Busquets' implementation of
libNoise's\nVoronoi generator"} addUserKnob {26 thanks l "" +STARTLINE T "
Special thanks to Ben Dickson for bearing with my questions and
problems and RSP comp for the valuable feedback."} } BackdropNode { inputs 0 name BackdropNode1 tile_color 0x7f7f7fff label "normalise grain" note_font_size 30 xpos 170 ypos 1662 bdwidth 320 bdheight 110 } BackdropNode { inputs 0 name BackdropNode11 tile_color 0x7f7f7fff label "add grain" note_font_size 30 xpos 830 ypos 2766 bdwidth 320 bdheight 110 } BackdropNode { inputs 0 name BackdropNode13 tile_color 0x7f7f7fff label scatter note_font_size 30 xpos -50 ypos 2022 bdwidth 320 bdheight 110 } BackdropNode { inputs 0 name BackdropNode14 tile_color 0x7f7f7fff label "analyze grain" note_font_size 30 xpos -159 ypos 606 bdwidth 319 bdheight 877 } BackdropNode { inputs 0 name BackdropNode2 tile_color 0x7f7f7fff label "grain response curve" note_font_size 30 xpos 610 ypos 2574 bdwidth 320 bdheight 110 } BackdropNode { inputs 0 name BackdropNode3 tile_color 0x7f7f7fff label QC note_font_size 30 xpos 1050 ypos 3222 bdwidth 320 bdheight 110 } BackdropNode { inputs 0 name BackdropNode4 tile_color 0x7f7f7fff label "grain response curve" note_font_size 30 xpos 610 ypos 1422 bdwidth 320 bdheight 110 } BackdropNode { inputs 0 name BackdropNode5 tile_color 0x7f7f7fff label "adapt grain" note_font_size 30 xpos 170 ypos 2574 bdwidth 320 bdheight 110 } BackdropNode { inputs 0 name BackdropNode6 tile_color 0x7f7f7fff label "sample range" note_font_size 30 xpos -490 ypos 606 bdwidth 320 bdheight 110 } BackdropNode { inputs 0 name BackdropNode7 tile_color 0x7f7f7fff label "luminance level" note_font_size 30 xpos 280 ypos -282 bdwidth 760 bdheight 685 } BackdropNode { inputs 0 name BackdropNode8 tile_color 0x7f7f7fff label "plate grain" note_font_size 30 xpos 170 ypos 606 bdwidth 320 bdheight 110 } BackdropNode { inputs 0 name BackdropNode9 tile_color 0x7f7f7fff label replace note_font_size 30 xpos 60 ypos 2191 bdwidth 540 bdheight 226 } Input { inputs 0 name DEGRAINED_PLATE label "\[value number]" note_font_size 30 xpos 730 ypos -896 number 2 } OCIOColorSpace { in_colorspace {{OCIOColorSpace1.in_colorspace}} out_colorspace {{OCIOColorSpace1.out_colorspace}} name OCIOColorSpace2 xpos 730 ypos -490 } Dot { name Dot9 xpos 764 ypos -390 } set N311f3000 [stack 0] Dot { name Dot28 xpos 764 ypos -198 } set N311f2c00 [stack 0] Dot { name Dot32 xpos 764 ypos 234 } set N311f2800 [stack 0] push $N311f2c00 Dot { name Dot27 xpos 624 ypos -198 } Colorspace { colorspace_out YCbCr name Colorspace1 xpos 590 ypos -130 } Dot { name Dot7 xpos 624 ypos -54 } set N311f1c00 [stack 0] Input { inputs 0 name PLATE label "\[value number]" note_font_size 30 xpos 290 ypos -892 number 1 } Dot { name Dot50 xpos 324 ypos -726 } set N311f1400 [stack 0] OCIOColorSpace { in_colorspace scene_linear out_colorspace scene_linear name OCIOColorSpace1 xpos 290 ypos -490 } Dot { name Dot29 xpos 324 ypos -198 } set N311f0800 [stack 0] Dot { name Dot6 xpos 464 ypos -198 } Colorspace { colorspace_out YCbCr name Colorspace2 xpos 430 ypos -130 } Merge2 { inputs 2 operation from bbox B Achannels rgb Bchannels rgb output rgb name Merge4 xpos 430 ypos -58 } Multiply { channels rgb value {{"1 / parent.luminance - 1"} 0 0 0} name Multiply6 xpos 430 ypos 14 } Dot { name Dot31 xpos 464 ypos 90 } push $N311f1c00 Merge2 { inputs 2 operation plus bbox B Achannels rgb Bchannels rgb output rgb name Merge5 xpos 590 ypos 86 } Colorspace { colorspace_in YCbCr name Colorspace3 xpos 590 ypos 158 } Merge2 { inputs 2 operation from bbox B Achannels rgb Bchannels rgb output rgb name Merge6 xpos 590 ypos 230 } Dot { name Dot35 xpos 624 ypos 306 } set N315b2000 [stack 0] push $N311f2800 Merge2 { inputs 2 operation from bbox B Achannels rgb Bchannels rgb output rgb name Merge7 xpos 730 ypos 302 disable {{"Multiply6.value.r == 0"}} } Dot { name Dot2 xpos 764 ypos 522 } set N315b1800 [stack 0] Dot { name Dot30 xpos 764 ypos 690 } set N315b1400 [stack 0] Dot { name Dot55 xpos 764 ypos 1170 } set N315b1000 [stack 0] Input { inputs 0 name mask label "\[value number]" note_font_size 30 xpos 1170 ypos -896 number 3 } Dot { name Dot39 xpos 1204 ypos 258 } set N315b0800 [stack 0] Dot { name Dot26 xpos 1204 ypos 1074 } set N315b0400 [stack 0] Invert { name Invert2 xpos 180 ypos 1064 disable {{!parent.invert_1}} } push $N315b1400 push $N311f0800 Merge2 { inputs 2 operation from bbox B Achannels rgb Bchannels rgb output rgb name Merge27 xpos 290 ypos 686 } Dot { name Dot3 xpos 324 ypos 786 } set N31563400 [stack 0] Dot { name Dot5 xpos 104 ypos 786 } set N31563000 [stack 0] push $N31563000 Copy { inputs 2 from0 {{{parent.Copy2.from0}}} to0 rgba.red name Copy3 xpos 70 ypos 848 } Expression { expr0 abs(r) channel1 {none none none rgba.alpha} expr1 "r == 0" channel2 none channel3 none name Expression4 xpos 70 ypos 926 } set N31562800 [stack 0] push $N315b1800 Colorspace { colorspace_out AlexaV3LogC name Colorspace5 xpos 70 ypos 518 } Clamp { maximum_enable false name Clamp2 xpos -40 ypos 512 } Dot { name Dot1 xpos -116 ypos 522 } set N31561c00 [stack 0] Dot { name Dot48 xpos -116 ypos 786 } set N31561800 [stack 0] push $N31561800 Copy { inputs 2 from0 rgba.blue to0 rgba.red name Copy2 xpos -150 ypos 848 } Expression { temp_name0 min temp_expr0 0.870827682503 temp_name1 max temp_expr1 0.915022015572 channel0 {none none none rgba.alpha} expr0 "r >= min && r <= max" channel1 none channel2 none channel3 none name Expression2 xpos -150 ypos 926 } Dot { name Dot4 xpos -116 ypos 1002 } ChannelMerge { inputs 2 operation stencil name ChannelMerge2 xpos -40 ypos 985 } push $N31562800 Copy { inputs 2 from0 rgba.alpha to0 rgba.alpha name Copy1 xpos 70 ypos 992 } ChannelMerge { inputs 2 A -rgba.green operation multiply name ChannelMerge1 xpos 70 ypos 1057 disable {{!A}} } Copy { inputs 2 from0 {{{parent.Copy2.from0}}} to0 rgba.green name Copy4 xpos 70 ypos 1160 } Premult { channels {rgba.red rgba.green -rgba.blue none} name Premult1 xpos 70 ypos 1238 } TimeWarp { lookup 1282 time "" filter nearest name TimeWarp1 xpos 70 ypos 1286 disable true } FrameBlend { channels {rgba.red rgba.green -rgba.blue rgba.alpha} startframe 0 endframe 9 userange true name FrameBlend1 xpos 70 ypos 1352 disable true } CurveTool { avgframes 0 channels {rgba.red rgba.green -rgba.blue rgba.alpha} ROI {0 0 {width} {height}} intensitydata {1.377529588e-08 1.821526818e-05 0 8.477105161e-07} name CurveTool xpos 70 ypos 1424 } push $N31561c00 Dot { name Dot16 xpos -336 ypos 522 } CurveTool { operation "Max Luma Pixel" channels {-rgba.red -rgba.green rgba.blue none} ROI {0 0 {width} {height}} maxlumapixdata {3583 1607} maxlumapixvalue {0 0 0.9149547815} minlumapixdata {8181 4280} minlumapixvalue {0 0 0.04878564551} name CurveTool_Range xpos -370 ypos 680 } Sampler { inputs 0 lut {red {curve x-0.00444662571 0.0005336523044 x0.003430385143 0.001032399774 x0.009597890079 0.001540798527 x0.01934378967 0.001953001073 x0.03391108289 0.002407587012 x0.05598417297 0.002831411211 x0.08963386714 0.00343182193 x0.1394716948 0.004241312591 x0.2149234116 0.005314255281 x0.3250966072 0.006701008596 x0.4888586402 0.008172613639 x0.7335344553 0.009848375423 x1.11005497 0.01008086635 x1.701566815 0.008992578788 x2.646425962 0.009265765656 x4.036708832 0.009687656155 x5.492133141 0.01050298669 x8.152188301 0.0192988078 x11.72720051 0.01752164016 x21.50120926 0.01643145163} green {curve x0.003520222381 0.0007075626385 x0.009994961321 0.001028803947 x0.01975484937 0.001473176377 x0.03445784375 0.001966089148 x0.05696836114 0.002595094962 x0.09107580781 0.00336301043 x0.1408977509 0.004326815753 x0.2164624482 0.005534744733 x0.3274065852 0.006973312038 x0.4927251339 0.008406514002 x0.736143589 0.009497122935 x1.108921885 0.008970127151 x1.718840003 0.008136171695 x2.667378187 0.009124653373 x3.955183268 0.008538980774 x5.567311287 0.01406942011 x8.046829224 0.02077973272 x11.73814678 0.01512256956 x21.51974297 0.01604729729} blue {curve x0.003330381121 0.0007775118259 x0.009459697641 0.001090836832 x0.01904519834 0.00149636536 x0.03374376148 0.00193711811 x0.05587526038 0.002422839577 x0.08960115165 0.003098600559 x0.1388557255 0.003950498538 x0.2129787505 0.005042325301 x0.3237577379 0.006425091251 x0.4854558408 0.007870417854 x0.7260692716 0.009051722286 x1.104099035 0.008214167103 x1.722133636 0.007147452339 x2.677326918 0.00797233901 x3.762497425 0.007413420124 x5.684577465 0.0157589611 x7.976866722 0.01787855378 x11.73128223 0.01526775811 x21.48760414 0.01624999999}} name Sampler1 onCreate "n = nuke.thisNode()\nn\['sampler'].setEnabled(False)" knobChanged "n = nuke.thisNode()\nk = nuke.thisKnob()\np = nuke.thisParent()\n\nif k.name() == 'lut':\n with p:\n for c in \['ColorLookup1','ColorLookup2']:\n nuke.toNode(c)\['lut'].fromScript(k.toScript())" xpos 840 ypos 1502 } push $N311f1400 Dot { name Dot51 xpos 115 ypos -726 } Input { inputs 0 name COMP label "\[value number]" note_font_size 30 xpos 950 ypos -896 } Dot { name Dot49 xpos 984 ypos -605 } set N314f9000 [stack 0] Switch { inputs 2 which {{parent.meta}} name Switch1 xpos 81 ypos -609 } Dot { name Dot54 xpos 115 ypos -486 } Dot { name Dot52 xpos -685 ypos -486 } Dot { name Dot53 xpos -685 ypos 3762 } push $N315b0800 Dot { name Dot40 xpos 874 ypos 258 } push $N315b2000 Dot { name Dot34 xpos 624 ypos 378 } Multiply { inputs 1+1 channels rgb value 0 maskChannelMask -rgba.red name Multiply1 xpos 840 ypos 374 } push $N314f9000 OCIOColorSpace { in_colorspace {{OCIOColorSpace1.in_colorspace}} out_colorspace {{OCIOColorSpace1.out_colorspace}} name OCIOColorSpace3 xpos 950 ypos -490 } Dot { name Dot44 xpos 984 ypos -390 } set N32a66400 [stack 0] Merge2 { inputs 2 operation from bbox B Achannels rgb Bchannels rgb output rgb name Merge8 xpos 950 ypos 374 disable {{"Multiply6.value.r == 0"}} } Dot { name Dot18 xpos 984 ypos 2658 } set N32a65c00 [stack 0] ColorLookup { lut {master {} red {curve x-0.00444662571 0.0005336523044 x0.003430385143 0.001032399774 x0.009597890079 0.001540798527 x0.01934378967 0.001953001073 x0.03391108289 0.002407587012 x0.05598417297 0.002831411211 x0.08963386714 0.00343182193 x0.1394716948 0.004241312591 x0.2149234116 0.005314255281 x0.3250966072 0.006701008596 x0.4888586402 0.008172613639 x0.7335344553 0.009848375423 x1.11005497 0.01008086635 x1.701566815 0.008992578788 x2.646425962 0.009265765656 x4.036708832 0.009687656155 x5.492133141 0.01050298669 x8.152188301 0.0192988078 x11.72720051 0.01752164016 x21.50120926 0.01643145163} green {curve x0.003520222381 0.0007075626385 x0.009994961321 0.001028803947 x0.01975484937 0.001473176377 x0.03445784375 0.001966089148 x0.05696836114 0.002595094962 x0.09107580781 0.00336301043 x0.1408977509 0.004326815753 x0.2164624482 0.005534744733 x0.3274065852 0.006973312038 x0.4927251339 0.008406514002 x0.736143589 0.009497122935 x1.108921885 0.008970127151 x1.718840003 0.008136171695 x2.667378187 0.009124653373 x3.955183268 0.008538980774 x5.567311287 0.01406942011 x8.046829224 0.02077973272 x11.73814678 0.01512256956 x21.51974297 0.01604729729} blue {curve x0.003330381121 0.0007775118259 x0.009459697641 0.001090836832 x0.01904519834 0.00149636536 x0.03374376148 0.00193711811 x0.05587526038 0.002422839577 x0.08960115165 0.003098600559 x0.1388557255 0.003950498538 x0.2129787505 0.005042325301 x0.3237577379 0.006425091251 x0.4854558408 0.007870417854 x0.7260692716 0.009051722286 x1.104099035 0.008214167103 x1.722133636 0.007147452339 x2.677326918 0.00797233901 x3.762497425 0.007413420124 x5.684577465 0.0157589611 x7.976866722 0.01787855378 x11.73128223 0.01526775811 x21.48760414 0.01624999999} alpha {}} name ColorLookup2 xpos 730 ypos 2654 } push $N315b0400 Dot { name Dot38 xpos 1204 ypos 1842 } Dot { name Dot37 xpos 544 ypos 1842 } Dot { name Dot22 xpos 544 ypos 2271 } set N32a64c00 [stack 0] Dot { name Dot20 xpos 544 ypos 2391 } push $N32a64c00 Dot { name Dot17 xpos 434 ypos 2271 } set N32a64400 [stack 0] Dot { name Dot13 xpos 214 ypos 2271 } Input { inputs 0 name external_grain label "\[value number]" note_font_size 30 xpos -150 ypos 1716 number 4 } Dot { name Dot21 xpos -116 ypos 1938 } push $N315b1000 ColorLookup { channels rgb lut {master {} red {curve x-0.00444662571 0.0005336523044 x0.003430385143 0.001032399774 x0.009597890079 0.001540798527 x0.01934378967 0.001953001073 x0.03391108289 0.002407587012 x0.05598417297 0.002831411211 x0.08963386714 0.00343182193 x0.1394716948 0.004241312591 x0.2149234116 0.005314255281 x0.3250966072 0.006701008596 x0.4888586402 0.008172613639 x0.7335344553 0.009848375423 x1.11005497 0.01008086635 x1.701566815 0.008992578788 x2.646425962 0.009265765656 x4.036708832 0.009687656155 x5.492133141 0.01050298669 x8.152188301 0.0192988078 x11.72720051 0.01752164016 x21.50120926 0.01643145163} green {curve x0.003520222381 0.0007075626385 x0.009994961321 0.001028803947 x0.01975484937 0.001473176377 x0.03445784375 0.001966089148 x0.05696836114 0.002595094962 x0.09107580781 0.00336301043 x0.1408977509 0.004326815753 x0.2164624482 0.005534744733 x0.3274065852 0.006973312038 x0.4927251339 0.008406514002 x0.736143589 0.009497122935 x1.108921885 0.008970127151 x1.718840003 0.008136171695 x2.667378187 0.009124653373 x3.955183268 0.008538980774 x5.567311287 0.01406942011 x8.046829224 0.02077973272 x11.73814678 0.01512256956 x21.51974297 0.01604729729} blue {curve x0.003330381121 0.0007775118259 x0.009459697641 0.001090836832 x0.01904519834 0.00149636536 x0.03374376148 0.00193711811 x0.05587526038 0.002422839577 x0.08960115165 0.003098600559 x0.1388557255 0.003950498538 x0.2129787505 0.005042325301 x0.3237577379 0.006425091251 x0.4854558408 0.007870417854 x0.7260692716 0.009051722286 x1.104099035 0.008214167103 x1.722133636 0.007147452339 x2.677326918 0.00797233901 x3.762497425 0.007413420124 x5.684577465 0.0157589611 x7.976866722 0.01787855378 x11.73128223 0.01526775811 x21.48760414 0.01624999999} alpha {}} name ColorLookup1 xpos 730 ypos 1502 } Dot { name Dot24 xpos 764 ypos 1746 } push $N31563400 Dot { name Dot33 xpos 324 ypos 1386 } MergeExpression { inputs 2 temp_name0 target temp_expr0 .01 expr0 "Br * (target / Ar)" expr1 "Bg * (target / Ag)" expr2 "Bb * (target / Ab)" channel3 none name MergeExpression1 xpos 290 ypos 1742 } Dot { name Dot15 xpos 324 ypos 1842 } set N32a2a000 [stack 0] Dot { name Dot25 xpos 104 ypos 1842 } Switch { inputs 2 which {{parent.external_grain}} name Switch2 xpos 70 ypos 1934 } Group { name VoronoiScatter xpos 70 ypos 2102 disable {{!parent.scatter}} addUserKnob {20 User} addUserKnob {41 useGPUIfAvailable l "Use GPU if available" T VoroNoise.useGPUIfAvailable} addUserKnob {41 vectorize l "Vectorize on CPU" -STARTLINE T VoroNoise.vectorize} addUserKnob {15 box} box {{parent.box x1004 0 x1036 -75} {parent.box x1004 100 x1036 120} {parent.box x1004 496 x1036 325} {parent.box x1004 916 x1036 320}} addUserKnob {3 sample_frame l "sample frame"} sample_frame {{parent.sample_frame}} addUserKnob {7 cell_size l "cell size" R 0 100} cell_size {{parent.cell_size}} addUserKnob {6 overlay_pattern l "overlay pattern" -STARTLINE} overlay_pattern {{parent.overlay}} addUserKnob {3 edge_blend_size l "edge blend size"} edge_blend_size {{parent.edge_blend_size}} addUserKnob {7 amplitude R 0 100} amplitude {{parent.amplitude}} addUserKnob {7 frequency R 0 100} frequency {{parent.frequency}} addUserKnob {41 VoroNoise_Seed l Seed T VoroNoise.VoroNoise_Seed} } Input { inputs 0 name Input1 xpos 180 ypos -879 } Dot { name Dot14 xpos 214 ypos -750 } set N32a29000 [stack 0] Dot { name Dot16 xpos 434 ypos -750 } Remove { name Remove1 xpos 400 ypos -687 } Dot { name Dot6 xpos 434 ypos -606 } set N32a28400 [stack 0] Dot { name Dot15 xpos 654 ypos -606 } set N329e3c00 [stack 0] Dot { name Dot7 xpos 874 ypos -606 } Noise { output {rgba.red -rgba.green -rgba.blue none} replace true size {{parent.frequency} {"parent.frequency * pixel_aspect"}} zoffset {{"x + 1000"}} gamma 1 name Noise1 xpos 840 ypos -514 } Noise { output {-rgba.red rgba.green -rgba.blue none} replace true size {{parent.Noise1.size} {parent.Noise1.size}} zoffset {{x}} gamma 1 name Noise2 xpos 840 ypos -466 } Clamp { name Clamp1 xpos 840 ypos -424 } Dot { name Dot11 xpos 874 ypos -366 } push $N329e3c00 BlinkScript { ProgramGroup 1 KernelDescription "2 \"VoroNoise\" iterate pixelWise c117be128a07c11b6d82fd34148d66b3bcac41976ec9c2082affe38e890c2c0f 2 \"src\" Read Point \"dst\" Write Point 6 \"Frequency\" Float 1 AABIQg== \"Seed\" Int 1 AAAAAA== \"aspect ratio\" Float 1 AACAPw== \"width\" Int 1 AAAAAA== \"height\" Int 1 AAAAAA== \"Randomness\" Float 1 AAAAPw== 6 \"frequency\" 1 1 \"seed\" 1 1 \"aspect_ratio\" 1 1 \"width\" 1 1 \"height\" 1 1 \"randomness\" 1 1 0" kernelSource "// Voronoi.blink\n// A test implementation of libNoise's Voronoi generator using Blink\n// Ivan Busquets - August 2013\n// Modified for DasGrain by Fabian Holtz - April 2019\n\n#define X_NOISE_GEN 1619\n#define Y_NOISE_GEN 31337\n#define Z_NOISE_GEN 6971\n#define SEED_NOISE_GEN 1013\n#define SQRT_3 1.73205081\n\ninline int IntValueNoise3D (int x, int y, int z, int seed)\n\{\n // All constants are primes and must remain prime in order for this noise\n // function to work correctly.\n int n = (\n X_NOISE_GEN * x\n + Y_NOISE_GEN * y\n + Z_NOISE_GEN * z\n + SEED_NOISE_GEN * seed)\n & 0x7fffffff;\n n = (n >> 13) ^ n;\n return (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;\n\}\n\ninline float ValueNoise3D (int x, int y, int z, int seed)\n\{\n return 1.0 - ((float)IntValueNoise3D (x, y, z, seed) / 1073741824.0);\n\}\n\nkernel VoroNoise : ImageComputationKernel\n\{\n Image src;\n Image dst;\n\nparam:\n float frequency;\n int seed;\n float aspect_ratio;\n int width;\n int height;\n float randomness;\n\n\n void define() \{\n defineParam(frequency, \"Frequency\", 50.0f);\n defineParam(aspect_ratio, \"aspect ratio\", 1.0f);\n defineParam(seed, \"Seed\", 0);\n defineParam(randomness, \"Randomness\", 0.5f);\n \}\n\n\n\n\n void process(int2 pos) \{\n float x = pos.x * aspect_ratio * frequency / width;\n float y = pos.y * frequency / width;\n int xInt = (x > 0.0) ? x : x - 1;\n int yInt = (y > 0.0) ? y : y - 1;\n\n\n float minDist = 2147483647.0;\n float xCandidate = 0;\n float yCandidate = 0;\n\n float dist;\n\nfor (int yCur = yInt - 2; yCur <= yInt + 2; yCur++) \{\n for (int xCur = xInt - 2; xCur <= xInt + 2; xCur++) \{\n\n // Calculate the position and distance to the seed point inside of\n // this unit cube. Limited by the randomness value\n float xPos = xCur + (ValueNoise3D (xCur, yCur, 0, seed ) + 1 ) * randomness + (1-randomness) - 1;\n float yPos = yCur + (ValueNoise3D (xCur, yCur, 0, seed + 1) + 1 ) * randomness + (1-randomness) - 1;\n\n float xDist = xPos - x;\n float yDist = yPos - y;\n\n dist = pow(xDist, 2) + pow(yDist, 2);\n if (dist < minDist) \{\n // This seed point is closer to any others found so far, so record\n // this seed point.\n minDist = dist;\n xCandidate = xPos;\n yCandidate = yPos;\n\t\}\n \}\n\}\n\n SampleType(dst) sample(0.0f);\n\n sample.x = xCandidate / aspect_ratio / frequency;\n sample.y = yCandidate / height * width / frequency;\n sample.z = 0;\n\n dst() = sample;\n\}\n\};" rebuild "" VoroNoise_Frequency {{"width / parent.cell_size"}} VoroNoise_Seed {{"(x + (parent.parent.stereo == 2 ? \[lsearch \[value root.views] \[view]] / 2 : 0)) * 5"}} "VoroNoise_aspect ratio" {{pixel_aspect}} VoroNoise_width {{width}} VoroNoise_height {{height}} rebuild_finalise "" name VoroNoise xpos 620 ypos -520 } Copy { inputs 2 from0 rgba.red to0 forward.u from1 rgba.green to1 forward.v name Copy1 xpos 620 ypos -382 disable {{"parent.amplitude == 0"}} } IDistort { uv forward uv_offset 0.5 uv_scale {{parent.amplitude} {"uv_scale.w * pixel_aspect"}} filter impulse name IDistort1 xpos 620 ypos -280 disable {{"parent.amplitude == 0"}} } Dot { name Dot5 xpos 654 ypos -246 } NoTimeBlur { rounding floor name NoTimeBlur3 xpos 620 ypos -154 } Transform { translate {{"floor((x * size) % 1 * (size)) - int(size / 2)"} {"floor(x % 1 * (size)) - int(size/2)"}} filter impulse black_outside false name Transform1 xpos 620 ypos -58 disable {{"parent.edge_blend_size < 1"}} addUserKnob {20 User} addUserKnob {3 size} size {{"parent.edge_blend_size + 1"}} } Dot { name Dot9 xpos 654 ypos 42 } set N329e0c00 [stack 0] push $N32a28400 Expression { expr0 "(x + .5) / width" expr1 "(y + .5) / height" expr2 0 name STMapGenerator xpos 400 ypos -514 } NoTimeBlur { rounding floor name NoTimeBlur2 xpos 400 ypos -154 } Merge2 { inputs 2 operation from Achannels {rgba.red rgba.green -rgba.blue none} Bchannels {rgba.red rgba.green -rgba.blue none} output {rgba.red rgba.green -rgba.blue none} name Merge2 xpos 400 ypos 38 } Dot { name Dot10 xpos 434 ypos 210 } push $N329e0c00 Expression { temp_name0 view_index temp_expr0 "parent.parent.stereo == 1 ? \[lsearch \[value root.views] \[view]] / 2 : 0" expr0 "random((r + view_index) * 1000000, 0) * (maxx - minx) + minx" expr1 "random((g + view_index) * 1000000, 0) * (maxy - miny) + miny" channel2 none channel3 none name Expression3 xpos 620 ypos 110 addUserKnob {20 User} addUserKnob {7 frequency R 0 100} frequency {{parent.parent.cell_size}} addUserKnob {7 multiplier R 0 3} multiplier 0.5 addUserKnob {15 shrink} shrink {{"frequency * multiplier + ceil(parent.edge_blend_size / 2) + IDistort1.uv_scale.w / 2"} {"frequency * multiplier + ceil(parent.edge_blend_size / 2) + IDistort1.uv_scale.h / 2"} {"frequency * multiplier + floor(parent.edge_blend_size / 2) + IDistort1.uv_scale.w / 2"} {"frequency * multiplier + floor(parent.edge_blend_size / 2) + IDistort1.uv_scale.h / 2"}} addUserKnob {26 ""} addUserKnob {7 minx} minx {{"(parent.box.x + shrink.x + .5) / width"}} addUserKnob {7 maxx} maxx {{"(parent.box.r - shrink.r - .5) / width"}} addUserKnob {7 miny} miny {{"(parent.box.y + shrink.y + .5) / height"}} addUserKnob {7 maxy} maxy {{"(parent.box.t - shrink.t - .5) / height"}} } Merge2 { inputs 2 operation plus Achannels {rgba.red rgba.green -rgba.blue none} Bchannels {rgba.red rgba.green -rgba.blue none} output {rgba.red rgba.green -rgba.blue none} name Merge3 xpos 620 ypos 206 } Expression { expr0 "(r + (maxx - minx) - minx) % (maxx - minx) + minx" expr1 "(g + (maxy - miny) - miny) % (maxy - miny) + miny" channel2 none channel3 none name Expression7 xpos 620 ypos 278 addUserKnob {20 User} addUserKnob {7 minx} minx {{"(parent.box.x + rint(x % 1 * parent.edge_blend_size) + .5) / width"}} addUserKnob {7 maxx} maxx {{"(parent.box.r + rint(x % 1 * parent.edge_blend_size) - .5) / width"}} addUserKnob {7 miny} miny {{"(parent.box.y + rint(x % 1 * parent.edge_blend_size) + .5) / height"}} addUserKnob {7 maxy} maxy {{"(parent.box.t + rint(x % 1 * parent.edge_blend_size) - .5) / height"}} } Dot { name Dot3 xpos 654 ypos 354 } set N32972800 [stack 0] Dot { name Dot13 xpos 654 ypos 546 } push $N32972800 Dot { name Dot8 xpos 874 ypos 354 } Blur { channels rgb size {{pixel_aspect} 1} name Blur1 label "\[value size]" xpos 840 ypos 440 } Difference { inputs 2 name Difference2 xpos 840 ypos 536 } Expression { channel0 {none none none rgba.alpha} expr0 "a > 1e-9" channel1 none channel2 none channel3 none name Expression2 xpos 840 ypos 614 } Shuffle { red alpha green alpha blue alpha name Shuffle1 label "\[value in]:\[value out]" xpos 840 ypos 680 } Dot { name Dot4 xpos 874 ypos 762 } push $N32972800 push $N32a29000 FrameHold { first_frame {{parent.sample_frame}} name FrameHold1 xpos 180 ypos -256 } NoTimeBlur { rounding floor name NoTimeBlur1 xpos 180 ypos -154 } STMap { inputs 2 channels rgb uv rgb filter impulse name STMap1 xpos 180 ypos 350 } set N32970400 [stack 0] TimeBlur { divisions {{"max(Transform1.size == 1 ? 2 : pow2(Transform1.size), 1)"}} shutter 1 shuttercustomoffset {{"1 / divisions / 2"}} name TimeBlur1 xpos 180 ypos 446 disable {{"parent.edge_blend_size < 1"}} } set N32907c00 [stack 0] push $N32970400 Dot { name Dot1 xpos -6 ypos 354 } Difference { inputs 2 name Difference1 xpos -40 ypos 440 } Expression { channel0 {none none none rgba.alpha} expr0 "a > 1e-10" channel1 none channel2 none channel3 none name Expression1 xpos -40 ypos 494 } Blur { channels alpha size {{parent.parent.edge_blend_size}} name Blur2 xpos -40 ypos 536 } Grade { channels alpha blackpoint 0.5 white_clamp true name Grade2 xpos -40 ypos 584 } Dot { name Dot2 xpos -6 ypos 666 } push $N32907c00 Grade { inputs 1+1 white 1.4 black_clamp false name Grade1 xpos 180 ypos 662 disable {{"parent.edge_blend_size < 1"}} } Merge2 { inputs 2 Achannels rgb Bchannels rgb output rgb name Merge1 xpos 180 ypos 758 disable {{!parent.overlay_pattern}} } Assert { expression {{"Expression3.maxx > Expression3.minx && Expression3.maxy > Expression3.miny"}} message "increase sample box size or decrease cell size" name error xpos 180 ypos 854 } Output { name Output1 xpos 180 ypos 950 } end_group Multiply { inputs 1+1 channels rgb value 1.8 maskChannelMask {{{parent.Merge9.maskChannelMask}}} invert_mask {{!Merge9.invert_mask}} name Multiply7 xpos 70 ypos 2315 disable {{"!maskChannelMask || !\[exists parent.input3.name]"}} } Dot { name Dot23 xpos 104 ypos 2391 } push $N32a64400 push $N32a2a000 Multiply { inputs 1+1 channels rgb value 1.8 maskChannelMask {{{parent.Merge9.maskChannelMask}}} invert_mask {{parent.Merge9.invert_mask}} name Multiply2 xpos 290 ypos 2315 disable {{"!maskChannelMask || (!parent.scatter && !parent.external_grain)"}} } Merge2 { inputs 2+1 operation copy Achannels rgb Bchannels rgb output rgb maskChannelMask -rgba.alpha name Merge9 xpos 290 ypos 2387 disable {{"!(parent.scatter || parent.external_grain)"}} } Dot { name Dot11 xpos 324 ypos 2490 } set N328abc00 [stack 0] MergeExpression { inputs 2 temp_name0 reverse temp_expr0 "1 / MergeExpression1.temp_expr0" expr0 "Br * Ar * reverse" expr1 "Bg * Ag * reverse" expr2 "Bb * Ab * reverse" name MergeExpression2 xpos 290 ypos 2654 } Dot { name Dot8 xpos 324 ypos 2850 } push $N32a65c00 Merge2 { inputs 2 operation plus bbox B Achannels rgb Bchannels rgb output rgb name Merge3 xpos 950 ypos 2846 } Dot { name Dot42 xpos 984 ypos 3018 } set N328aac00 [stack 0] OCIOColorSpace { in_colorspace {{OCIOColorSpace1.out_colorspace}} out_colorspace {{OCIOColorSpace1.in_colorspace}} name OCIOColorSpace4 xpos 950 ypos 3086 } Dot { name Dot19 xpos 984 ypos 3162 } set N328aa000 [stack 0] Dot { name Dot41 xpos 1204 ypos 3162 } set N328a9c00 [stack 0] Dot { name Dot36 xpos 1314 ypos 3162 } Blur { channels rgb size 1 name Blur1 xpos 1280 ypos 3254 } push $N328a9c00 Merge2 { inputs 2 operation difference bbox B Achannels rgb Bchannels rgb output rgb name Merge10 xpos 1170 ypos 3254 } Multiply { channels rgb value 50 name Multiply3 xpos 1170 ypos 3302 } Dot { name Dot43 xpos 1204 ypos 3402 } push $N32a66400 Dot { name Dot45 xpos 1424 ypos -390 } push $N328aac00 Merge2 { inputs 2 operation from Achannels rgb Bchannels rgb output rgb name Merge11 xpos 1390 ypos 3014 } Dot { name Dot46 xpos 1424 ypos 3522 } push $N328abc00 Dot { name Dot14 xpos 104 ypos 2490 } Dot { name Dot12 xpos 104 ypos 3402 } push $N311f3000 Dot { name Dot47 xpos -556 ypos -390 } push $N311f0800 Merge2 { inputs 2 operation from Achannels rgb Bchannels rgb output rgb name Merge12 xpos -590 ypos -202 } Dot { name Dot10 xpos -556 ypos 3522 } push $N328aa000 Switch { inputs 5 which {{output}} name Output xpos 950 ypos 3656 addUserKnob {20 User} addUserKnob {4 output M {"regrained comp" "plate grain" "normalised grain" "adapted grain" "grain QC"}} } CopyMetaData { inputs 2 mergeMode "Meta only" name CopyMetaData1 xpos 950 ypos 3758 } Output { name Output1 xpos 950 ypos 3854 } end_group push $N34298800 push $N34298c00 Merge2 { inputs 2 operation minus name Merge5 selected true xpos -2510 ypos 4949 } push $N3129d000 Merge2 { inputs 2 operation plus name Merge9 selected true xpos -2391 ypos 5008 } Keymix { inputs 3 name Keymix1 selected true xpos -2268 ypos 5085 }