gue
Hi, seeing as Soup's copy/transfer attribute features are rather particle centric - from my understanding at least - I am trying to discover a way to copy values between 2 nurbsCurves. Here is the case:

In my grooming workflow guide curves have custom parameters setup on them that influence the simulated fur (eg. deformation radius). When a groom is updated, these guide curves are replaced by a new set of curves, which have different names and only default values in these common/shared attributes. 2 curves only share the same position on the character mesh, so a world space (nurbsCurveShape1.cv[0]) or uv space coordinate/(follicleShape.uparam/vparam).

curveShape10333.innerRadius [0.25] >>> curveShape1.innerRadius [0].

Does soup allow me to copy attribute data between different objects?  Its basically a simple get/setAttr, but requiring a nearest position lookup to define the target curve.

Thanks!
Quote 0 0
pshipkov
Yes, easily.
But i don't think you need much of SOuP really.
What you need is to collect the positions of the first CV of the "old" curves and store them into vector array.
Then do the same with the new set of curves.
Then run proximity check on them and find the closest pairs between them.
The get/setAttr between them.

if you have a minimal Maya scene with the couple of "old" and "new" curves i can provide you the few lines of code that will take care of it, in case tech problems like that are not your forte.
Quote 0 0
gue
Hello Peter,

great, simpler than expected. Thanks for you help! Can you please elaborate the proximity check for me, or point out the node/object that handles this?

Am still curious as how to achieve this using soup itself, as I'd like to understand such basics better, so far haven't noodled anything meaningful together... But to follow up you suggestion, here is my reply to the pythonic approach, including a test scene containing two curves with attributes on both Shapes (roots positioned on a sphere).

Quote:
Then run proximity check on them and find the closest pairs between them.


"Elegant' proximity checking is the only thing I am not yet familiar with in Maya, ie. how to script the nearest point evaluation part using a function that has this built-in. Only know of a direct 'if condition'  B == A of the actual two point position values in the 2 lists, say rounded to the third floating point value. Is there a node/maya object to handle this comparison instead? Similar to Houdini's copy (by nearest point) node?

This is a simple start to saving the point positions for the test scene supplied. I'd add code to create a second list of the new curves .cv[0] positions (vector array). In an if loop compare if curveB pos == curveA pos, if condition is met, setAttr A->B.

You can ignore this half baked script part if you want, it needs some improvements 🙂

Thanks again,
Jan


Code:
''' 1 - save old root positions for curvesA cv[0] list '''
from maya import cmds
curvesA = cmds.ls(sl=True)
rootCvListA = list()
for c in curvesA:
    getRootCv = cmds.ls("%s.cv[0]" %c, fl=1)
    ''' using cmds.xform, could use cmds.pointPosition just the same '''
    rootCvPositionA = cmds.xform(getRootCv, q=True, ws=True, t=True)
    rootCvListA.append(rootCvPositionA)

''' 2 - same code as above for new root positions on curvesB list'''
curvesB = cmds.ls(sl=True)
''' as above etc etc '''

''' 3  - temp code: a loop setting the attr, to do: better rounding formatting for the if condition, exception handling if list len differs, etc '''
for i in rootCvListA:
    if rootCvListB[i] == rootCvListA:
        cmds.setAttr('%s.deformationRadius' %curvesB[i], '%s.deformationRadius' %curvesA[i])
Quote 0 0
pshipkov
Code:

import maya.cmds as mc
import maya.OpenMaya as om

def transfer():
    # source and target curves
    src = mc.ls("src*", typ="nurbsCurve") or []
    tgt = mc.ls("tgt*", typ="nurbsCurve") or []

    # source points (cv[0])
    src_cnt = len(src)
    src_pnts = om.MFloatPointArray(src_cnt)
    for i in range(src_cnt):
         x,y,z = mc.pointPosition(src[i]+".cv[0]", w=True)
         src_pnts[i].x = x
         src_pnts[i].y = y
         src_pnts[i].z = z

    # targets points (cv[0])
    tgt_cnt = len(tgt)
    tgt_pnts = om.MFloatPointArray(tgt_cnt)
    for i in range(tgt_cnt):
         x,y,z = mc.pointPosition(tgt[i]+".cv[0]", w=True)
         tgt_pnts[i].x = x
         tgt_pnts[i].y = y
         tgt_pnts[i].z = z

    # find the closest pairs
    for i in range(src_cnt):
        idx = None
        dst = 999999999.9
        for j in range(tgt_cnt):
            dst2 = src_pnts[i].distanceTo(tgt_pnts[j])
            if dst2 < dst:
                idx = j
                dst = dst2

        # copy source.influenceRadius to target.influenceRadius
        mc.setAttr(tgt[idx]+".influenceRadius", mc.getAttr(src[i]+".influenceRadius"))
transfer()
Quote 0 0
gue
Hi Peter,

thank you very much for this solution, your help is very inspiring! Tried it out on 10,000 curves and took around 102 seconds. I will be getting more into openMaya for my future component wrangling.

Will post the additions to this script when I have it ready. Planned are options to define 2 curve sets as inputs, array length mismatch handling, and a .json file dump/read, so this can be included in other scripts (rig builds for example).

We should wrap this thread up here, just asking out of curiosity:  are there any existing SOuP examples that do something similar? Or is it just simpler and more sensible to do this with code?
Quote 0 0
pshipkov
Glad it was helpful.
Keep in mind that my suggestion is based on brute-force approach implemented in Python = slow.
Main goal was simplicity.
There is much faster way to make this happen, but it will require couple of SOuP nodes and a bit more abstract code.
Quote 0 0

Add a Website Forum to your website.