def create_curve(control):
"""Create a curve.
:param control: A data dictionary generated from the dump function.
:return: The created curve.
"""
periodic = control['form'] == 2
degree = control['degree']
points = control['cvs']
points = points + points[:degree] if periodic else points
curve = cmds.curve(degree=degree, p=points, n=control['name'], per=periodic, k=control['knots'])
cmds.xform(curve, ws=True, matrix=control['xform'])
cmds.xform(curve, piv=control['pivot'])
cmds.delete(curve, constructionHistory=True)
cmds.setAttr('{0}.overrideEnabled'.format(curve), control['overrideEnabled'])
cmds.setAttr('{0}.overrideRGBColors'.format(curve), control['overrideRGBColors'])
cmds.setAttr('{0}.overrideColorRGB'.format(curve), *control['overrideColorRGB'])
cmds.setAttr('{0}.overrideColor'.format(curve), control['overrideColor'])
return curve
python类curve()的实例源码
def create_selected(self):
"""Create the curves selected in the curve list."""
curves = []
sel = cmds.ls(sl=True)
target = sel[0] if sel else None
for item in self.control_list.selectedItems():
text = item.text()
control_file = os.path.join(CONTROLS_DIRECTORY, '{0}.json'.format(text))
fh = open(control_file, 'r')
data = json.load(fh)
fh.close()
curve = create_curve(data)
if target:
cmds.delete(cmds.parentConstraint(target, curve))
curves.append(curve)
if curves:
cmds.select(curves)
def point_at_parameter(curve, t):
return cmds.pointPosition('{}.u[{}]'.format(curve, t))
def compute_knots(num_points, degree, array_typ=list):
'''Compute knots for the given number of points
:param num_points: number of points along curve
:param degree: degree of curve
:param array_typ: Type of array to return
'''
num_knots = num_points + degree - 1
knots = array_typ()
for i in xrange(degree):
knots.append(0)
for i in xrange(num_knots - degree * 2):
knots.append(i + 1)
for j in xrange(degree):
knots.append(i + 2) # exploit leaked reference
return knots
def curve_between(a, b, num_points=24, degree=3, name='curve#'):
'''Create a nurbsCurve between two MVectors
:param a: start of curve
:param b: end of curve
:param num_points: number of points on curve
:param degree: degree of curve
'''
v = b - a
cvs = []
for t in linspace(0, 1, num_points):
cvs.append(a + v * t)
knots = compute_knots(num_points, degree)
curve = cmds.curve(point=cvs, degree=degree, knot=knots)
curve = cmds.rename(curve, name)
curve_shape = cmds.listRelatives(curve, shapes=True)[0]
return curve, curve_shape
def curve_to_hair(curve_shape, hair_system):
curve = cmds.listRelatives(curve_shape, parent=True, f=True)[0]
curve_name = curve.split('|')[-1]
# Create follicle
follicle_shape = cmds.createNode('follicle')
follicle = cmds.listRelatives(follicle_shape, parent=True, f=True)[0]
follicle = cmds.rename(follicle, curve_name + '_follicle#')
follicle_shape = cmds.listRelatives(follicle, shapes=True, f=True)[0]
cmds.connectAttr(curve + '.worldMatrix', follicle_shape + '.startPositionMatrix')
cmds.connectAttr(curve_shape + '.local', follicle_shape + '.startPosition')
# # Create output curve
out_curve_shape = cmds.createNode('nurbsCurve')
out_curve = cmds.listRelatives(out_curve_shape, parent=True, f=True)[0]
out_curve = cmds.rename(out_curve, curve_name + '_out#')
out_curve_shape = cmds.listRelatives(out_curve, shapes=True, f=True)[0]
cmds.connectAttr(follicle + '.outCurve', out_curve_shape + '.create')
# Add follicle to hair system
add_follicle(follicle_shape, hair_system)
return [[follicle, follicle_shape], [out_curve, out_curve_shape]]
def populateCrvField(tfgKey="", *args):
if tfgKey not in ["cntrPivTFBG", "cntrPiv2TFBG", "upLoc2TFBG", "upLocTFBG"]:
sel = cmds.ls(sl=True)
if sel and len(sel)!=1:
cmds.warning("only select the curve you want to rig up!")
else:
if rig.isType(sel[0], "nurbsCurve"):
cmds.textFieldButtonGrp(widgets[tfgKey], e=True, tx=sel[0])
else:
cmds.warning("That's not a curve!")
else:
sel = cmds.ls(sl=True)
if sel and len(sel)!=1:
cmds.warning("only select the object you want to rig up!")
else:
cmds.textFieldButtonGrp(widgets[tfgKey], e=True, tx=sel[0])
if tfgKey == "upLocTFBG":
cmds.textFieldButtonGrp(widgets["upLoc2TFBG"], e=True, tx=sel[0])
if tfgKey == "cntrPivTFBG":
cmds.textFieldButtonGrp(widgets["cntrPiv2TFBG"], e=True, tx=sel[0])
def move_pivot(end, *args):
"""
Args:
end (int): parameter value (0 or 1 from buttons) the point on curve will return, start or end
*args:
"""
check = False
sel = cmds.ls(sl=True, exactType = "transform")
if sel:
for x in sel:
check = rig.isType(x, "nurbsCurve")
if check:
# get curve info
pos = cmds.pointOnCurve(x, parameter = end, position = True)
cmds.xform(x, ws=True, piv=pos)
else:
cmds.warning("{0} is not a nurbsCurve object. Skipping!".format(x))
def align_along_curve(*args):
"""
aligns and objet along a curve at given param
Args:
*args:
Returns:
void
"""
sel = cmds.ls(sl=True, type="transform")
if len(sel) != 2:
cmds.warning("You need to select curve then object to align!")
return()
crv = sel[0]
obj = sel[1]
if not rig.isType(crv, "nurbsCurve"):
cmds.warning("select curve first, THEN object")
return()
param = cmds.floatFieldGrp(widgets["alExFFG"], q=True, v1=True)
rig.align_to_curve(crv, obj, param)
def applyBrush(curve, parent):
'''
Simply applies the paint effects brush to the curve with the settings we want.
'''
mc.AttachBrushToCurves(curve)
stroke = mc.ls(sl=True)[0]
stroke = mc.parent(stroke,parent)[0]
mc.setAttr(stroke+'.displayPercent',92)
mc.setAttr(stroke+'.sampleDensity',0.5)
mc.setAttr(stroke+'.inheritsTransform',0)
mc.setAttr(stroke+'.translate',0,0,0)
mc.setAttr(stroke+'.rotate',0,0,0)
return stroke
def create_orient_manipulator(joint, material):
joint_scale = cmds.jointDisplayScale(query=True)
joint_radius = cmds.getAttr('{0}.radius'.format(joint))
radius = joint_scale * joint_radius
children = cmds.listRelatives(joint, children=True, path=True)
if children:
p1 = cmds.xform(joint, q=True, ws=True, t=True)
p1 = OpenMaya.MPoint(*p1)
p2 = cmds.xform(children[0], q=True, ws=True, t=True)
p2 = OpenMaya.MPoint(*p2)
radius = p1.distanceTo(p2)
arrow_cvs = [[-1, 0, 0], [-1, 2, 0], [-2, 2, 0], [0, 4, 0], [2, 2, 0], [1, 2, 0], [1, 0, 0], [-1, 0, 0]]
arrow_cvs = [[x[0]*radius, x[1]*radius, x[2]*radius] for x in arrow_cvs]
shape = cmds.curve(name='{0}_zForward'.format(joint), degree=1, point=arrow_cvs)
# shape = cmds.sphere(n='{0}_zForward'.format(joint), p=(0, 0, 0), ax=(0, 0, -1), ssw=0, esw=180, r=radius, d=3, ut=0, tol=0.01, s=8, nsp=4, ch=0)[0]
# cmds.setAttr('{0}.sz'.format(shape), 0)
# cmds.select(shape)
# cmds.hyperShade(assign=material)
group = cmds.createNode('transform', name='{0}_grp'.format(shape))
cmds.parent(shape, group)
cmds.makeIdentity(shape, apply=True)
cmds.addAttr(shape, longName=MESSAGE_ATTRIBUTE, attributeType='message')
cmds.connectAttr('{0}.message'.format(joint), '{0}.{1}'.format(shape, MESSAGE_ATTRIBUTE))
for attr in ['tx', 'ty', 'tz', 'ry', 'rz', 'v']:
cmds.setAttr('{0}.{1}'.format(shape, attr), lock=True, keyable=False)
return group, shape
def create_arrow(jointName):
curve = cmds.curve(name='%s_ForwardDirection' % jointName, degree=1, point=[(-1, 0, 0), (-1, 2, 0), (-2, 2, 0), (0, 4, 0), (2, 2, 0), (1, 2, 0), (1, 0, 0), (-1, 0, 0)])
group = cmds.group()
cmds.xform(objectSpace=True, pivots=(0, 0, 0))
jointScale = cmds.jointDisplayScale(query=True)
jointRadius = cmds.getAttr('%s.radius' % jointName)
jointScale *= jointRadius
cmds.xform(scale=(jointScale, jointScale, jointScale))
return group
def create_curves(curves):
for curve in curves:
create_curve(curve)
# Now parent the curves
for curve in curves:
if curve.get('parent'):
parent = curve['parent']
if cmds.objExists(parent):
cmds.parent(curve['name'], parent)
# Then create the stacks
for curve in curves:
if curve.get('stack'):
create_transform_stack(curve['name'], curve['stack'])
def get_knots(curve):
"""Gets the list of knots of a curve so it can be recreated.
:param curve: Curve to query.
:return: A list of knot values that can be passed into the curve creation command.
"""
curve = shortcuts.get_shape(curve)
info = cmds.createNode('curveInfo')
cmds.connectAttr('{0}.worldSpace'.format(curve), '{0}.inputCurve'.format(info))
knots = cmds.getAttr('{0}.knots[*]'.format(info))
cmds.delete(info)
return knots
def remove_selected(self):
"""Remove the curves selected in the curve list from the curve library."""
items = self.control_list.selectedItems()
if items:
button = QtWidgets.QMessageBox.question(self, 'Remove Controls',
'Are you sure you want to remove the selected controls?',
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
if button == QtWidgets.QMessageBox.Yes:
for item in items:
text = item.text()
control_file = os.path.join(CONTROLS_DIRECTORY, '{0}.json'.format(text))
os.remove(control_file)
self.populate_controls()
def _createCurve(name, angle, cvs, parent):
node = cmds.curve(d=1, p=cvs)
cmds.parent(node, parent)
name += '_n%03d' if angle < 0. else '_p%03d'
cmds.rename(node, name % abs(round(angle)))
return node
def get_curve_info(curve):
spans = cmds.getAttr(curve + '.spans')
degree = cmds.getAttr(curve + '.degree')
form = cmds.getAttr(curve + '.form')
cvs = spans + degree
return cvs, spans, degree, form
def average_curves(*curves):
cvs, spans, degree, form = get_curve_info(curves[0])
points = [cmds.getAttr(curve + '.cv[*]') for curve in curves]
if not all(len(points[0]) == len(curve_points) for curve_points in points):
raise Exception('Input curves need to have the same number of cvs')
averaged = [[0, 0, 0] for i in xrange(len(points[0]))]
for curve_points in points:
for point in curve_points:
averaged[0] += point[0]
averaged[1] += point[1]
averaged[2] += point[2]
averaged = [pnt / len(points) for pnt in averaged]
return averaged
def graph(fn, params, scale=10, offset=(0, 0, 0)):
'''Graph fn for the provided params'''
points = []
for t in params:
x = t * scale + offset[0]
y = fn(t) * scale + offset[1]
points.append((x, y, offset[2]))
cmds.curve(point=points)
def tangent_at_parameter(curve, t):
return cmds.pointOnCurve(curve, parameter=t, normalizedTangent=True)
def new_strand(hair_system=None):
if not hair_system:
selection = cmds.ls(sl=True, dag=True, leaf=True, type='hairSystem')
if selection:
hair_system = selection[0]
start = om.MVector(0, 0, 0)
end = om.MVector(0, 0, 24)
start_loc = cmds.spaceLocator(name='strand_start#')[0]
end_loc = cmds.spaceLocator(name='strand_end#')[0]
cmds.xform(end_loc, ws=True, translation=end)
tta = cmds.createNode('transformsToArrays')
cmds.connectAttr(start_loc + '.worldMatrix', tta + '.inTransforms[0].inMatrix')
cmds.connectAttr(end_loc + '.worldMatrix', tta + '.inTransforms[1].inMatrix')
pcc = cmds.createNode('pointCloudToCurve')
cmds.connectAttr(tta + '.outPositionPP', pcc + '.inArray')
expand_grp = cmds.group([start_loc, end_loc], name='strand_expand_grp#')
curve, curve_shape = curve_between(start, end, name='strand_curve#')
cmds.connectAttr(pcc + '.outCurve', curve_shape + '.create')
root_grp = cmds.group(empty=True, name='strand_grp#')
cmds.parent([expand_grp, curve], root_grp)
follicle_nodes, out_curve_nodes = add_curve_to_system(curve_shape, hair_system)
follicle_shape = follicle_nodes[1]
cmds.setAttr(follicle_shape + '.pointLock', 3)
cmds.setAttr(follicle_shape + '.sampleDensity', 24)
def add_curves_to_hair_system():
sel = cmds.ls(sl=True, dag=True, leaf=True, long=True)
if len(sel) < 2:
cmds.warning('Select a bunch of curves and a hairSystem node.')
return
curves = sel[:-1]
hair_system = sel[-1].split('|')[-1]
if cmds.nodeType(hair_system) != 'hairSystem':
cmds.warning(hair_system + ' is not a hairSystem.')
return
for curve in curves:
add_curve_to_system(curve, hair_system)
def passToExecute(*args):
lowResCurves = []
highResCurves = []
secCheck = cmds.checkBoxGrp(widgets["secondCBG"], q=True, v1=True)
name = cmds.textFieldGrp(widgets["nameTFG"], q=True, tx=True)
# get values from UI
#---------------- check that num is greater than 3, IN FACT MAKE SURE IT IS ODD
num = cmds.intFieldGrp(widgets["numCtrlIFG"], q=True, v1=True)
centerLoc = cmds.textFieldButtonGrp(widgets["cntrPivTFBG"], q=True, tx=True)
firstCrv = cmds.textFieldButtonGrp(widgets["upCrvTFBG"], q=True, tx=True)
firstNameSuf = cmds.textFieldGrp(widgets["upNameTFG"], q=True, tx=True)
firstName = "{0}_{1}".format(name, firstNameSuf)
if num and name and centerLoc and firstCrv and firstName:
curveJntRigExecute(num, centerLoc, firstCrv, firstName, crvType="up")
else:
cmds.warning("Some fields weren't filled out for the first curve! Undo and try again!")
return
if secCheck:
secondCrv = cmds.textFieldButtonGrp(widgets["downCrvTFBG"], q=True, tx=True)
secondNameSuf = cmds.textFieldGrp(widgets["downNameTFG"], q=True, tx=True)
secondName = "{0}_{1}".format(name, secondNameSuf)
if num and centerLoc and secondCrv and secondName:
curveJntRigExecute(num, centerLoc, secondCrv, secondName, crvType="down")
else:
cmds.warning("Some fields weren't filled out for the second curve! Undo and try again!")
return
def get_curve(*args):
sel = cmds.ls(sl=True)
crv = ""
if sel and len(sel) == 1:
check = rig.isType(sel[0], "nurbsCurve")
if not check:
cmds.warning("Must select one curve object!")
return
else:
cmds.warning("Must select one curve object!")
return
crv = sel[0]
cmds.textFieldButtonGrp(widgets["curveTFBG"], e=True, tx = crv)
def calculate_pts(crv, *args):
"""
uses the window to get the number of pts that should be in the curve
"""
mode = cmds.radioButtonGrp(widgets["methodRBG"], q=True, sl=True)
if mode == 1:
cLen = cmds.arclen(crv, ch=False)
perUnit = cmds.floatFieldGrp(widgets["recoFFG"], q=True, v1=True)
total = int(cLen * perUnit)
if mode == 2:
total = cmds.intFieldGrp(widgets["totalIFBG"], q=True, v1=True)
# print "curve = {0}, total = {1}".format(crv, total)
return total
def rebuildCurve(curve="", num=5, keep=False, ch=False, name="", *args):
"""
rebuilds curve (checks validity, min cvs, keep/history, etc)
Args:
curve (string): a valid nurbs curve
num (int): int number of pts
keep (bool): whether to keep original
ch (bool): whether to keep history
name (string): name of new curve (left blank will try to keep orig name)
Returns:
string: the name of the created curves (could be same as original!)
"""
newCurve = ""
if curve:
if isType(curve, "nurbsCurve"):
if not name:
name = curve
if not keep or not ch:
ch = False
if num < 3:
num = 3
newCurve = cmds.rebuildCurve(curve, rebuildType = 0, spans = num, keepRange = 0, replaceOriginal=not keep, name = name, ch=ch)[0]
return newCurve
def smartClose(*args):
name = cmds.textFieldGrp(widgets["nameTFG"], q=True, tx=True)
upSuf = cmds.textFieldGrp(widgets["upNameTFG"], q=True, tx=True)
dwnSuf = cmds.textFieldGrp(widgets["downNameTFG"], q=True, tx=True)
topMidCtrl = ctrlsUp[len(ctrlsUp)/2]
downMidCtrl = ctrlsUp[len(ctrlsDown)/2]
if len(lowResCurves)==2 and len(highResCurves)==2:
tmpCloseLow = cmds.duplicate(lowResCurves[0], n="{0}_closeLowTmpCrv".format(name))[0]
cmds.parent(tmpCloseLow, w=True)
tmpLowBS = cmds.blendShape(lowResCurves[0], lowResCurves[1], tmpCloseLow)[0]
tmpLowUpAttr = "{0}.{1}".format(tmpLowBS, lowResCurves[0])
tmpLowDwnAttr = "{0}.{1}".format(tmpLowBS, lowResCurves[1])
cmds.setAttr(tmpLowUpAttr, 0.5)
cmds.setAttr(tmpLowDwnAttr, 0.5)
closeLow = cmds.duplicate(tmpCloseLow, n="{0}_CLOSE_LOW_CRV".format(name))[0]
cmds.delete([tmpCloseLow, tmpLowBS])
lowBS = cmds.blendShape(lowResCurves[0], lowResCurves[1], closeLow)[0]
lowUpAttr = "{0}.{1}".format(lowBS, lowResCurves[0])
lowDwnAttr = "{0}.{1}".format(lowBS, lowResCurves[1])
#---------------- connect up down into reverse setup that drives lowclosecrv to go up/down
cmds.addAttr(topMidCtrl, ln="__xtraAttrs__", )
cmds.setAttr(lowUpAttr, 1)
cmds.setAttr(lowDwnAttr, 0)
closeUpHigh = cmds.duplicate(highResCurves[0], n="{0}_HI_{1}_CLOSE_CRV".format(name, upSuf.upper() ))[0]
cmds.parent(closeUpHigh, w=True)
upHighWire = cmds.wire(closeUpHigh, en=1, gw=True, ce=0, li=0, w=closeLow, name = "{0}_CLS_UP_WIRE".format(name))[0]
wireUpBaseCrv = "{0}BaseWire".format(closeLow)
cmds.setAttr("{0}.scale[0]".format(upHighWire), 0)
#---------------- set up blend shape on high res curve (drive high res with wire driven curve)
#---------------- set up the center ctrl to drive this BS
cmds.setAttr(lowUpAttr, 0)
cmds.setAttr(lowDwnAttr, 1)
closeDwnHigh = cmds.duplicate(highResCurves[1], n="{0}_HI_{1}_CLOSE_CRV".format(name, dwnSuf.upper() ))[0]
cmds.parent(closeDwnHigh, w=True)
dwnHighWire = cmds.wire(closeDwnHigh, en=1, gw=True, ce=0, li=0, w=closeLow, name = "{0}_CLS_DWN_WIRE".format(name))[0]
wireDwnBase = "{0}BaseWire".format(closeLow)
cmds.setAttr("{0}.scale[0]".format(dwnHighWire), 0)
#---------------- set up blend shape on high res curve (drive high res with wire driven curve)
#---------------- set up the center ctrl to drive this BS
def create_line(uniform = True, *args):
"""
gets info from win to create nurbs curve along an axis
Args:
uniform (bool): whether the parameterization should be uniform (even), which makes the points not even
"""
axis = cmds.radioButtonGrp(widgets["lineAxisRBG"], q=True, sl=True)
length = cmds.floatFieldGrp(widgets["lineLenFFG"], q=True, v1=True)
density = cmds.floatFieldGrp(widgets["lineDenFFG"], q=True, v1=True)
numCvs = length * density
if numCvs < 3.0: # curve needs 3 cvs (for 3 dg curve)
numCvs = 3.0
cvDist = length/numCvs
# make a list of pt dist along some axis
axisList = []
for x in range(0,int(numCvs)+1):
axisList.append(x)
pts = []
if axis == 1:
for y in range(0, int(numCvs)+1):
pt = [axisList[y]*cvDist, 0, 0]
pts.append(pt)
if axis == 2:
for y in range(0, int(numCvs)+1):
pt = [0, axisList[y]*cvDist, 0]
pts.append(pt)
if axis == 3:
for y in range(0, int(numCvs)+1):
pt = [0, 0, axisList[y]*cvDist]
pts.append(pt)
line = cmds.curve(name = "line_01", d=3, p=pts)
shp = cmds.listRelatives(line, s=True)[0]
cmds.rename(shp, "{0}Shape".format(line))
if uniform:
line = cmds.rebuildCurve(line, rebuildType = 0, spans = 0, keepRange = 0, replaceOriginal=True, end=1, keepControlPoints=0)[0]
cmds.select(line, r=True)
def curve_through_selection(*args):
"""
creates a curve through the selection, hopefully in order
Args:
None
Returns:
string, name of curve created
"""
sel = cmds.ls(sl=True, fl=True)
if not sel or len(sel)==1:
cmds.warning("You need to select multiple things to create curve through!")
return()
pList = []
crvType = cmds.radioButtonGrp(widgets["crvSelRBG"], q=True, sl=True)
for obj in sel:
if cmds.objectType(obj) in ["transform"]:
pos = cmds.xform(obj, q=True, ws=True, rp=True)
pList.append(pos)
elif obj in cmds.filterExpand(sm=[28, 30, 31, 32, 34, 46]):
pos = cmds.pointPosition(obj)
pList.append(pos)
#add points if only 2 (cv, ep) or 3 (cv) are given, and create the curve
if crvType == 1:
if len(pList) == 2:
f = [float(sum(x)/2) for x in zip(*pList)]
pList.insert(1, f)
vec1 = [pList[1][0]-pList[0][0], pList[1][1]-pList[0][1], pList[1][2]-pList[0][2]]
newPt1 =[pList[0][0] + (vec1[0]*0.05), pList[0][1] + (vec1[1]*0.05), pList[0][2] + (vec1[2]*0.05)]
vec2 = [pList[1][0] - pList[2][0], pList[1][1] - pList[2][1], pList[1][2] - pList[2][2]]
newPt2= [pList[2][0] + (vec2[0]*0.05), pList[2][1] + (vec2[1]*0.05), pList[2][2] + (vec2[2]*0.05)]
pList.insert(1, newPt1)
pList.insert(3, newPt2)
if len(pList) == 3:
vec1 = [pList[1][0]-pList[0][0], pList[1][1]-pList[0][1], pList[1][2]-pList[0][2]]
newPt1 =[pList[0][0] + (vec1[0]*0.05), pList[0][1] + (vec1[1]*0.05), pList[0][2] + (vec1[2]*0.05)]
vec2 = [pList[1][0] - pList[2][0], pList[1][1] - pList[2][1], pList[1][2] - pList[2][2]]
newPt2= [pList[2][0] + (vec2[0]*0.05), pList[2][1] + (vec2[1]*0.05), pList[2][2] + (vec2[2]*0.05)]
pList.insert(1, newPt1)
pList.insert(3, newPt2)
crv = cmds.curve(d=3, p=pList, name="newCurve")
if crvType == 2:
if len(pList) == 2:
f = [float(sum(x)/2) for x in zip(*pList)]
pList.insert(1, f)
crv = cmds.curve(d=3, ep=pList, name="newCurve")
return(crv)