Maya API: best way to get name from created polygon?

I’ve just started dipping my toes in the Maya API. I followed a tutorial about creating a polygon from points in space. I’m just wondering what’s the best way to actually select the transform after creation. Or to assign the lambert shader?

Right now I’m just accessing the name and creating a PyMEL object of it. With a module I have, I then run “assignLambert” to assign the Lambert shader to it.

# build polygon from locators
locators = pm.ls(sl=1)
coords = []
for loc in locators:
    coords.append(om.MPoint(loc.getTranslation(space='world')) )
    

meshFn = om.MFnMesh()
mergeVertices = 1
pointTolerance = 0.001

faceArray = om.MPointArray()
faceArray.setLength(4)
faceArray.set(coords[0], 0)
faceArray.set(coords[1], 1)
faceArray.set(coords[2], 2)
faceArray.set(coords[3], 3)

meshFn.addPolygon(faceArray, mergeVertices, pointTolerance)
pm.select(pm.ls(meshFn.name())[0].getTransform(), r=1)
dag_shaderUtils.assignLambert()

Selection is easy. Just use MGlobal::setActiveSelectionList.

That said, the API is not a replacement for MEL. The API is how you write brand new things to do with MEL.

Many other things that are easy to do in MEL are annoying to do in the API. Assigning shaders is one of those things because you lose all the automation you’re used to in the UI. And since there are already MEL commands to do that, the best way to handle that is to just use MEL.

I hate how Google still brings up Maya2011 api in search results, but it’s still relevant:
https://download.autodesk.com/us/maya/2011help/API/cgfx_attr_def_8cpp-example.html#a94

This drops you into a setTexture function, and you can see some of the comments like:

// Use the MEL commands (as opposed to dgMod.createNode) as these
// correctly hook up the rendering message connections so our 
// nodes show up in the hypershade etc.

So in their own examples, they just drop out to MEL to do that stuff.

2 Likes

Aha, very nice. Thanks a lot.

Everything is much easier.

For MFnMesh, a function is available to return the name to a string representation: fullPathName
Returns the full path of the attached object, from the root of the DAG on down.

Inherited from: MFnDagNode

https://help.autodesk.com/view/MAYAUL/2022/ENU/?guid=Maya_SDK_py_ref_class_open_maya_1_1_m_fn_dag_node_html

To assign a material to an object, you do not need to first select that object.
You will need to specify the name of the mesh, or the names of the specific polygons to which you want to assign the desired material.


import maya.api.OpenMaya as om
import maya.cmds as cmds

# For example, let's create a new mesh consisting of two triangular polygons
# (adding polygons in turn):

vertArray = om.MPointArray()
vert_point = [(0,0,0,1),(1,0,0,1),(1,0,1,1),(0,0,1,1)]

mesh_DG_name = om.MFnMesh()

# Create the first polygon for points: 0, 3, and 2.
# (with merge Vertices and merge Tolerance = 0.0 )

mesh_DG_name.addPolygon( vertArray.copy( map(vert_point.__getitem__, [0,3,2]) ), 1, 0.0 )

# Create a second polygon for points: 2, 1, and 0

mesh_DG_name.addPolygon( vertArray.copy( map(vert_point.__getitem__, [2,1,0]) ), 1, 0.0 )

# Obviously, we are building all polygons counter-clockwise,
# this determines the direction of the normal for the polygon.
# If we tried to build the second polygon in a clockwise direction,
# it would mean generating a little bit of geometry.
# Since we specified the merge for vertices with the same coordinates in the construction options,
# the polygons must have a common edge, but the normals must look in different directions.
# Maya does not allow you to create nonmanifold geometry.
# Therefore, the creation of the second polygon would be ignored.

# Next, get the name of the created mesh

mesh_fullPathName = mesh_DG_name.fullPathName()


# shape_name = mesh_DG_name.absoluteName()
# transform_name = mesh_DG_name.fullPathName().split('|')[1]


# Turn ON the display of materials and textures:

for item in ['modelPanel1', 'modelPanel2', 'modelPanel3', 'modelPanel4']:
    cmds.modelEditor(item, edit = True,
                           dtx = 1, # display textures
                           cme = 1, # colormanagement
                           ocl = 0, # display oclusion culling
                       shadows = 0, # display shadows
                           swf = 1, # smoth wireframe
                            tx = 1, # display textures objects
                           udm = 0, # use default material
                           wos = 1, # wireframe on shaded
                            xr = 0) # XRay on/off


# Let's get closer:

cmds.viewFit( mesh_fullPathName, animate = True, allObjects = True )

# 1. Assign the default Lambert shader for the entire mesh ( initialShadingGroup ):

cmds.sets( mesh_fullPathName, edit = True, forceElement = 'initialShadingGroup' )

# Or just for some polygons:

cmds.sets(mesh_fullPathName + '.f[1]', e = 1, forceElement = 'initialShadingGroup')


# 2. Let's create a new Lambert material (or any other Shader):

# Create the Lambert material:

MY_LAMBERT_SHADER = cmds.shadingNode( 'lambert', asShader = True, name = 'MY_LAMBERT_MATERIAL' )

#Creating a SHADING ENGINE:

MY_SHADING_ENGINE = cmds.sets( renderable = True, noSurfaceShader = True, empty = 1, name = ( MY_LAMBERT_SHADER + '_SG' ) )

# We connect the resulting Lambert material with the input slot for the surface material:

cmds.connectAttr( MY_LAMBERT_SHADER + '.outColor', MY_SHADING_ENGINE + '.surfaceShader' )

# Set purple colot from attribute "color" for Lambert material:

cmds.setAttr(MY_LAMBERT_SHADER + '.color', 1.0, 0.0, 1.0, type = 'double3')

# Let's assign this new material:

cmds.sets( mesh_fullPathName, edit = True, forceElement = MY_SHADER_SG )

# Let's create and assign a chesker to the color chanel:

# create chesker:

MY_CHECKER = cmds.shadingNode('checker', asTexture = 1, name = 'MY_ERROR_CHECKER')
cmds.setAttr(MY_CHECKER + '.color1', 0.0, 0.0, 0.0, type = 'double3')
cmds.setAttr(MY_CHECKER + '.color2', 1.0, 0.0, 1.0, type = 'double3')

# create tex2dPlacement for chesker:
MY_CHECKER_tex2dPlacement = cmds.shadingNode("place2dTexture", asUtility = True, name = 'place2dTex__for_' + MY_CHECKER)
cmds.setAttr(MY_CHECKER_tex2dPlacement + '.ihi', 0)
cmds.setAttr(MY_CHECKER_tex2dPlacement + '.repeatU', 4)
cmds.setAttr(MY_CHECKER_tex2dPlacement + '.repeatV', 4)

# we conect tex2dPlacement  with chesker:

cmds.connectAttr(MY_CHECKER_tex2dPlacement + '.outUV', MY_CHECKER + '.uvCoord')
cmds.connectAttr(MY_CHECKER_tex2dPlacement + '.outUvFilterSize', MY_CHECKER + '.uvFilterSize')

# we conect chesker  with shader color chanel:

cmds.connectAttr(MY_CHECKER + '.outColor', MY_LAMBERT_SHADER + '.color')

# Whoops... we don't see a checker on polygons.
# That's because polygons don't have UV coordinates!
# Let's fix:

# Requesting the name of the current UV set:

curent_UVset_name = mesh_DG_name.getUVSetNames()[-1]

# set UVs:

mesh_DG_name.setUVs( (0.0, 1.0, 1.0, 0.0), (0.0, 0.0, 1.0, 1.0), curent_UVset_name )

# assign UVs:

mesh_DG_name.assignUVs((3,3),(0,3,2,2,1,0),curent_UVset_name)

# Voila!

# Let's try to connect the texture file instead of the checker:
# We will use a texture file from standard Maya.

# Get Maya installation path:
import os
maya_pth = sl_g_maya_dir = str(os.environ['MAYA_LOCATION'])
img_pth = maya_pth + '/brushImages/hotelFacade.jpg'

# Let's create a function to create a file node along with a place2dTexture node
# from the specified path

def createFileTexture(filename, nodename, colorManagement = True):

    file_nodename = 'file__' + nodename
    tex2d_nodename = 'place2dTex__' + nodename

    # Create file node:

    texFile = cmds.shadingNode('file', name = file_nodename , asTexture = True, isColorManaged = colorManagement)
    cmds.setAttr(texFile + '.uvTilingMode', 0)

    # from the specified path

    cmds.setAttr(texFile + '.fileTextureName', filename, type = 'string')

    # Create a place2dTexture node and connect it to the file node

    tex2dPlacement = cmds.shadingNode('place2dTexture', name = tex2d_nodename, asUtility = True)
    cmds.connectAttr(tex2dPlacement + '.outUV', texFile + '.uvCoord')
    cmds.connectAttr(tex2dPlacement + '.outUvFilterSize', texFile + '.uvFilterSize')
    cmds.connectAttr(tex2dPlacement + '.vertexCameraOne', texFile + '.vertexCameraOne')
    cmds.connectAttr(tex2dPlacement + '.vertexUvThree', texFile + '.vertexUvThree')
    cmds.connectAttr(tex2dPlacement + '.vertexUvTwo', texFile + '.vertexUvTwo')
    cmds.connectAttr(tex2dPlacement + '.vertexUvOne', texFile + '.vertexUvOne')
    cmds.connectAttr(tex2dPlacement + '.repeatV', texFile + '.repeatV')
    cmds.connectAttr(tex2dPlacement + '.repeatU', texFile + '.repeatU')
    cmds.connectAttr(tex2dPlacement + '.rotateFrame', texFile + '.rotateFrame')
    cmds.connectAttr(tex2dPlacement + '.offsetV', texFile + '.offsetV')
    cmds.connectAttr(tex2dPlacement + '.offsetU', texFile + '.offsetU')
    cmds.setAttr(tex2dPlacement + '.ihi', 0)

    return texFile, tex2dPlacement

# Run the function:

create_texture = createFileTexture(img_pth, 'albedo', colorManagement = True)

# Disconnect the checker node from the color channel:

cmds.disconnectAttr(MY_CHECKER + '.outColor', MY_LAMBERT_SHADER + '.color')

# We connect the node file with the color channel:

cmds.connectAttr(create_texture[0] + '.outColor', MY_LAMBERT_SHADER + '.color')

:slight_smile:

1 Like

Very nice. Thanks a lot.