Search code examples
pythonmaya

Creating Hair follicles along a nurbsPlane with Python in Maya for a ribbon Spine?


I achieved the creation of follicles along the nurbsPlane. However, when I connect the OutTranslate attributes to have them move with the vertices, all except the first one move to the end of the plane. Can anyone explain why it is doing this? I am a beginner, so if anything else is weirdly written please tell me so I can improve. Thanks in advance!


import maya.cmds as cmds

listName = ['spine01', 'spine02','spine03', 'spine04','spine05', 'spine06','spine07', 'spine08', 'spine09', 'spine10' ]
planeLength = 45.00 
cmds.select(all=True)
cmds.delete()

cmds.nurbsPlane(p=[planeLength/2,0,0], ax=[0,0,0], w=planeLength, lr=0.1 , d=3, u=9, v=1, n='spineNurbsPlane')
cmds.rotate(0,0,90, 'spineNurbsPlane')
cmds.select(d=True)
cmds.group(em=True, n='follicle_grp')

for i in range( len(listName)):    
    y=str(i+1)
    cmds.createNode( 'follicle', n='follicle'+listName[i])
    cmds.parent('follicle'+y,'follicle_grp', s=True )
    cmds.setAttr('follicle'+listName[i]+'.simulationMethod', 0)
    cmds.makeIdentity('spineNurbsPlane', apply=True, t=1, r=1, s=1, n=0 )

    cmds.connectAttr('follicle'+listName[i]+'.outRotate','follicle'+y+'.rotate', f=True )
    cmds.connectAttr('follicle'+listName[i]+'.outTranslate','follicle'+y+'.translate')
    cmds.connectAttr('spineNurbsPlaneShape.worldMatrix','follicle'+listName[i]+'.inputWorldMatrix')
    cmds.connectAttr('spineNurbsPlaneShape.local','follicle'+listName[i]+'.inputSurface')

    cmds.setAttr( 'follicle'+y+'.parameterV', 0.5)
    cmds.setAttr( 'follicle'+y+'.parameterU', i*5)

Solution

  • The issue are the values you are setting to the follicle's parameterU attribute. This attribute's range is from 0 to 1 (yes you can set above 1, but shouldn't), and you are passing values way beyond 1 that make them all clump together on top.

    Just to illustrate, let's look at a few values you're currently getting with i*5 and replace i with the value from the loop:

    0 * 5  # Outputs 0, puts the follicle on the bottom
    1 * 5 # Outputs 5, already beyond attribute's range and puts it on top
    2 * 5 # Outputs 10, again puts it on top
    3 * 5 # Outputs 15, yup same thing
    .. and so on
    

    So you need to pass a value that makes sense. To remap this so the values are between 0 - 1 you can use this simple formula: loopIndex / (totalFollicleCount - 1). And that's it, that will properly set them along the length of the plane because it'll make the values between 0 - 1. By the way we need to subtract the total length by 1 to get the last follicle to be placed on the very top.

    import maya.cmds as cmds
    
    listName = ['spine01', 'spine02', 'spine03', 'spine04', 'spine05', 'spine06', 'spine07', 'spine08', 'spine09', 'spine10']
    planeLength = 45.00 
    cmds.select(all=True)
    cmds.delete()
    
    cmds.nurbsPlane(p=[planeLength / 2, 0, 0], ax=[0, 0, 0], w=planeLength, lr=0.1 , d=3, u=9, v=1, n='spineNurbsPlane')
    cmds.rotate(0, 0, 90, 'spineNurbsPlane')
    cmds.select(d=True)
    cmds.group(em=True, n='follicle_grp')
    
    for i in range(len(listName)):    
        y = str(i + 1)
        cmds.createNode('follicle', n='follicle' + listName[i])
        cmds.parent('follicle' + y,'follicle_grp', s=True)
        cmds.setAttr('follicle' + listName[i] + '.simulationMethod', 0)
        cmds.makeIdentity('spineNurbsPlane', apply=True, t=1, r=1, s=1, n=0)
    
        cmds.connectAttr('follicle' + listName[i] + '.outRotate', 'follicle' + y + '.rotate', f=True)
        cmds.connectAttr('follicle' + listName[i] + '.outTranslate', 'follicle' + y + '.translate')
        cmds.connectAttr('spineNurbsPlaneShape.worldMatrix', 'follicle' + listName[i] + '.inputWorldMatrix')
        cmds.connectAttr('spineNurbsPlaneShape.local', 'follicle' + listName[i] + '.inputSurface')
    
        cmds.setAttr('follicle' + y + '.parameterV', 0.5)
        cmds.setAttr('follicle' + y + '.parameterU', float(i) / (len(listName) - 1))
    

    Oh and please utilize white-space to make the code more readable otherwise it makes my eyes bleed!