PyMel- Getting texture file from a material

So, my first inelegant-yet-functional PyMel script is done and working. The core of it is in this little snippet here, that digs through a mesh's inputs until it finds the texture node on the surface shader:

#Pass through the mesh's shape and return a texture name. 
import pymel as pm

def getTextureFile(geo):

    sg = []

    #Get the shading group from the selected mesh
    raw_sg = pm.listConnections(geo, type='shadingEngine')

    #Rapidly check for duplicates in the list- I do this by checking each item 
    #against an empty list. 
    #If the item is not in the empty list I append it. 
    
    for element in raw_sg:
        if element not in sg:
            sg.append(element)

    #Get some info
    sgInfo = pm.listConnections(sg[0], type='materialInfo')
    fileNode = pm.listConnections(sgInfo[0], type='file')
    textureFile = pm.getAttr(fileNode[0].fileTextureName)



    print 'This is the file', str(textureFile)
    return str(textureFile)
It still leaves a lot to be desired, for instance it doesn't know what to do if a mesh doesn't actually have a texture! But, provided it does, using the win32com module I can then send the texture file information onto Photoshop and Alienbrain and open files/check out texture chains etc etc.

EDIT:
------------------------------------------------------------------------------------------------------------
Thanks to Daydreamer who pointed out the missing pymel reference at the top of the snippet, as well as other issues with the script which I am working through...

After a happy weekend of actually reading part of the official tutorial, I have a slightly better understanding of how to access a mesh's attributes and nodes using PyMel. Here is a snippet of the above snippet that does pretty much the same thing, only using the pymel connections, input and output commands. The intention is only to test the functionality.
    
    import pymel as pm

    geo = pm.ls(sl=True)[0].getShape()

    #Get the shading group from the selected mesh
    sg = geo.outputs(type='shadingEngine')

    #Work through the node to get the file texture name
    sgInfo = sg[0].connections(type='materialInfo')
    
    #It falls apart here if you have no file node! Oops...
    fileNode = sgInfo[0].connections(type='file')

    #Get the file texture name attribute's value
    textureFile = pm.getAttr(fileNode[0].fileTextureName)

    print 'This is the file', str(textureFile)

4 comments:

  1. Hi Pete,
    nice.....

    but, u can improve this snippet many folds.

    eg.

    In section

    A. # Clean up the list(which looks misleading)
    1. use list comprehension instead of normal loop. it will run faster then normal loop and u dont have to declare sg variable in advance.

    2.it seems u r creating a new list named sg frm raw_sg, u can du thz by using deepcopy function or usin slicing.

    B. #Pass through the mesh's shape and return a texture name. and #Get some info

    1. Where is PyMel??
    just using "pm" doesn't mean PyMel, don't u think if i use "cmds"(python in maya) instead of "pm" it will be exactly the same. where is OOP?

    C. This code will also starts failing if my variables values are None. In simple, if i don't have texture over my selected mesh.
    You need to add checks or validations.

    Need more elaborate discussion, write in to me.
    Or drop comment on my site.


    Regards
    Day Dreamer
    www.daydreamer3d.weebly.com


    ReplyDelete
    Replies
    1. Hi Day Dreamer, thanks for your comment! I've not used list comprehension before, I will have to look into it! My intention with that section of code is to remove any duplicate items. It's a bit of a dirty way of doing it, so if list comprehension is faster + cleaner I'm all for it!

      B.1 - Bad copy paste on my part, I use "import pymel as pm" as my pymel reference and it was missing from the start of the snippet, fixed now! Thanks for pointing it out!

      You are correct that the script totally falls flat if there are no textures assigned to a given mesh, which is a *major* flaw. Some checks would be the logical next step.

      In the #Get some info, I must admit I'm pretty (extremely) new at Pymel- is this the way you would normally query for a texture file, or is there a simpler/more direct way?

      Delete
  2. # Note:- ____ means whitespaces

    import pymel as pm

    # Check selection
    sel = pm.ls(sl=True)
    if not sel:
    ____print 'Selection is empty. Kindly select a geometry.'
    ____# if under function return here

    # Assuming you are interested in single selected object
    # (generally, i prefer last selected object, Maya Way)
    # re-defying "sel" variable with just last object
    sel = sel[-1]

    geo = sel.getShape()

    # Checking selected object is a mesh(shape)
    if not geo:
    ____print 'No Shape Found For %s' % sel
    ____# if under function return here

    #Get the shading group from the selected mesh
    sg = geo.outputs(type='shadingEngine')
    if not sg:
    ____print 'No Shading Engine Exists For %s' % geo
    ____# return here

    #Work through the node to get the file texture name
    sgInfo = sg[0].connections(type='materialInfo')

    #It falls apart here if you have no file node! Oops...
    fileNode = sgInfo[0].connections(type='file')
    if not fileNode:
    ____print 'No Texture Exists For %s' % geo
    ____# return here

    #Get the file texture name attribute's value
    #textureFile = pm.getAttr(fileNode[0].fileTextureName)
    textureFile = fileNode[0].fileTextureName.get()

    if not textureFile:
    ____print 'No Texture Path Found For:-\n\t\tShape:- {0}\n\t\tTexture:- {1}'.format(geo, fileNode[0])
    ____return here

    print 'This is the file %s' % textureFile

    ReplyDelete
  3. Why not remove duplicates in your list by simply doing a my_list = list(set(my_list))

    -Sven

    ReplyDelete

Comments?