Esempio n. 1
0
    def getObjectTabPolicy(self):
        """
        Returns the widget that should be displayed under the 'Object' tab.
        """
        # Get the create node in the package, which contains the transform
        # parameter.
        # return self._LightUIDelegate__getObjectTabPolicy()
        packageNode = self.getPackageNode()
        createNode = NU.GetRefNode(packageNode, "create")
        if createNode is None:
            return None

        # Create a root group policy and add some hints on it
        rootPolicy = QT4FormWidgets.PythonGroupPolicy('object')
        rootPolicy.getWidgetHints()['open'] = True
        rootPolicy.getWidgetHints()['hideTitle'] = True

        transformPolicy = QT4FormWidgets.PythonGroupPolicy('transform')
        transformPolicy.getWidgetHints()['open'] = True

        translatePolicy = FormMaster.CreateParameterPolicy(
            None, createNode.getParameter("transform.translate"))
        rotatePolicy = FormMaster.CreateParameterPolicy(
            None, createNode.getParameter("transform.rotate"))
        scalePolicy = FormMaster.CreateParameterPolicy(
            None, createNode.getParameter("transform.scale"))

        transformPolicy.addChildPolicy(translatePolicy)
        transformPolicy.addChildPolicy(rotatePolicy)
        transformPolicy.addChildPolicy(scalePolicy)
        rootPolicy.addChildPolicy(transformPolicy)

        viewerObjectSettingsNode = NU.GetRefNode(packageNode,
                                                 "viewerObjectSettings")
        annotationPolicy = QT4FormWidgets.PythonGroupPolicy('annotation')
        annotationPolicy.getWidgetHints()['open'] = False

        textPolicy = FormMaster.CreateParameterPolicy(
            None,
            viewerObjectSettingsNode.getParameter(
                'args.viewer.default.annotation.text'))
        colorPolicy = FormMaster.CreateParameterPolicy(
            None,
            viewerObjectSettingsNode.getParameter(
                'args.viewer.default.annotation.color'))
        previewColor = FormMaster.CreateParameterPolicy(
            None, createNode.getParameter('previewColor'))
        pickablePolicy = FormMaster.CreateParameterPolicy(
            None,
            viewerObjectSettingsNode.getParameter(
                'args.viewer.default.pickable'))

        annotationPolicy.addChildPolicy(textPolicy)
        annotationPolicy.addChildPolicy(colorPolicy)
        annotationPolicy.addChildPolicy(previewColor)
        annotationPolicy.addChildPolicy(pickablePolicy)

        rootPolicy.addChildPolicy(annotationPolicy)

        return rootPolicy
    def create(cls, enclosingNode, locationPath):
        """
        Creates the contents of the EditStackNode that contains the edit nodes.
        This could be any other kind of node with at least one input and one
        output, but the createPackageEditStackNode() helper function does all
        of the configuration boilerplate code of an EditStackNode for you.
        The return value is a ArnoldSpotLightGafferEditPackage instance.

        This particular package node will contain a TransformEdit node on it,
        which will allow to edit the transform of a spot light.
        """
        # Create the package node. Since this is an edit package we want to use
        # an EditStackNode instead of a GroupNode, since it already has an
        # input and an output by default. This also adds some necessary
        # parameters to this node.
        packageNode = cls.createPackageEditStackNode(enclosingNode,
                                                     locationPath)

        # Build material edit node
        materialNode = NodegraphAPI.CreateNode('Material', packageNode)
        actionParam = materialNode.getParameter('action')
        actionParam.setValue('edit material', 0)

        editLocationParam = materialNode.getParameter('edit.location')
        editLocationParam.setExpression('=^/__gaffer.location')
        editLocationParam.setExpressionFlag(True)
        NU.AddNodeRef(packageNode, 'material_edit', materialNode)

        packageNode.buildChildNode(adoptNode=materialNode)

        # Build transform edit node
        transformEditNode = NodegraphAPI.CreateNode('TransformEdit',
                                                    packageNode)
        actionParam = transformEditNode.getParameter('action')
        actionParam.setValue('override interactive transform', 0)

        pathParam = transformEditNode.getParameter('path')
        pathParam.setExpression('=^/__gaffer.location')
        pathParam.setExpressionFlag(True)

        # Adds reference parameters to the transform edit node
        NU.AddNodeRef(packageNode, 'transform_edit', transformEditNode)

        # Add the transform edit node into the package node using
        # EditStackNode's buildChildNode().
        packageNode.buildChildNode(adoptNode=transformEditNode)

        # Create and append light linking nodes
        linkingNodes = Packages.LinkingMixin.getLinkingNodes(packageNode,
                                                             create=True)
        NU.AppendNodes(
            packageNode,
            tuple(linkingNode for linkingNode in linkingNodes
                  if linkingNode is not None))

        # Instantiate a package with the package node
        return cls.createPackage(packageNode)
Esempio n. 3
0
def editColour(collection, colour, parentNode):
    asStack = SuperToolUtils.GetRefNode(parentNode, Constants.ATTRSET_KEY)
    asNode = doesCollectionExistInStack(collection, asStack)
    for idx, component in enumerate(colour):
        asNode.getParameter("groupValue.colour.i{}".format(idx)).setValue(
            component, 0.0)

    mcStack = SuperToolUtils.GetRefNode(parentNode, Constants.MAT_KEY)
    mcNode = doesCollectionExistInStack(collection, mcStack)
    for idx, component in enumerate(colour):
        mcNode.getParameter(
            "shaders.hydraSurfaceParams.katanaColor.value.i{}".format(
                idx)).setValue(component, 0.0)
Esempio n. 4
0
    def __getObjectTabPolicy(self):
        """
        Returns the widget that should be displayed under the 'Object' tab.
        """
        # Get the create node in the package, which contains the transform
        # parameter.
        packageNode = self.getPackageNode()
        createNode = NU.GetRefNode(packageNode, "create")
        if createNode is None:
            return None

        # Create a root group policy and add some hints on it
        rootPolicy = QT4FormWidgets.PythonGroupPolicy('object')
        rootPolicy.getWidgetHints()['open'] = True
        rootPolicy.getWidgetHints()['hideTitle'] = True

        transformPolicy = QT4FormWidgets.PythonGroupPolicy('transform')
        transformPolicy.getWidgetHints()['open'] = True

        translatePolicy = FormMaster.CreateParameterPolicy(
            None, createNode.getParameter("transform.translate"))
        rotatePolicy = FormMaster.CreateParameterPolicy(
            None, createNode.getParameter("transform.rotate"))
        scalePolicy = FormMaster.CreateParameterPolicy(
            None, createNode.getParameter("transform.scale"))

        transformPolicy.addChildPolicy(translatePolicy)
        transformPolicy.addChildPolicy(rotatePolicy)
        transformPolicy.addChildPolicy(scalePolicy)

        rootPolicy.addChildPolicy(transformPolicy)

        return rootPolicy
    def getMaterialTabPolicy(self):
        # Create a new material policy that just has the prmanLightParams for
        # each light type
        packageNode = self.getPackageNode()
        materialNode = NU.GetRefNode(packageNode, "material_edit")
        if materialNode is not None:
            materialPolicy = QT4FormWidgets.PythonGroupPolicy('material')
            materialPolicy.getWidgetHints()['hideTitle'] = True

            lightShaderPolicy = FormMaster.CreateParameterPolicy(materialPolicy,
                materialNode.getParameter('shaders.arnoldLightShader'))
            lightShaderPolicy = QT4FormWidgets.ValuePolicyProxy(lightShaderPolicy)
            lightShaderPolicy.setWidgetHints(lightShaderPolicy.getWidgetHints())
            lightShaderPolicy.getWidgetHints()['readOnly'] = True
            materialPolicy.addChildPolicy(lightShaderPolicy)

            imageShaderPolicy = FormMaster.CreateParameterPolicy(materialPolicy,
                materialNode.getParameter('shaders.arnoldSurfaceShader'))
            imageShaderPolicy = QT4FormWidgets.ValuePolicyProxy(imageShaderPolicy)
            imageShaderPolicy.setWidgetHints(imageShaderPolicy.getWidgetHints())
            imageShaderPolicy.getWidgetHints()['readOnly'] = True
            materialPolicy.addChildPolicy(imageShaderPolicy)

            params1Policy = FormMaster.CreateParameterPolicy(materialPolicy,
                materialNode.getParameter('shaders.arnoldLightParams'))
            params1Policy.getWidgetHints()['open'] = True
            params2Policy = FormMaster.CreateParameterPolicy(materialPolicy,
                materialNode.getParameter('shaders.arnoldSurfaceParams'))
            params2Policy.getWidgetHints()['open'] = True
            materialPolicy.addChildPolicy(params1Policy)
            materialPolicy.addChildPolicy(params2Policy)
            return materialPolicy
        return None
    def __getObjectTabPolicy(self):
        """
        Returns the widget that should be displayed under the 'Object' tab.
        """
        # Works similarly to SkyDomeUIDelegate.__getObjectTabPolicy, but uses
        # the TransformEdit to modify the transform.
        packageNode = self.getPackageNode()
        transfromEditNode = NU.GetRefNode(packageNode, "transform_edit")

        if transfromEditNode is None:
            return None

        rootPolicy = QT4FormWidgets.PythonGroupPolicy('object')
        rootPolicy.getWidgetHints()['open'] = True
        rootPolicy.getWidgetHints()['hideTitle'] = True

        # Add these three top-level parameters in TransformEdit to the root
        # policy.
        for paramName in ('action', 'rotationOrder', 'args'):
            parameter = transfromEditNode.getParameter(paramName)
            policy = FormMaster.CreateParameterPolicy(rootPolicy,
                                                      parameter)
            rootPolicy.addChildPolicy(policy)

        return rootPolicy
Esempio n. 7
0
 def createLights(self):
     ScriptActions.createMeshLights(
         SuperToolUtils.GetRefNode(self.node, Constants.GAFFER_NODE_KEY),
         self.celParamPolicy.getValue(),
         lightName=self.lightNameParamPolicy.getValue(),
         rigName=self.rigNameParamPolicy.getValue(),
         mode=self.modeNameParamPolicy.getValue(),
         lightType=self.typeParamPolicy.getValue(),
     )
Esempio n. 8
0
    def __buildDefaultNetwork(self):
        """
        MaterialStack -------------------------------------------------->
        Dot --> AttributeSetStack -> OpScriptStack -> OpScriptStack ----> Merge
        """
        # Create nodes and set parameters:
        dotNode = NodegraphAPI.CreateNode("Dot", self)

        attrSetStack = NodegraphAPI.CreateNode("GroupStack", self)
        attrSetStack.setChildNodeType("AttributeSet")

        matCreateStack = NodegraphAPI.CreateNode("GroupStack", self)
        matCreateStack.setChildNodeType("Material")

        opscriptStack = NodegraphAPI.CreateNode("GroupStack", self)
        opscriptStack.setChildNodeType("OpScript")

        opscriptOverrideStack = NodegraphAPI.CreateNode("GroupStack", self)
        opscriptOverrideStack.setChildNodeType("OpScript")

        mergeNode = NodegraphAPI.CreateNode("Merge", self)
        mergeNode.getParameter('showAdvancedOptions').setValue("Yes", 0.0)
        mergeNode.getParameter('advanced.mergeGroupAttributes').insertArrayElement(0)
        mergeNode.getParameter('advanced.mergeGroupAttributes').getChildByIndex(0).setValue("material", 0.0)

        # Make connections:
        self.getSendPort(self.getInputPortByIndex(0).getName()).connect(
            dotNode.getInputPortByIndex(0)
        )

        # Branch A
        dotNode.getOutputPortByIndex(0).connect(attrSetStack.getInputPortByIndex(0))
        attrSetStack.getOutputPortByIndex(0).connect(opscriptStack.getInputPortByIndex(0))
        opscriptStack.getOutputPortByIndex(0).connect(opscriptOverrideStack.getInputPortByIndex(0))
        opscriptOverrideStack.getOutputPortByIndex(0).connect(mergeNode.addInputPort("i0"))

        # Branch B
        matCreateStack.getOutputPortByIndex(0).connect(mergeNode.addInputPort("i1"))

        self.getReturnPort(self.getOutputPortByIndex(0).getName()).connect(
            mergeNode.getOutputPortByIndex(0)
        )

        AutoPos.AutoPositionNodes([dotNode,
                                   attrSetStack,
                                   opscriptStack,
                                   opscriptOverrideStack,
                                   mergeNode,
                                   matCreateStack])

        # Store references to nodes:
        SuperToolUtils.AddNodeRef(self, Constants.DOT_KEY, dotNode)
        SuperToolUtils.AddNodeRef(self, Constants.ATTRSET_KEY, attrSetStack)
        SuperToolUtils.AddNodeRef(self, Constants.MAT_KEY, matCreateStack)
        SuperToolUtils.AddNodeRef(self, Constants.OPSCRIPT_ASSIGN_KEY, opscriptStack)
        SuperToolUtils.AddNodeRef(self, Constants.OPSCRIPT_OVERRIDE_KEY, opscriptOverrideStack)
        SuperToolUtils.AddNodeRef(self, Constants.MERGE_NODE_KEY, mergeNode)
Esempio n. 9
0
    def updateCollections(self, *args):
        # Cook at Dot node, aka at 'clean' point before any new attribute has been set by SuperTool
        collectionNames = ScriptActions.cookCollections(root=self.root,
                                                        node=SuperToolUtils.GetRefNode(self.node,
                                                                                       Constants.DOT_KEY
                                                                                       )
                                                        ).keys()
        ScriptActions.setColourAttributes(collectionNames,
                                          SuperToolUtils.GetRefNode(self.node,
                                                                    Constants.ATTRSET_KEY
                                                                    ),
                                          root=self.root,
                                          )

        # Re-cook since previous nodes added attributes
        self.collections = ScriptActions.cookCollections(root=self.root,
                                                         node=SuperToolUtils.GetRefNode(self.node,
                                                                                        Constants.ATTRSET_KEY
                                                                                        )
                                                         )
        ScriptActions.buildMaterials(self.collections,
                                     SuperToolUtils.GetRefNode(self.node,
                                                               Constants.MAT_KEY
                                                               ),
                                     )

        ScriptActions.createAssignOpScripts(self.collections.keys(),
                                            SuperToolUtils.GetRefNode(self.node,
                                                                      Constants.OPSCRIPT_ASSIGN_KEY
                                                                      ),
                                            root=self.root)

        ScriptActions.createOverrideOpScripts(self.collections.keys(),
                                              SuperToolUtils.GetRefNode(self.node,
                                                                        Constants.OPSCRIPT_OVERRIDE_KEY
                                                                        ),
                                              root=self.root)

        self.collectionsList.clear()
        self.items = []  # Need to store items so Qt doesn't remove the objects from memory after the clear call
        idx = 0
        for collection, attrs in self.collections.items():
            self.items.append(Widgets.ColourCollectionItem(collection, attrs["colour"]))
            self.collectionsList.addItem(self.items[idx])
            idx = idx + 1
    def getMaterialTabPolicy(self):
        # Create a new material policy that just has the prmanLightParams for
        # each light type

        packageNode = self.getPackageNode()
        materialNode = NU.GetRefNode(packageNode, "material")
        if materialNode:
            materialNode.checkDynamicParameters()
            materialPolicy = QT4FormWidgets.PythonGroupPolicy('material')
            materialPolicy.getWidgetHints()['hideTitle'] = True

            shaderPolicy = FormMaster.CreateParameterPolicy(materialPolicy,
                materialNode.getParameter('shaders.arnoldLightShader'))
            shaderPolicy = QT4FormWidgets.ValuePolicyProxy(shaderPolicy)
            shaderPolicy.setWidgetHints(shaderPolicy.getWidgetHints())
            shaderPolicy.getWidgetHints()['readOnly'] = False
            materialPolicy.addChildPolicy(shaderPolicy)

            paramsPolicy = FormMaster.CreateParameterPolicy(materialPolicy,
                materialNode.getParameter('shaders.arnoldLightParams'))
            paramsPolicy.getWidgetHints()['open'] = True
            materialPolicy.addChildPolicy(paramsPolicy)
            return materialPolicy
        return None
Esempio n. 11
0
    def create(cls, enclosingNode, locationPath):
        """
        A factory method which returns an instance of the class.

        @type enclosingNode: C{NodegraphAPI.Node}
        @type locationPath: C{str}
        @rtype: L{LightPackage}
        @param enclosingNode: The parent node within which the new
            package's node should be created.
        @param locationPath: The path to the location to be created/managed
            by the package.
        @return: The newly-created package instance.
        """
        # Create the package node
        packageNode = NodegraphAPI.CreateNode('Group', enclosingNode)
        packageNode.addOutputPort('out')

        # Add parameter containing the package type and location path to the
        # package node
        NU.AddPackageTypeAndPath(packageNode, cls.__name__, locationPath)

        # Create an expression to link the name of the sky dome location to the
        # name of the package.
        locExpr = '=^/%s' % NU.GetPackageLocationParameterPath()

        # Create geometry for the light - in this case a sphere
        createNode = NodegraphAPI.CreateNode('PrimitiveCreate', packageNode)
        createNode.getParameter('type').setValue('coordinate system sphere', 0)
        createNode.getParameter('transform.scale.x').setValue(
            cls.DEFAULT_SIZE, 0)
        scaleExpr = "=transform.scale.x"
        createNode.getParameter('transform.scale.y').setExpression(scaleExpr)
        createNode.getParameter('transform.scale.z').setExpression(scaleExpr)
        createNode.getParameters().createChildNumber('forceAsStaticScene', 1)

        createNodeExtraAttrsParameter = \
            createNode.getParameters().createChildGroup('extraAttrs')
        createNodeExtraAttrsParameter.createChildString(
            '__gafferPackage', '').setExpression('@%s' % packageNode.getName())
        createNode.getParameter('name').setExpression(locExpr)
        createNode.addInputPort('masterMaterial')

        # Store the package class as a parameter on the create node
        NU.SetOrCreateDeepScalarParameter(
            createNode.getParameters(), 'extraAttrs.info.gaffer.packageClass',
            cls.__name__)

        # Set the type of the package location to "light", so that the Gaffer
        # recognizes it as such
        typeAttrSetNode = NodegraphAPI.CreateNode('AttributeSet', packageNode)
        typeAttrSetNode.setName("SetTypeAttributeSet")
        typeAttrSetNode.getParameter('paths.i0').setExpression(locExpr)
        typeAttrSetNode.getParameter('attributeName').setValue('type', 0)
        typeAttrSetNode.getParameter('attributeType').setValue('string', 0)
        typeAttrSetNode.getParameter('stringValue.i0').setValue('light', 0)

        # Set the "viewer.locationType" attribute on the package location to
        # "nurbspatch", so that the viewer knows to display it as geometry
        viewerTypeAttrSetNode = NodegraphAPI.CreateNode(
            'AttributeSet', packageNode)
        viewerTypeAttrSetNode.setName("SetViewerTypeAttributeSet")
        viewerTypeAttrSetNode.getParameter('paths.i0').setExpression(locExpr)
        viewerTypeAttrSetNode.getParameter('attributeName').setValue(
            'viewer.locationType', 0)
        viewerTypeAttrSetNode.getParameter('attributeType').setValue(
            'string', 0)
        viewerTypeAttrSetNode.getParameter('stringValue.i0').setValue(
            'nurbspatch', 0)

        # Add the package location to the light list at /root
        lightListEditNode = NodegraphAPI.CreateNode('LightListEdit',
                                                    packageNode)
        lightListEditNode.setName("LightListEdit")
        lightListEditNode.getParameter('locations.i0').setExpression(locExpr)

        # Create the Material node
        materialNode = NodegraphAPI.CreateNode('Material', packageNode)
        materialNode.getParameter('action').setValue('edit material', 0)
        materialNode.getParameter('makeInteractive').setValue('Yes', 0)
        materialNode.getParameters().createChildNumber(
            'makeInteractiveSpecificToMaterial', 1)
        materialNode.getParameter('edit.location').setExpression(locExpr)

        # Create an OpScript node to copy the preview texture from the shader
        # to the sphere
        copyPreviewTextureOpScriptNode = cls.__createOpScriptNode(
            packageNode, 'CopyPreviewTextureOpScript',
            cls.__getPreviewTextureOpScript())

        # Create an OpScript node to copy the transform from the sphere to the
        # shader
        copyXformOpScriptNode = cls.__createOpScriptNode(
            packageNode, 'CopyXformOpScript', cls.__getCopyXformOpScript())

        # Create an OpScript node to flip the UVs in the viewer
        viewerUVFlipOpScriptNode = cls.__createOpScriptNode(
            packageNode, 'ViewerUVFlipOpScript',
            cls.__getViewerUVFlipOpScript())

        # Create a DistantPort node to reference the master material
        masterMaterialDistantPortNode = NodegraphAPI.CreateNode(
            'DistantPort', packageNode)
        masterMaterialDistantPortNode.setBypassed(True)

        # Create a ViewerObjectSettings node in case we want to customize how
        # the skydome is displayed in the viewer
        viewerObjectSettingsNode = NodegraphAPI.CreateNode(
            'ViewerObjectSettings', packageNode)
        viewerObjectSettingsNode.getParameter('CEL').setExpression(locExpr)

        # Add node references to the package node
        NU.AddNodeRef(packageNode, 'create', createNode)
        NU.AddNodeRef(packageNode, 'lightListEdit', lightListEditNode)
        NU.AddNodeRef(packageNode, 'material', materialNode)
        NU.AddNodeRef(packageNode, 'master', masterMaterialDistantPortNode)
        NU.AddNodeRef(packageNode, 'viewerObjectSettings',
                      viewerObjectSettingsNode)

        # Wire up and position the nodes
        NU.WireInlineNodes(
            packageNode,
            (masterMaterialDistantPortNode, createNode, typeAttrSetNode,
             viewerTypeAttrSetNode, lightListEditNode, materialNode,
             copyPreviewTextureOpScriptNode, copyXformOpScriptNode,
             viewerUVFlipOpScriptNode, viewerObjectSettingsNode))

        # Create and append light linking nodes
        linkingNodes = Packages.LinkingMixin.getLinkingNodes(packageNode,
                                                             create=True)
        NU.AppendNodes(
            packageNode,
            tuple(linkingNode for linkingNode in linkingNodes
                  if linkingNode is not None))
        # Create a package node instance
        result = cls(packageNode)
        Packages.CallbackMixin.executeCreationCallback(result)

        # Create a post-merge stack node for this package
        postMergeNode = result.createPostMergeStackNode()

        # Use an AttributeSet node to set Arnold's background attribute at root
        arnoldBGAttrSetNode = NodegraphAPI.CreateNode('AttributeSet',
                                                      packageNode)
        arnoldBGAttrSetNode.setName("ArnoldBGAttributeSet")
        arnoldBGAttrSetNode.getParameter('paths.i0').setValue('/root', 0)
        arnoldBGAttrSetNode.getParameter('attributeName').setValue(
            'arnoldGlobalStatements.background', 0)
        arnoldBGAttrSetNode.getParameter('attributeType').setValue('string', 0)
        arnoldBGAttrSetNode.getParameter('stringValue.i0').setExpression(
            'getParam("%s.__gaffer.location")' % packageNode.getName())
        postMergeNode.buildChildNode(adoptNode=arnoldBGAttrSetNode)

        # Set our material to point at a baked Look File material
        result.setLookFileMaterial(
            cls.DEFAULT_BAKED_LIGHT_FILENAME,
            "/root/materials/%s" % cls.DEFAULT_BAKED_LIGHT_NAME)

        return result
Esempio n. 12
0
    def create(cls, enclosingNode, locationPath, shaderName=''):
        """
        A factory method which returns an instance of the class.

        @type enclosingNode: C{NodegraphAPI.Node}
        @type locationPath: C{str}
        @rtype: L{LightPackage}
        @param enclosingNode: The parent node within which the new
            package's node should be created.
        @param locationPath: The path to the location to be created/managed
            by the package.
        @return: The newly-created package instance.
        """
        # Create the package node
        packageNode = NodegraphAPI.CreateNode('Group', enclosingNode)
        packageNode.addOutputPort('out')

        # Add parameter containing the package type and location path to the package node
        NU.AddPackageTypeAndPath(packageNode, cls.__name__, locationPath)

        # Create an expression to link the name of the sky dome location to the name of the package
        locExpr = '=^/%s' % NU.GetPackageLocationParameterPath()

        # Create geometry for the light - in this case a bounded plane
        createNode = NodegraphAPI.CreateNode('LightCreate', packageNode)
        createNode.getParameter('transform.scale.x').setValue(cls.DEFAULT_SIZE, 0)
        scaleExpr = "=transform.scale.x"
        createNode.getParameter('transform.scale.y').setExpression(scaleExpr)
        createNode.getParameter('transform.scale.z').setExpression(scaleExpr)
        createNode.getParameters().createChildNumber('forceAsStaticScene', 1)

        createNodeExtraAttrsParameter = createNode.getParameters().createChildGroup('extraAttrs')
        createNodeExtraAttrsParameter.createChildString('__gafferPackage', '').setExpression('@%s' % packageNode.getName())
        createNode.getParameter('name').setExpression(locExpr)
        createNode.addInputPort('masterMaterial')

        # Store the package class as a parameter on the create node
        NU.SetOrCreateDeepScalarParameter(createNode.getParameters(),
                                          'extraAttrs.info.gaffer.packageClass',
                                          cls.__name__)

        # Add the package location to the light list at /root
        lightListEditNode = NodegraphAPI.CreateNode('LightListEdit', packageNode)
        lightListEditNode.setName("LightListEdit")
        lightListEditNode.getParameter('locations.i0').setExpression(locExpr)

        # Create the Material node
        materialNode = NodegraphAPI.CreateNode('Material', packageNode)
        materialNode.getParameter('action').setValue('edit material', 0)
        materialNode.getParameter('makeInteractive').setValue('Yes', 0)
        materialNode.getParameters().createChildNumber('makeInteractiveSpecificToMaterial', 1)
        materialNode.getParameter('edit.location').setExpression(locExpr)

        # Create an OpScript node to copy the transform from the sphere to the shader
        copyXformOpScriptNode = cls.createOpScriptNode(packageNode,
                                                         'CopyXformOpScript',
                                                         cls.getCopyXformOpScript())

        # Create a DistantPort node to reference the master material
        masterMaterialDistantPortNode = NodegraphAPI.CreateNode('DistantPort', packageNode)
        masterMaterialDistantPortNode.setBypassed(True)

        # Create a ViewerObjectSettings node in case we want to customize how
        # the spot light is displayed in the viewer
        viewerObjectSettingsNode = NodegraphAPI.CreateNode('ViewerObjectSettings', packageNode)
        viewerObjectSettingsNode.getParameter('CEL').setExpression(locExpr)

        # Create the Merge node, for merging in child packages
        mergeNode = NodegraphAPI.CreateNode('Merge', packageNode)
        mergeNode.addInputPort('i0')

        # Add node references to the package node
        NU.AddNodeRef(packageNode, 'create', createNode)
        NU.AddNodeRef(packageNode, 'lightListEdit', lightListEditNode)
        NU.AddNodeRef(packageNode, 'material', materialNode)
        NU.AddNodeRef(packageNode, 'master', masterMaterialDistantPortNode)
        NU.AddNodeRef(packageNode, 'viewerObjectSettings', viewerObjectSettingsNode)
        NU.AddNodeRef(packageNode, 'merge', mergeNode)

        # Wire up and position the nodes
        NU.WireInlineNodes(packageNode, (masterMaterialDistantPortNode,
                                         createNode,
                                         lightListEditNode,
                                         materialNode,
                                         copyXformOpScriptNode,
                                         viewerObjectSettingsNode,
                                         mergeNode))

        # Create and append light linking nodes
        linkingNodes = Packages.LinkingMixin.getLinkingNodes(packageNode, create=True)
        NU.AppendNodes(packageNode, tuple(linkingNode for linkingNode in linkingNodes if linkingNode is not None))

        # Create a package node instance
        result = cls(packageNode)
        Packages.CallbackMixin.executeCreationCallback(result)

        # By default we use inline shaders, rather than forcing the user through look files, so this is old:
        # Set our material to point at a baked Look File material
        #result.setLookFileMaterial(cls.DEFAULT_BAKED_LIGHT_FILENAME, "/root/materials/%s" % cls.DEFAULT_BAKED_LIGHT_NAME)

        # Set the main shader
        result.setShader('arnoldLight', shaderName)

        return result