Search code examples
pythonmayauv-mappingpymel

how do i link the UVs from a custom UVset to a texture in Maya using pymel (or maya.cmds)


I'm writing a tool that will help make me make custom uvSets on a model that will be linked to ramps(no interpolation) that will be sent to vray_extraTex render elements. these will become mattes and used in the same way as vRay multi mattes. however, I am not able to link the ramp that is my texture for the vray_extraTex to the custom uvSet using pymel.

I can do all this manually in Maya but for some reason, I am missing something for pymel to link the UVs to the ramp. I am testing in a Maya scene with a pSphere that has two uvSets and the second set is active. This code has been stripped down a bit:

def main():
    inclusiveSet = None
    renderElements =[]
    ramps = []
    newChannels = ['TestA','TestB','TestC','TestD'] 
    for i, channel in enumerate(newChannels):
        modIndex = i % 3 # 0:Red, 1:Green, 2:Blue
        shapeNode=pm.PyNode('pSphereShape1')
        transformNode=shapeNode.getTransform()

        if modIndex == 0: # the first channel in the new Render Element
            # make an etex render element
            eTexElement = pm.PyNode(pm.mel.eval('vrayAddRenderElement("ExtraTexElement")'))
            eTexElement.vray_name_extratex.set('')
            eTexElement.vray_explicit_name_extratex.set('empty_empty_empy')            
            renderElements.append(eTexElement)
            # make a ramp
            ramp = pm.shadingNode('ramp', asTexture=True, name='eTex_{}_ramp'.format(transformNode.name()))
            ramps.append(ramp)
            ramp.outColor.connect(eTexElement.vray_texture_extratex)
            # make a place2dtexture
            place2d = pm.shadingNode('place2dTexture', asUtility=True)
            place2d.outUV.connect(ramp.uv)
            place2d.translateFrameU.set(len(renderElements) - 1)
            # link UVs to ramp
            # NOT WORKING
            indices = pm.polyUVSet(shapeNode.name(), query=True, allUVSetsIndices=True)
            currentUVSet = pm.polyUVSet(shapeNode, query=True, currentUVSet=True )
            for i in indices:
                if currentUVSet == pm.getAttr("{}.uvSet[{}].uvSetName".format(shapeNode.name(), i)):
                    pm.uvLink(uvSet='{}.uvSet[{}].uvSetName'.format(shapeNode.name(), i) , texture=ramp)

        explicit_name = eTexElement.vray_explicit_name_extratex.get()
        nameTokens = explicit_name.split('_')
        nameTokens[modIndex] = channel
        explicit_name = '_'.join(nameTokens)
        eTexElement.vray_explicit_name_extratex.set(explicit_name)

main()

I get no errors but when I check the UV Linking the ramps are still set to map1 uvSet and not the second set that was active.

I expected to see the ramps connected to the uvChooser node and linked to the second uvSet.

I realized while writing this post that maybe I need to attach the ramps to the shader that is assigned to the geo before I can uvlink them with python. I'll try and test that next


Solution

  • so after some more testing, I was able to get it to work after assigning the ramps to a new attr on the objects' shader and with a couple of minor fixes to the code I posted before. fixed:

    def connectTexture(layeredTex, shapeNode):
        shadingGrps = pm.listConnections(shapeNode,type='shadingEngine')
        shaders = pm.ls(pm.listConnections(shadingGrps),materials=1)
        shader = shaders[0]
        pm.addAttr(shader, longName='eTexLayeredTex', usedAsColor=True, attributeType='float3' )
        pm.addAttr(shader, longName='eTexLayeredTexR', attributeType='float', parent='eTexLayeredTex' )
        pm.addAttr(shader, longName='eTexLayeredTexG', attributeType='float', parent='eTexLayeredTex' )
        pm.addAttr(shader, longName='eTexLayeredTexB', attributeType='float', parent='eTexLayeredTex' )
        layeredTex.outColor.connect(shader.eTexLayeredTex)
    
    
    def main():
        inclusiveSet=None
        renderElements=[]
        ramps=[]
        newChannels = ['TestA','TestB','TestC','TestD']
        shapeNode=pm.PyNode('pSphereShape1')
        transformNode=shapeNode.getTransform()
    
        # make a layeredTexture
        layeredTexture = pm.shadingNode('layeredTexture', asTexture=True, name='eTex_{}_layeredTexture'.format(transformNode.name()))
        layeredTexture.attr('inputs')[0].color.set(0,0,0)
        layeredTexture.attr('inputs')[0].alpha.set(1)
        layeredTexture.attr('inputs')[0].blendMode.set(1)
        connectTexture(layeredTexture, shapeNode)
        for i, channel in enumerate(newChannels):
            modIndex = i % 3 # 0:Red, 1:Green, 2:Blue
            if modIndex == 0: # the first channel in the new Render Element
    
                # make an etex render element
                eTexElement = pm.PyNode(pm.mel.eval('vrayAddRenderElement("ExtraTexElement")'))
                eTexElement.vray_name_extratex.set('')
                eTexElement.vray_explicit_name_extratex.set('empty_empty_empy')            
                renderElements.append(eTexElement)
    
                # make a ramp
                ramp = pm.shadingNode('ramp', asTexture=True, name='eTex_{}_ramp'.format(transformNode.name()))
                ramps.append(ramp)
                ramp.interpolation.set(0)
                ramp.colorEntryList[0].position.set(0.0)
                ramp.colorEntryList[1].position.set((1.0 / 3.0))
                ramp.colorEntryList[2].position.set((2.0 / 3.0))
                ramp.colorEntryList[0].color.set(1,0,0)
                ramp.colorEntryList[1].color.set(0,1,0)
                ramp.colorEntryList[2].color.set(0,0,1)
                ramp.defaultColor.set(0,0,0)            
                ramp.outColor.connect(eTexElement.vray_texture_extratex)
                ramp.outColor.connect( layeredTexture.attr( 'inputs[{}].color'.format( 1 + i // 3)))
    
                # make a place2dtexture
                place2d = pm.shadingNode('place2dTexture', asUtility=True)
                place2d.outUV.connect(ramp.uv)
                place2d.outUvFilterSize.connect(ramp.uvFilterSize)
                place2d.wrapU.set(0)
                place2d.wrapV.set(0)
                place2d.translateFrameU.set(len(renderElements) - 1)
    
                # link UVs to ramp
                indices = pm.polyUVSet(shapeNode.name(), query=True, allUVSetsIndices=True)
                currentUVSet = pm.polyUVSet(shapeNode, query=True, currentUVSet=True )[0]
                for index in indices:
                    if currentUVSet == pm.getAttr('{}.uvSet[{}].uvSetName'.format(shapeNode.name(), index)):
                        pm.uvLink(uvSet='{}.uvSet[{}].uvSetName'.format(shapeNode.name(), index) , texture=ramp)
    
            explicit_name = eTexElement.vray_explicit_name_extratex.get()
            nameTokens = explicit_name.split('_')
            nameTokens[modIndex] = channel
            explicit_name = '_'.join(nameTokens)
            eTexElement.vray_explicit_name_extratex.set(explicit_name)
    
    main()
    

    they key was connecting the ramps to a material assigned to the object. Strangely after the uvLinks are made you can delete the connection between the ramps and the material and the uvLinks still work correctly. I posted this in case someone comes across a similar problem