[MAYA][PYTHON] Area Lights per selected face - critique

Hi all

Really should get a bit more active on here! Figure I’m going to start putting more stuff up for open critique so I can get better. My knowledge is pretty functional, and I’m now getting pretty comfortable with python but I wonder if I’m picking up a lot of bad habits and I’m sure I can be so much more efficient!

So here’s a starter.
One of our lighting guys wanted to be able to generate Area Lights per polygon of his selected object, and have the area lights match up the size of the polygon.

Here’s a quick vid of it working

Cheers :slight_smile:

Luke

from maya import cmds
import math

#CREATES AREA LIGHTS THAT MATCHES POLYGONS

#GET FACES
def areaLightFaceMatch( sel = cmds.ls(selection = True) ):

    for face in sel: #If faces are in slice we'll iterate through those 
        if ':' in face:
            faceShape = face.split('.f')[0] #Get object shape name

            faceNums = face.split( '[' )[-1]
            faceNums = faceNums.split( ']' )[0]

            sRange = int(faceNums.split(':')[0]) # Start Range
            eRange = int(faceNums.split(':')[-1]) # end Range

            i = sRange

            while i <= eRange:
                faceAreaLight('{0}.f[{1}]'.format(faceShape, i))
                i += 1

        else:
            faceAreaLight( face )

def faceAreaLight( inFace = '' ):

        #Query face positions
        faceLocation = cmds.xform(inFace, query = True, translation = True, worldSpace = True)
        
        #Calculate centre point of face
        avX = 0
        avY = 0
        avZ = 0
        numVerts = 0

        i = 0
        while i < len(faceLocation):
            avX += faceLocation[i]
            avY += faceLocation[i+1]
            avZ += faceLocation[i+2]
            i += 3
            numVerts += 1
    
        avX /= numVerts
        avY /= numVerts
        avZ /= numVerts

        faceCentre = [avX, avY, avZ]

        #Query face normal
        faceNormalQuery = cmds.polyInfo( inFace, faceNormals = True )
        faceNormal = faceNormalQuery[0].split()[2:]

        #Place locators for aim constraint (angle of Light)
        #We want it to face outwards (normal based) so we create a Target locator off the face's normal
        #and an Up Vector locator  at the averate point of one of the edges
        locTarget = cmds.createNode( 'locator' )
        cmds.move(  faceCentre[0] + float(faceNormal[0]), 
                   faceCentre[1] + float(faceNormal[1]),
                   faceCentre[2] + float(faceNormal[2]), 
                   cmds.listRelatives(locTarget, parent = True)[0] )

        locUpVector = cmds.createNode( 'locator' )
        cmds.move(  (faceLocation[0] + faceLocation[3]) / 2, 
                    (faceLocation[1] + faceLocation[4]) / 2, 
                    (faceLocation[2] + faceLocation[5]) / 2, 
                    cmds.listRelatives(locUpVector, parent=True)[0] )

        newLight = cmds.createNode( 'areaLight' )
        newLightTransform = cmds.listRelatives(newLight, parent = True)[0]
        cmds.move( faceCentre[0], faceCentre[1], faceCentre[2], newLightTransform )

        #Create the aim constraint to angle the light, ensuring that maintain offset is turned off (we want it to rotate)
        aimConstraint = cmds.aimConstraint( cmds.listRelatives(locTarget, parent = True)[0], 
                                            newLightTransform,
                                            aimVector = ( 0, 0, -1.0 ),
                                            upVector = ( 0, -1.0, 0 ),
                                            worldUpType = 'object', 
                                            worldUpObject = cmds.listRelatives(locUpVector, parent = True)[0], 
                                            mo = False )

        #SCALE CALCULATIONS
        #We need to scale the light so it matches the polygon.
        #To do this I'm calculating the length of two vectors, from vert 0 to vert 1, and vert 0 to vert 2 (across and up the face)
        vX = (faceLocation[0] - faceLocation[3], faceLocation[1] - faceLocation[4], faceLocation[2] - faceLocation[5])
        magnitudeX = math.sqrt( (vX[0] * vX[0]) + (vX[1] * vX[1]) + (vX[2] * vX[2]) )

        vY = (faceLocation[0] - faceLocation[6], faceLocation[1] - faceLocation[7], faceLocation[2] - faceLocation[8])
        magnitudeY = math.sqrt( (vY[0] * vY[0]) + (vY[1] * vY[1]) + (vY[2] * vY[2]) )
        
        #I then plug in the vector's magnitudes into the scale attribute directly 
        #(but by half as the area light is already in the centre of the face)
        cmds.setAttr( '{0}.scaleX'.format(newLightTransform), magnitudeX * 0.5 )
        cmds.setAttr( '{0}.scaleY'.format(newLightTransform), magnitudeY * 0.5 )
        cmds.setAttr( '{0}.scaleZ'.format(newLightTransform), 30 )

        #Then we can remove the locators and aim constraint
        cmds.delete( aimConstraint )
        cmds.delete( cmds.listRelatives(locTarget, parent = True)[0] )
        cmds.delete( cmds.listRelatives(locUpVector, parent = True)[0] )