Custom Scripts X: Arnold beauty rebuilder

This is a beauty passes rebuilder for Arnold that separates the different passes that make the beauty and then merge them again, so compositors can tweak specific passes as they please.

It has 5 kinds of rebuilds:

  • Basic Light Rebuild: Separates direct and indirect light
  • Basic Albedo Rebuild: Separates the albedo and the light influence
  • Simple Beauty Rebuild: Separates the most used basic beauty passes (diffuse, emission, specular, sss, transmission)
  • Advance Beauty Rebuild: Separates the most used basic beauty passes and at the same time separates the direct and indirect light influence of them
  • Complex Beauty Rebuild: Separates the most used basic beauty passes, separating the direct and indirect light influence and also the albedo influence

If you want to take into consideration coat and volume passes too, you can edit the AOV lists in the script.

It also checks if the read file contains all the passes that are needed for the selected rebuild type. If not, it tells which are the missing ones, before generating the rebuild.

class arnold_beauty_rebuilder():

    def __init__(self):
        self.readN = nuke.selectedNode()
        self.readNXpos = int(self.readN['xpos'].value())
        self.readNYpos = int(self.readN['ypos'].value())
        self.readNChannels = self.readN.channels()
        self.readNLayers = list(set([c.split('.')[0] for c in self.readNChannels]))
        self.basicLightAOVList = ['indirect', 'direct']
        self.basicAlbedoAOVList = ['diffuse_albedo', ['diffuse_indirect', 'diffuse_direct']]
        self.simpleBeautyAOVList = ['diffuse', 'emission', 'specular', 'sss', 'transmission']
        self.advanceBeautyAOVList = [['diffuse_indirect', 'diffuse_direct'], 'emission', ['specular_indirect', 'specular_direct'], ['sss_indirect', 'sss_direct'], ['transmission_indirect', 'transmission_direct']]
        self.complexBeautyAOVList = [['diffuse_albedo', ['diffuse_indirect', 'diffuse_direct']], 'emission', ['specular_albedo', ['specular_indirect', 'specular_direct']], ['sss_albedo', ['sss_indirect', 'sss_direct']], ['transmission_albedo', ['transmission_indirect', 'transmission_direct']]]

    def checkLayers(self, aovList):
        self.finalAOVList = []
        self.missingAOV = []
        for aov in aovList:
            if type(aov) is str:
                self.finalAOVList.append(aov)
            else:
                for subAOV in aov:
                    if type(subAOV) is str:
                        self.finalAOVList.append(subAOV)
                    else:
                        for subSubAOV in subAOV:
                            self.finalAOVList.append(subSubAOV)
        for aov in self.finalAOVList:
            if aov not in self.readNLayers:
                self.missingAOV.append(aov)
        if len(self.missingAOV) != 0:
            strMissingAOV = ''
            for i in self.missingAOV:
                strMissingAOV = strMissingAOV + '\n' + '-' + i
            nuke.message('Warning! The following AOVs are missing:' + '\n' + strMissingAOV)

    def set_unpremult(self):
        self.unpremult = nuke.nodes.Unpremult(channels='all')
        self.unpremult.setXpos(self.readNXpos)
        self.unpremult.setYpos(self.readNYpos + 150)
        self.unpremult.setInput(0, self.readN)

    def set_oDot(self):
        self.oDot = nuke.nodes.Dot()
        self.oDot.setXpos(self.readNXpos + 34)
        self.oDot.setYpos(self.readNYpos + 250)
        self.oDot.setInput(0, nuke.toNode(self.unpremult.name()))

    def set_auxDot(self, tDot):
        self.auxDot = nuke.nodes.Dot()
        self.auxDot.setXpos(int(nuke.toNode(tDot)['xpos'].getValue())+200)
        self.auxDot.setYpos(int(nuke.toNode(tDot)['ypos'].getValue()))
        self.auxDot.setInput(0, nuke.toNode(tDot))
        self.lastAuxDot = self.auxDot.name()

    def set_shuffle(self, channelS):
        self.shuffleID = channelS
        self.shuffleID = nuke.nodes.Shuffle(label=channelS.upper())
        self.shuffleID.knob('in').setValue(channelS)
        self.shuffleID.setXpos(int(self.auxDot['xpos'].getValue())-34)
        self.shuffleID.setYpos(int(self.auxDot['ypos'].getValue())+50)
        self.shuffleID.setInput(0, nuke.toNode(self.auxDot.name()))

    def set_remove(self, channelK):
        self.remove = nuke.nodes.Remove(operation='keep', channels=channelK)
        self.remove.setXpos(int(nuke.toNode(self.shuffleID.name())['xpos'].getValue()))
        self.remove.setYpos(int(nuke.toNode(self.shuffleID.name())['ypos'].getValue())+50)
        self.remove.setInput(0, nuke.toNode(self.shuffleID.name()))

    def set_merge(self, mergeType, aLine='NOTHING', bLine='NOTHING'):
        self.mergeID = nuke.nodes.Merge(operation=mergeType)
        self.mergeID.setXpos(int(nuke.toNode(bLine)['xpos'].getValue()))
        self.mergeID.setYpos(int(nuke.toNode(bLine)['ypos'].getValue())+200)
        if bLine != 0:
            self.mergeID.setInput(0, nuke.toNode(bLine))
        elif aLine != 0:
            self.mergeID.setInput(1, nuke.toNode(aLine))

    def set_merge_dot(self, target, y):
        self.mergeDot = nuke.nodes.Dot()
        self.mergeDot.setXpos(int(nuke.toNode(target)['xpos'].getValue())+34)
        self.mergeDot.setYpos(int(nuke.toNode(target)['ypos'].getValue())+y+3)
        self.mergeDot.setInput(0, nuke.toNode(target))

    def set_alpha(self, target):
        self.set_shuffle('alpha')
        self.set_remove('alpha')
        self.copy = nuke.nodes.Copy(from0='rgba.alpha', to0='rgba.alpha')
        self.copy.setXpos(int(nuke.toNode(target)['xpos'].getValue()))
        self.copy.setYpos(int(nuke.toNode(target)['ypos'].getValue())+200)
        self.copy.setInput(0, nuke.toNode(target)) 
        self.copyDot = nuke.nodes.Dot()
        self.copyDot.setXpos(int(nuke.toNode(self.shuffleID.name())['xpos'].getValue())+34)
        self.copyDot.setYpos(int(nuke.toNode(self.copy.name())['ypos'].getValue())+11)
        self.copyDot.setInput(0, nuke.toNode(self.remove.name()))
        self.copy.setInput(1, self.copyDot)

    def set_premult(self, target, x='NOTHING', y='NOTHING'):
        self.premult = nuke.nodes.Premult()
        self.premult.setXpos(int(nuke.toNode(target)['xpos'].getValue())+x)
        self.premult.setYpos(int(nuke.toNode(self.copy.name())['ypos'].getValue())+y)
        self.premult.setInput(0, nuke.toNode(target))

    def basicLight_rebuild(self):
        self.set_unpremult()
        self.set_oDot()
        self.set_auxDot(self.oDot.name())
        self.set_shuffle('indirect')
        self.set_remove('rgb')
        self.set_merge('plus', 0, self.remove.name())
        self.set_auxDot(self.lastAuxDot)
        self.set_shuffle('direct')
        self.set_remove('rgb')
        self.set_merge_dot(self.remove.name(), 200)
        self.mergeID.setInput(1, nuke.toNode(self.mergeDot.name()))
        self.set_auxDot(self.lastAuxDot)
        self.set_alpha(self.mergeID.name())
        self.set_premult(self.copy.name(), 0, 75)
        self.set_premult(self.oDot.name(), -34, 75)

    def basicAlbedo_rebuild(self):
        self.set_unpremult()
        self.set_oDot()
        for subAOV in self.basicAlbedoAOVList:
            if type(subAOV) is str:
                self.set_auxDot(self.oDot.name())
                self.set_shuffle(subAOV)
                self.set_remove('rgb')
                self.set_merge_dot(self.remove.name(), 200)
                self.set_merge('multiply', 0, self.mergeDot.name())
                lastMerge = self.mergeID.name()
                multiplyMerge = self.mergeID.name()
                nuke.toNode(self.mergeID.name()).setYpos(int(nuke.toNode(self.mergeID.name())['ypos'].getValue())+200)
                nuke.toNode(self.mergeID.name()).setXpos(int(nuke.toNode(self.mergeID.name())['xpos'].getValue())-34)
                self.set_merge_dot(self.mergeDot.name(), -3)
                nuke.toNode(self.mergeDot.name()).setXpos(int(nuke.toNode(self.mergeDot.name())['xpos'].getValue())+134)
                self.set_merge('divide', 0, self.mergeDot.name())
                divideMerge = self.mergeID.name()
                nuke.toNode(divideMerge).setXpos(int(nuke.toNode(divideMerge)['xpos'].getValue())-34)
                self.set_merge_dot(self.mergeID.name(), 200+1)
                nuke.toNode(multiplyMerge).setInput(1, nuke.toNode(self.mergeDot.name()))
            else:
                for subSubAOV in subAOV:
                    self.set_auxDot(self.lastAuxDot)
                    if subAOV.index(subSubAOV) == 0:
                        nuke.toNode(self.lastAuxDot).setXpos(int(nuke.toNode(self.lastAuxDot)['xpos'].getValue())+150)
                    self.set_shuffle(subSubAOV)
                    self.set_remove('rgb')
                    if subAOV.index(subSubAOV) == 0:
                        self.set_merge('plus', 0, self.remove.name())
                        self.set_merge_dot(self.mergeID.name(), 200+3)
                        divideDot = self.mergeDot.name()
                    else:
                        self.set_merge_dot(self.remove.name(), 200)
                self.mergeID.setInput(1, nuke.toNode(self.mergeDot.name()))
        nuke.toNode(divideMerge).setInput(1, nuke.toNode(divideDot))
        self.set_auxDot(self.lastAuxDot)
        self.set_alpha(lastMerge)
        self.set_premult(self.copy.name(), 0, 75)
        self.set_premult(self.oDot.name(), -34, 75)

    def simpleBeauty_rebuild(self):
        self.set_unpremult()
        self.set_oDot()
        mergeList = []
        dotList = []
        for aov in self.simpleBeautyAOVList:
            if self.simpleBeautyAOVList.index(aov) == 0:
                self.set_auxDot(self.oDot.name())
                self.set_shuffle(aov)
                self.set_remove('rgb')
                for i in range(len(self.simpleBeautyAOVList)-1):
                    if range(len(self.simpleBeautyAOVList)-1).index(i) == 0:
                        self.set_merge('plus', 0, self.remove.name())
                    else:
                        self.set_merge('plus', 0, self.mergeID.name())
                    mergeList.append(self.mergeID.name())                    
            else: 
                self.set_auxDot(self.lastAuxDot)
                self.set_shuffle(aov)
                self.set_remove('rgb')
                self.set_merge_dot(self.remove.name(), 200 * self.simpleBeautyAOVList.index(aov))
                dotList.append(self.mergeDot.name())
        for merge in mergeList:
            nuke.toNode(merge).setInput(1, nuke.toNode(dotList[mergeList.index(merge)]))
        self.set_auxDot(self.lastAuxDot)
        self.set_alpha(self.mergeID.name())
        self.set_premult(self.copy.name(), 0, 75)
        self.set_premult(self.oDot.name(), -34, 75)

    def advanceBeauty_rebuild(self):
        self.set_unpremult()
        self.set_oDot()
        mergeList = []
        dotList = []
        for aov in self.advanceBeautyAOVList:
            if type(aov) is str:
                self.set_auxDot(self.lastAuxDot)
                self.set_shuffle(aov)
                self.set_remove('rgb')
                self.set_merge_dot(self.remove.name(), 200 * (self.advanceBeautyAOVList.index(aov)+1))
                dotList.append(self.mergeDot.name())
            elif self.advanceBeautyAOVList.index(aov) == 0:
                for subAOV in aov:
                    if aov.index(subAOV) == 0:
                        self.set_auxDot(self.oDot.name())
                        self.set_shuffle(subAOV)
                        self.set_remove('rgb')
                        for i in range(len(self.advanceBeautyAOVList)):
                            if range(len(self.advanceBeautyAOVList)).index(i) == 0:
                                self.set_merge('plus', 0, self.remove.name())
                            else:
                                self.set_merge('plus', 0, self.mergeID.name())
                            mergeList.append(self.mergeID.name())
                            lastMerge = self.mergeID.name()    
                    else:
                        self.set_auxDot(self.lastAuxDot)
                        self.set_shuffle(subAOV)
                        self.set_remove('rgb')
                        self.set_merge_dot(self.remove.name(), 200)
                        dotList.append(self.mergeDot.name())
            else:
                for subAOV in aov:
                    self.set_auxDot(self.lastAuxDot)
                    self.set_shuffle(subAOV)
                    self.set_remove('rgb')
                    if aov.index(subAOV) == 0:
                        self.set_merge('plus', 0, self.remove.name())
                        self.set_merge_dot(self.mergeID.name(), 200 * self.advanceBeautyAOVList.index(aov))
                        dotList.append(self.mergeDot.name())
                    else:
                        self.set_merge_dot(self.remove.name(), 200)
                self.mergeID.setInput(1, nuke.toNode(self.mergeDot.name()))
        for merge in mergeList:
            nuke.toNode(merge).setYpos(int(nuke.toNode(dotList[mergeList.index(merge)])['ypos'].getValue()))
            nuke.toNode(merge).setInput(1, nuke.toNode(dotList[mergeList.index(merge)]))
        self.set_auxDot(self.lastAuxDot)
        self.set_alpha(lastMerge)
        self.set_premult(self.copy.name(), 0, 75)
        self.set_premult(self.oDot.name(), -34, 75)

    def complexBeauty_rebuild(self):
        self.set_unpremult()
        self.set_oDot()
        mergeList = []
        dotList = []
        for aov in self.complexBeautyAOVList:
            if type(aov) is str:
                self.set_auxDot(self.lastAuxDot)
                self.set_shuffle(aov)
                self.set_remove('rgb')
                self.set_merge_dot(self.remove.name(), 200 * (self.complexBeautyAOVList.index(aov)+3))
                dotList.append(self.mergeDot.name())
            elif self.complexBeautyAOVList.index(aov) == 0:
                for subAOV in aov:
                    if type(subAOV) is str:
                        self.set_auxDot(self.oDot.name())
                        self.set_shuffle(subAOV)
                        self.set_remove('rgb')
                        self.set_merge_dot(self.remove.name(), 200)
                        self.set_merge('multiply', 0, self.mergeDot.name())
                        multiplyMerge = self.mergeID.name()
                        nuke.toNode(self.mergeID.name()).setYpos(int(nuke.toNode(self.mergeID.name())['ypos'].getValue())+200)
                        nuke.toNode(self.mergeID.name()).setXpos(int(nuke.toNode(self.mergeID.name())['xpos'].getValue())-34)
                        for i in range(len(self.complexBeautyAOVList)-1):
                            self.set_merge('plus', 0, self.mergeID.name())
                            mergeList.append(self.mergeID.name())
                        lastMerge = self.mergeID.name()
                        self.set_merge_dot(self.mergeDot.name(), -3)
                        nuke.toNode(self.mergeDot.name()).setXpos(int(nuke.toNode(self.mergeDot.name())['xpos'].getValue())+134)
                        self.set_merge('divide', 0, self.mergeDot.name())
                        divideMerge = self.mergeID.name()
                        nuke.toNode(divideMerge).setXpos(int(nuke.toNode(divideMerge)['xpos'].getValue())-34)
                        self.set_merge_dot(self.mergeID.name(), 200)
                        nuke.toNode(multiplyMerge).setInput(1, nuke.toNode(self.mergeDot.name()))

                    else:
                        for subSubAOV in subAOV:
                            self.set_auxDot(self.lastAuxDot)
                            if subAOV.index(subSubAOV) == 0:
                                nuke.toNode(self.lastAuxDot).setXpos(int(nuke.toNode(self.lastAuxDot)['xpos'].getValue())+150)
                            self.set_shuffle(subSubAOV)
                            self.set_remove('rgb')
                            if subAOV.index(subSubAOV) == 0:
                                self.set_merge('plus', 0, self.remove.name())
                                self.set_merge_dot(self.mergeID.name(), 200+3)
                                divideDot = self.mergeDot.name()
                            else:
                                self.set_merge_dot(self.remove.name(), 200)
                        self.mergeID.setInput(1, nuke.toNode(self.mergeDot.name()))
                nuke.toNode(divideMerge).setInput(1, nuke.toNode(divideDot))
            else:
                for subAOV in aov:
                    if type(subAOV) is str:
                        self.set_auxDot(self.lastAuxDot)
                        self.set_shuffle(subAOV)
                        self.set_remove('rgb')
                        self.set_merge_dot(self.remove.name(), 200)
                        self.set_merge('multiply', 0, self.mergeDot.name())
                        nuke.toNode(self.mergeID.name()).setYpos(int(nuke.toNode(self.mergeID.name())['ypos'].getValue())+200)
                        nuke.toNode(self.mergeID.name()).setXpos(int(nuke.toNode(self.mergeID.name())['xpos'].getValue())-34)
                        multiplyMerge = self.mergeID.name()
                        self.set_merge_dot(self.mergeDot.name(), -3)
                        nuke.toNode(self.mergeDot.name()).setXpos(int(nuke.toNode(self.mergeDot.name())['xpos'].getValue())+134)
                        divideDot = self.mergeDot.name()
                        self.set_merge_dot(self.mergeID.name(), 200 * (self.complexBeautyAOVList.index(aov)))
                        dotList.append(self.mergeDot.name())
                        self.set_merge('divide', 0, divideDot)
                        divideMerge = self.mergeID.name()
                        nuke.toNode(self.mergeID.name()).setXpos(int(nuke.toNode(self.mergeID.name())['xpos'].getValue())-34)
                        self.set_merge_dot(self.mergeID.name(), 200)
                        nuke.toNode(multiplyMerge).setInput(1, nuke.toNode(self.mergeDot.name()))
                    else:
                        for subSubAOV in subAOV:
                            self.set_auxDot(self.lastAuxDot)
                            if subAOV.index(subSubAOV) == 0:
                                nuke.toNode(self.lastAuxDot).setXpos(int(nuke.toNode(self.lastAuxDot)['xpos'].getValue())+150)
                            self.set_shuffle(subSubAOV)
                            self.set_remove('rgb')
                            if subAOV.index(subSubAOV) == 0:
                                self.set_merge('plus', 0, self.remove.name())
                                self.set_merge_dot(self.mergeID.name(), 200+3)
                                nuke.toNode(divideMerge).setInput(1, nuke.toNode(self.mergeDot.name()))
                            else:
                                self.set_merge_dot(self.remove.name(), 200)
                        self.mergeID.setInput(1, nuke.toNode(self.mergeDot.name()))
        for merge in mergeList:
            nuke.toNode(merge).setInput(1, nuke.toNode(dotList[mergeList.index(merge)]))
        self.set_auxDot(self.lastAuxDot)
        self.set_alpha(lastMerge)
        self.set_premult(self.copy.name(), 0, 75)
        self.set_premult(self.oDot.name(), -34, 75)

def arnold_beauty_rebuild():
    if nuke.selectedNode().Class() != 'Read':
        nuke.message('Please, select a Read node')
    else:
        abr = arnold_beauty_rebuilder()
        abrCL = getattr(abr, 'checkLayers')
        p = nuke.Panel('Arnold Beauty Rebuild')
        rebuilds = ['Basic\ light\ rebuild', ' Basic\ albedo\ rebuild', ' Basic\ beauty\ rebuild', ' Advance\ beauty\ rebuild', ' Complex\ beauty\ rebuild']
        p.addEnumerationPulldown('Rebuild type', (','.join(rebuilds)).replace(',', ''))
        if not p.show():
            return
        rebuildType = p.value('Rebuild type')
        if rebuildType == rebuilds[0].replace('\\', ''):
            abrCL(getattr(abr, 'basicLightAOVList'))
            abrBL = getattr(abr, 'basicLight_rebuild')
            abrBL()
        elif rebuildType == rebuilds[1][1:].replace('\\', ''):
            abrCL(getattr(abr, 'basicAlbedoAOVList'))
            abrBA = getattr(abr, 'basicAlbedo_rebuild')
            abrBA()
        elif rebuildType == rebuilds[2][1:].replace('\\', ''):
            abrCL(getattr(abr, 'simpleBeautyAOVList'))
            abrSB = getattr(abr, 'simpleBeauty_rebuild')
            abrSB()
        elif rebuildType == rebuilds[3][1:].replace('\\', ''):
            abrCL(getattr(abr, 'advanceBeautyAOVList'))
            abrAB = getattr(abr, 'advanceBeauty_rebuild')
            abrAB()
        else:
            abrCL(getattr(abr, 'complexBeautyAOVList'))
            abrCB = getattr(abr, 'complexBeauty_rebuild')
            abrCB()

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.