def createSrf(self): #calculate the witdth of the surface as a fraction of the total joint chain length jntChainLength = 0 crvPoints = [] for i in range(1,self.numJnt): pos1 = self.ikJntList[i-1].getTranslation(space='world') crvPoints.append(pos1) pos2 = self.ikJntList[i].getTranslation(space='world') jntChainLength += (pos2 - pos1).length() if i == self.numJnt - 1: crvPoints.append(pos2) jntChainLength = math.ceil(jntChainLength ) self.width = jntChainLength * self.widthMult crv1 = pm.curve(n=self.name + '_crv1',d=1,p=crvPoints) pm.move(crv1,self.width / 2.0,0,0,r=1) pm.parent(crv1,self.mainGrp) crv2 = pm.curve(n=self.name + '_crv2',d=1,p=crvPoints) pm.move(crv2,self.width / -2.0,0,0,r=1) pm.parent(crv2,self.mainGrp) pm.select(cl=1) loftSrf = pm.loft(crv2,crv1,ch=1,u=1,c= 0,ar= 1,d=3,ss= 1,rn=0,po=0,rsn=1,n=self.name + "_srf")[0] rebuiltLoftSrf = pm.rebuildSurface(loftSrf,ch=1, rpo=1, rt=0, end=1, kr=0, kcp=0, kc=0, su=self.numCtrl-1, du=3, sv=0, dv=3, tol=0, fr=0, dir=2 )[0] self.srf = loftSrf pm.parent(self.srf,self.mainGrp)
def create_guideSurface( IdName, listOfJnts ): loftCurves = [] for i in range(2): # duplicate and select hierarchy of joints listOfOffsetJnts = pm.duplicate( listOfJnts, name = 'b_' + IdName +'_offset1', parentOnly = True ) # offset each joint on it's own z-axis for jnt in listOfOffsetJnts: if i == 0: pm.move(jnt, (0,0,-0.5), relative = True, objectSpace = True, preserveChildPosition = True) if i == 1: pm.move(jnt, (0,0,0.5), relative = True, objectSpace = True, preserveChildPosition = True) # draw loftcurves loftCurvePoints = [] for each in listOfOffsetJnts: jntPosition = pm.xform(each, q = True, t = True, ws = True) loftCurvePoints.append(jntPosition) loftCurves.append( pm.curve( name = IdName + '_loftCurve' + str(i), degree = 1, point = loftCurvePoints ) ) pm.delete(listOfOffsetJnts) # loft guideSurface guideSurface = pm.loft( loftCurves[0], loftCurves[1], name = IdName + '_guide_surface', ar=True, rsn=True, d=3, ss=1, object=True, ch=False, polygon=0 ) guideSurface = pm.rebuildSurface( guideSurface ,ch=1, rpo=1, rt=0, end=1, kr=1, kcp=0, kc=0, su=0, du=3, sv=1, dv=3, tol=0.01, fr=0, dir=2 ) # cleanup pm.delete( loftCurves ) guideSurface[0].inheritsTransform.set(False) guideSurface[0].overrideEnabled.set(True) guideSurface[0].overrideDisplayType.set(1) # guideSurface[0].visibility.set(False) print('Successfully lofted guide surface. Continuing...') return guideSurface
def buildSrf(self): startJntVec = om.MVector(self.start[0], self.start[1], self.start[2]) endJntVec = om.MVector(self.end[0], self.end[1], self.end[2]) diffVec = endJntVec - startJntVec self.rbnLength = diffVec.length() crvPoints = [] for i in range(self.rbnSegments + 1): vec = startJntVec + diffVec * (i * 1.0 / self.rbnSegments) crvPoints.append([vec.x, vec.y, vec.z]) # pm.spaceLocator(p=[vec.x,vec.y,vec.z]) tmp = pm.curve(n=self.rbnName + '_crv1', d=1, p=crvPoints) crv1 = pm.ls(tmp)[0] crv1.setPivots(self.start) crv2 = pm.duplicate(crv1)[0] self.offsetCrv(crv1, -1.0 * self.rbnWidth / 2) self.offsetCrv(crv2, 1.0 * self.rbnWidth / 2) tmpLoftSrf = \ pm.loft(crv1, crv2, ch=0, u=1, c=0, ar=1, d=1, ss=1, rn=0, po=0, rsn=1, n=self.rbnName + "_lft_srf")[0] rebuiltLoftSrf = \ pm.rebuildSurface(ch=0, rpo=0, rt=0, end=1, kr=1, kcp=0, kc=0, su=0, du=3, sv=0, dv=1, fr=0, dir=2, n=self.rbnName + "_srf")[0] rebuiltLoftSrf.setPivots(rebuiltLoftSrf.c.get()) self.rbnSrf = rebuiltLoftSrf pm.delete(self.rbnSrf, ch=1) pm.delete([crv1, crv2, tmpLoftSrf]) pm.parent(self.rbnSrf, self.rbnTransformGrp)
def CurveLoft(crv, geom, size, norDir, nm): try: crvSh = crv.listRelatives(s=1, type='nurbsCurve')[0] except: pm.warning('%s is not nurbsCurve') return tmpOC = pm.createNode('nearestPointOnCurve', n='TmpOC') crv.ws >> tmpOC.inputCurve copyCrvA = crv.duplicate(n='%sCopyACrv' % crv.name().replace('Crv', ''))[0] copyCrvB = crv.duplicate(n='%sCopyBCrv' % crv.name().replace('Crv', ''))[0] cvSz = int(crv.spans.get()) if crv.d.get() == 3: cvSz = cvSz + 3 upvec = dt.Vector(int(norDir[0]), int(norDir[1]), int(norDir[2])) for i in xrange(cvSz): tmpOC.inPosition.set(crv.cv[i].getPosition(space='world')) tVec = pm.pointOnCurve(crv, pr=tmpOC.parameter.get(), nt=1) cVecA = dt.cross(upvec, dt.Vector(tVec)) cVecB = dt.cross(dt.Vector(tVec), upvec) pm.move(copyCrvA.cv[i], cVecA * size, r=1) pm.move(copyCrvB.cv[i], cVecB * size, r=1) geo = pm.loft(copyCrvB, copyCrvA, ch=1, u=1, c=0, ar=1, d=3, ss=1, rn=0, po=int(geom), rsn=1) mel.eval('DeleteHistory %s' % geo[0].name()) pm.delete(tmpOC, copyCrvA, copyCrvB) return geo[0]
def createSrf(self): # calculate the witdth of the surface as a fraction of the total joint chain length jntChainLength = 0 crvPoints = [] for i in range(1, self.numJnt): pos1 = self.ikJntList[i - 1].getTranslation(space='world') crvPoints.append(pos1) pos2 = self.ikJntList[i].getTranslation(space='world') jntChainLength += (pos2 - pos1).length() if i == self.numJnt - 1: crvPoints.append(pos2) jntChainLength = math.ceil(jntChainLength) self.width = jntChainLength * self.widthMult crv1 = pm.curve(n=self.name + '_crv1', d=1, p=crvPoints) pm.move(crv1, self.width / 2.0, 0, 0, r=1) pm.parent(crv1, self.mainGrp) crv2 = pm.curve(n=self.name + '_crv2', d=1, p=crvPoints) pm.move(crv2, self.width / -2.0, 0, 0, r=1) pm.parent(crv2, self.mainGrp) pm.select(cl=1) loftSrf = pm.loft(crv2, crv1, ch=1, u=1, c=0, ar=1, d=3, ss=1, rn=0, po=0, rsn=1, n=self.name + "_srf")[0] rebuiltLoftSrf = \ pm.rebuildSurface(loftSrf, ch=1, rpo=1, rt=0, end=1, kr=0, kcp=0, kc=0, su=self.numCtrl - 1, du=3, sv=0, dv=3, tol=0, fr=0, dir=2)[0] self.srf = loftSrf pm.parent(self.srf, self.mainGrp)
def createMiddleCrv( curves=[], parameter=0.5 ): ''' update : 2015-04-24 ''' if curves: curves = pm.select(curves) curves = pm.selected() if not curves: raise surface, loft = pm.loft( curves, ch = True, uniform = True, close = False, autoReverse = True, degree = 3, sectionSpans = 1, range = False, polygon=0, # 0: nurbs surface # 1: polygon (use nurbsToPolygonsPref to set the parameters for the conversion) # 2: subdivision surface (use nurbsToSubdivPref to set the parameters for the conversion) # 3: Bezier surface # 4: subdivision surface solid (use nurbsToSubdivPref to set the parameters for the conversion) reverseSurfaceNormals = True ) dupCrv, crvFromSurf = pm.duplicateCurve( surface.getShape().v[ parameter ], ch=True, range=False, local=False ) pm.delete( surface, loft, crvFromSurf ) dupCrv = pm.PyNode( dupCrv ) dupCrv.rename('middleCrv#') return dupCrv
def createRbnSrf(self): startJntVec = om.MVector(self.start[0], self.start[1], self.start[2]) endJntVec = om.MVector(self.end[0], self.end[1], self.end[2]) diffVec = endJntVec - startJntVec # calculate the witdth of the surface as a fraction of the total joint chain length jntChainLength = diffVec.length() self.width = jntChainLength * self.widthMult crvPoints = [] for i in range(self.numCtrl): vec = startJntVec + diffVec * (i * 1.0 / (self.numCtrl - 1)) crvPoints.append([vec.x, vec.y, vec.z]) tmp = pm.curve(n=self.name + '_crv1', d=1, p=crvPoints) crv1 = pm.ls(tmp)[0] crv1.setPivots(self.start) crv2 = pm.duplicate(crv1)[0] self.offsetCrv(crv1, -1.0 * self.width / 2) self.offsetCrv(crv2, 1.0 * self.width / 2) tmpLoftSrf = pm.loft(crv1, crv2, ch=0, u=1, c=0, ar=1, d=3, ss=1, rn=0, po=0, rsn=1, n=self.name + "_tmp")[0] rebuiltLoftSrf = \ pm.rebuildSurface(ch=0, rpo=0, rt=0, end=1, kr=0, kcp=0, kc=0, su=0, du=3, sv=0, dv=1, fr=0, dir=2, n=self.name + "_srf")[0] rebuiltLoftSrf.setPivots(rebuiltLoftSrf.c.get()) self.rbnSrf = rebuiltLoftSrf pm.delete(self.rbnSrf, ch=1) pm.delete([crv1, crv2, tmpLoftSrf]) pm.parent(self.rbnSrf, self.mainGrp)
def build_plane(name=None, crv=None, spans=None, direction='u', width_axis=None, width=1, log=True): '''Given a valid curve, build nurbs plane Attributes: name -- Prefix name for plane. Str crv -- Curve to use as build guide. nt.Transform spans -- Spans for the plane. Int direction -- Build direction. 'u' or 'v' width_axis -- Plane width axis. 'x', 'y' or 'z' width -- Width of plane. Float ''' general.check_type(name, 'name', [str]) general.check_type(crv, 'crv', [pm.nt.Transform]) general.check_type(spans, 'spans', [int]) general.check_type(direction, 'direction', [str]) general.check_type(width_axis, 'width_axis', [str]) general.check_type(width, 'width', [float, int]) if direction not in ['u', 'v']: raise errors.InputError('direction', direction, "'u' or 'v'") if width_axis not in ['x', 'y', 'z']: raise errors.InputError('width_axis', width_axis, "'x', 'y' or 'z'") d1 = crv.duplicate() d2 = crv.duplicate() move_amt = [] if width_axis == 'x': move_amt = [width, 0, 0] elif width_axis == 'y': move_amt = [0, width, 0] elif width_axis == 'z': move_amt = [0, 0, width] if log: str_1 = 'move_amt: ', move_amt general.logging.debug(str_1) pm.move(move_amt[0], move_amt[1], move_amt[2], d1, r=1) pm.move(-move_amt[0], -move_amt[1], -move_amt[2], d2, r=1) p = pm.loft(d1, d2, n=name + '_plane', ch=0)[0] if direction == 'u': pm.rebuildSurface(p, dir=2, su=spans, sv=2) if direction == 'v': pm.rebuildSurface(p, dir=2, sv=spans, su=2) pm.delete(d1) pm.delete(d2) return p
def jntChainToPoly( JntRoots, ch=False, smoothBind=True ): ''' 조인트 체인들에 메쉬를 붙여줌. C:/Program Files/Autodesk/MayaBonusTools2013/scripts/bt_makeJointsDynamicUI.mel 참고할것 ''' curveList = [] for root in JntRoots: root = pm.PyNode(root) chain = root.getChildren( allDescendents=True, type='joint' ) chain.reverse() chain.insert(0,root) curveList.append( jntToCrv( chain, degree=1, ep=False) ) loftedSurface, loft = pm.loft( curveList, ch=1, u=1, c=0, ar=1, d=1, ss=1, rn=0, po=1, rsn=True ) nurbsTessellate = pm.PyNode( loft.outputSurface.outputs()[0] ) nurbsTessellate.polygonType.set(1) # 0.Triangle, 1.Quads nurbsTessellate.setAttr('format', 2) # 0.Count, 1.Fit, 2.General, 3.CVs nurbsTessellate.uType.set(3) # 1.Per Surf # of Isofarms in 3D, 2.Per Surf # of Isofarms, 3.Per Span # of Isofarms nurbsTessellate.vType.set(3) # 1.Per Surf # of Isofarms in 3D, 2.Per Surf # of Isofarms, 3.Per Span # of Isofarms nurbsTessellate.uNumber.set(1) nurbsTessellate.vNumber.set(1) #polyNormalizeUV -normalizeType 1 -preserveAspectRatio off ; if not ch: pm.delete( loftedSurface, ch=True ) pm.delete( curveList ) if smoothBind: pm.select( JntRoots, hi=True ) JNTs = pm.selected( type='joint') pm.skinCluster( JNTs, loftedSurface, toSelectedBones = True, bindMethod = 0, # 0 - Closest distance between a joint and a point of the geometry. # 1 - Closest distance between a joint, considering the skeleton hierarchy, and a point of the geometry. # 2 - Surface heat map diffusion skinMethod = 0, # 0 - classical linear skinning (default). # 1 - dual quaternion (volume preserving), # 2 - a weighted blend between the two normalizeWeights = 1, # 0 - none, # 1 - interactive, # 2 - post (default) maximumInfluences = 1, dropoffRate = 4, removeUnusedInfluence = False, ) for jnt in JNTs: vtx = getClosestVertexOnMesh( loftedSurface, jnt.getTranslation( ws=True ) ) setWeight( [vtx], jnt) return loftedSurface
def bdBuildSrf(self,name): selected = pm.ls(sl=1) if selected: if len(selected) == 1: if selected[0].type() == 'joint': print 'start srf' self.startJnt = selected[0] children = self.startJnt.getChildren(type='joint') print children #need to implement a case with more joint chidren #build the one degree curves for lofting self.endJnt = children[0] startPos1,endPos1 = self.bdGetPos(-0.05) startPos2,endPos2 = self.bdGetPos( 0.05) pm.spaceLocator(p=startPos1) pm.spaceLocator(p=startPos2) pm.spaceLocator(p=endPos1) pm.spaceLocator(p=endPos2) dif1 = (endPos1 - startPos1) dif2 = (endPos2 - startPos2) crv1Points = [] crv2Points = [] for i in range(self.segmentsRbn): pos = dif1 * (i/(self.segmentsRbn*1.0)) + startPos1 crv1Points.append(pos ) pos = dif2 * (i/(self.segmentsRbn*1.0)) + startPos2 crv2Points.append(pos) crv1Points.append(endPos1) crv2Points.append(endPos2) print 'building curve' tmp = pm.curve(n=name + '_crv1',d=1,p=crv1Points) crv1 = pm.ls(tmp)[0] print crv1 #crv1.setScalePivot(startPos1) #crv1.setRotatePivot(startPos1) crv2 = pm.curve(n=name + '_crv2',d=1,p=crv2Points) #crv2.setScalePivot(startPos2) #crv2.setRotatePivot(startPos2) drvGrp = self.bdCreateDrvJnt(crv1,crv2) #loft the curves loftSrf = pm.loft(crv1,crv2,ch=1,u=1,c= 0,ar= 1,d=1,ss= 1,rn=0,po=0,rsn=1,n=name + "_lft_srf")[0] #loftSrf.setScalePivot(startPos2) #loftSrf.setRotatePivot(startPos2) rebuiltLoftSrf = pm.rebuildSurface(ch=1, rpo = 0, rt = 0, end = 1, kr=1, kcp=0,kc=0, su=0, du=3, sv=0, dv=1, fr=0, dir=2 , n=name + "_srf")[0] self.rbnSrf = rebuiltLoftSrf crvGrp = pm.group([crv1,crv2],name=name+'_crv_grp') crvGrp.centerPivots() srfGrp = pm.group([loftSrf,rebuiltLoftSrf],name=name+'_srf_grp') srfGrp.centerPivots() self.rbnGrp = pm.group([crvGrp,srfGrp],n=name+"_grp") pm.parent(drvGrp,self.rbnGrp)
def _createPlane(self, name=None, crv1=None, crv2=None): ''' Plane made by lofting two curves ''' _name = '_createPlane' pymelLogger.info('Started: %s' % _name) plane = pm.loft( crv1, crv2, ch=False, rn=True)[0] plane.rename('%s_plane' % name) pymelLogger.info('Ended: %s' % _name) return plane
def _create_ribbon(self): """Create the ribbon spine based on the guides.""" ribboncrv = pm.curve(p=[ctl.position() for ctl in self.guides.spine], n='%s_%sRibbon_CRV' % (self.side, self.name), d=3) ribboncrv.listRelatives(ad=True)[0].rename('%sShape' % ribboncrv) crva = pm.curve(d=1, p=[ctl.position() for ctl in self.guides.spine]) crvb = crva.duplicate()[0] crva.tx.set(-1) crvb.tx.set(1) nrbname = '%s_%sRibbon_NRB' % (self.side, self.name) loft = pm.loft(crva, crvb, n=nrbname, ch=False)[0] self.ribbon = pm.rebuildSurface(loft, su=0, sv=0, ch=False) pm.delete(crva, crvb)
def create(self,control_count): """Generate hairMesh""" self.control = HairCtrlGrp(num_ctrl=control_count) pm.select(self.control.ctrls) pm.nurbsToPolygonsPref(pt=1, un=4, vn=7, f=2, ut=2, vt=2) hairMesh = pm.loft(n=self.name, po=1, ch=1, u=1, c=0, ar=1, d=3, ss=1, rn=0, rsn=True) self.transform = hairMesh[0] self.transform.addAttr('lengthDivisions', min=1, at='long', dv=self.lengthDivs) self.transform.addAttr('widthDivisions', min=4, at='long', dv=self.widthDivs) self.transform.setAttr('lengthDivisions', e=1, k=1) self.transform.setAttr('widthDivisions', e=1, k=1) self.tesselate = pm.listConnections(hairMesh)[-1] self.transform.connectAttr('widthDivisions', self.tesselate+".uNumber") self.transform.connectAttr('lengthDivisions', self.tesselate+".vNumber") self.shape = self.transform.getShape() self.gen_node = hairMesh[1]
def makeRibbon(jnts=[], axis="z"): if not jnts: jnts = pmc.ls(sl=True) offset = pmc.datatypes.Vector( [float(a == axis.lower()) for a in ["x", "y", "z"]]) curves = [] for j in jnts: if j.type() != "joint": pmc.error("Invalid selection. Select joints only.") pos = j.getTranslation(ws=True) c = pmc.curve(d=1, p=[(pos+offset), (pos-offset)]) curves.append(c) #pmc.skinCluster(j, c, maxInfluences=1) #loft = pmc.loft(curves) loft = pmc.loft(curves, ch=False)[0] pmc.delete(curves) #pmc.skinCluster(jnts, loft, maximumInfluences=1) return loft
def makeSurfFromEdges(name="untitled_SURF_RIG", symVec=None, numSpans=None): """Create a surface based on the selected mesh edges""" sel = getSymSelection() if not sel or len(sel) < 2: pmc.warning("Surface not created. Select two or more mesh edges.") return crv = makeNiceCurveFromEdges(sel, symVec, numSpans) # find distance to offset curve by if crv.form() == "open": surf = makeOpenSurf(crv, sel[0].node(), name) else: crv2 = pmc.duplicate(crv)[0] # loops get scaled pmc.scale(crv, .5, .5, .5) pmc.scale(crv2, 1.5, 1.5, 1.5) surf = pmc.loft(crv, crv2, uniform=True, n=name, ch=0)[0] pmc.delete(crv2) """ # how many spans? if not numSpans: # (x/8)*2 ensures even numSpans rather than /4 numSpans = min(8, (len(sel)/8)*2) # rebuild: u is the lofted direction, v is the length direction # debug time - rebuild can drastically change the curvature. # perhaps there is a better way along the lines of mirroring CVs? # even though neither side is probably great if the rebuild is so # dependant upon seam placement... # or maybe not - was that just a temporary thing from debugging it? # keepCorners=0 to avoid weird UV texture/normal issues pmc.rebuildSurface(surf, rebuildType=0, rpo=1, keepRange=0, dir=2, kc=0, spansU=1, spansV=numSpans, ch=0) """ # determine if its normal is "backwards" - get normal of random vert, # then normal of surf at the closest point to that vert surf = orientSurf(surf, sel) pmc.delete(crv) return surf
def makeRibbon(jnts=None, axis="z"): """create a lofted surface, and kill history... or not? just skin "curves" to joints 1:1?""" if not jnts: jnts = pmc.ls(sl=True) offset = pmc.datatypes.Vector( [float(a == axis.lower()) for a in ["x", "y", "z"]]) curves = [] for j in jnts: if j.type() != "joint": pmc.error("Invalid selection. Select joints only.") pos = j.getTranslation(ws=True) c = pmc.curve(d=1, p=[(pos + offset), (pos - offset)]) curves.append(c) # pmc.skinCluster(j, c, maxInfluences=1) # loft = pmc.loft(curves) loft = pmc.loft(curves, ch=False)[0] pmc.delete(curves) # pmc.skinCluster(jnts, loft, maximumInfluences=1) return loft
def createRbnSrf(self): startJntVec = om.MVector(self.start[0], self.start[1], self.start[2]) endJntVec = om.MVector(self.end[0], self.end[1], self.end[2]) diffVec = endJntVec - startJntVec # calculate the witdth of the surface as a fraction of the total joint chain length jntChainLength = diffVec.length() self.width = jntChainLength * self.widthMult crv1 = pm.duplicate(pm.ls(self.buildCrv)[0])[0] crv1.setPivots(self.start) crv2 = pm.duplicate(crv1)[0] self.offsetCrv(crv1, -0.3 * self.width) self.offsetCrv(crv2, 0.3 * self.width) loftSrf = pm.loft(crv1, crv2, ch=0, u=1, c=0, ar=1, d=1, ss=1, rn=0, po=0, rsn=1)[0] loftSrf = \ pm.rebuildSurface(ch=0, rpo=1, rt=0, end=1, kr=0, kcp=0, kc=0, su=0, du=1, sv=0, dv=1, tol=0, fr=0, dir=2, n=self.name + "_srf")[0] pm.rename(loftSrf, self.name + "_srf") loftSrf.setPivots(loftSrf.c.get()) self.rbnSrf = loftSrf pm.delete(self.rbnSrf, ch=1) pm.delete([crv1, crv2]) pm.parent(self.rbnSrf, self.mainGrp)
def buildRibbon(start, end, normal, numControls=3, name='Ribbon', groupName='', controlSpec={}): chain = util.getChain(start, end) controlChain = util.dupChain(start, end) if not name: name = 'Ribbon' container = util.parentGroup(chain[0]) container.setParent(lib.getNodes.mainGroup()) world = group(em=True) hide(world) world.setParent(container) #controlChain[0].setParent( container ) crv = curve(d=1, p=[(0, 0, 0)] * len(chain)) for i, j in enumerate(chain): xform(crv.cv[i], t=xform(j, q=True, ws=True, t=True), ws=True) dup = duplicate(crv)[0] # &&& Obviously need to calc the offset somehow, maybe I can use the mirror state? Maybe not, due to asymmetry #offset = dt.Vector(5, 0, 0) offset = normal crv.t.set(offset) dup.t.set(offset * -1) surfaceTrans = loft(crv, dup, uniform=True, polygon=0, sectionSpans=1, degree=3, autoReverse=True)[0] surfaceTrans.setParent(world) delete(crv, dup) rebuildSurface(surfaceTrans, rebuildType=0, replaceOriginal=True, spansU=1, spansV=(len(chain) - 1) * 2, dir=2, degreeV=3, degreeU=1) hide(surfaceTrans) surfaceShape = surfaceTrans.getShape() closest = createNode('closestPointOnSurface') surfaceShape.worldSpace >> closest.inputSurface vScalar = surfaceShape.minMaxRangeV.get()[1] #constraints = [] for jnt, hairJoint in zip(chain, controlChain): #jnt.setParent(world) follicle = createNode('follicle') hide(follicle) trans = follicle.getParent() #hairJoints.append(trans) trans.setParent(world) pos = jnt.getTranslation(space='world') closest.inPosition.set(pos) surfaceShape.local >> follicle.inputSurface u = closest.parameterU.get() # closestPointOnSurface returns val in relation to the maxV but the follicle needs it normalized. v = closest.parameterV.get() / vScalar follicle.parameterU.set(u) follicle.parameterV.set(v) follicle.outTranslate >> trans.translate follicle.outRotate >> trans.rotate trans.translate.lock() trans.rotate.lock() hairJoint.setParent(trans) constraints = util.constrainAtoB(chain, controlChain) temp = core.capi.asMObject(surfaceShape) nurbsObj = OpenMaya.MFnNurbsSurface(temp.object()) controls = [] controlJoints = [] for i in range(numControls): percent = i / float(numControls - 1) * vScalar p = pointOnSurface(surfaceShape, u=.5, v=percent, p=True) ctrl = controllerShape.build( name + '%i' % (i + 1), controlSpec['main'], type=controllerShape.ControlType.TRANSLATE) ctrl.t.set(p) j = joint(ctrl) hide(j) controlJoints.append(j) ctrl.setParent(container) # Aim the control at the next joint with it's up following the surface if i < numControls - 1: target = chain[i + 1] normal = nurbsObj.normal(0.5, percent) lib.anim.orientJoint(ctrl, target, upVector=dt.Vector(normal.x, normal.y, normal.z)) core.dagObj.zero(ctrl) controls.append(ctrl) # Orient the final control to the final joint core.dagObj.matchTo(controls[-1], chain[-1]) core.dagObj.zero(controls[-1]) skinCluster(surfaceShape, controlJoints, tsb=True) mainCtrl = nodeApi.RigController.convert(controls[0]) mainCtrl.container = container for i, ctrl in enumerate(controls[1:], 1): mainCtrl.subControl[str(i)] = ctrl return mainCtrl, constraints
def build_plane(name=None, crv=None, spans=None, direction='u', width_axis=None, width=1, log=True): '''Given a valid curve, build nurbs plane Attributes: name -- Prefix name for plane. Str crv -- Curve to use as build guide. nt.Transform spans -- Spans for the plane. Int direction -- Build direction. 'u' or 'v' width_axis -- Plane width axis. 'x', 'y' or 'z' width -- Width of plane. Float ''' general.check_type(name, 'name', [str]) general.check_type(crv, 'crv', [pm.nt.Transform]) general.check_type(spans, 'spans', [int]) general.check_type(direction, 'direction', [str]) general.check_type(width_axis, 'width_axis', [str]) general.check_type(width, 'width', [float, int]) if direction not in ['u', 'v']: raise errors.InputError('direction', direction, "'u' or 'v'") if width_axis not in ['x', 'y', 'z']: raise errors.InputError('width_axis', width_axis, "'x', 'y' or 'z'") d1 = crv.duplicate() d2 = crv.duplicate() move_amt = [] if width_axis == 'x': move_amt = [width, 0, 0] elif width_axis == 'y': move_amt = [0, width, 0] elif width_axis == 'z': move_amt = [0, 0, width] if log: str_1 = 'move_amt: ', move_amt general.logging.debug(str_1) pm.move(move_amt[0], move_amt[1], move_amt[2], d1, r=1) pm.move(-move_amt[0], -move_amt[1], -move_amt[2], d2, r=1) p = pm.loft(d1, d2, n=name+'_plane', ch=0)[0] if direction == 'u': pm.rebuildSurface(p, dir=2, su=spans, sv=2) if direction == 'v': pm.rebuildSurface(p, dir=2, sv=spans, su=2) pm.delete(d1) pm.delete(d2) return p
def generateProfile(self): n_polyType = pm.nurbsToPolygonsPref(q=1, polyType=1) n_format = pm.nurbsToPolygonsPref(q=1, format=1) n_uType = pm.nurbsToPolygonsPref(q=1, uType=1) n_uNumber = pm.nurbsToPolygonsPref(q=1, uNumber=1) n_vType = pm.nurbsToPolygonsPref(q=1, vType=1) n_vNumber = pm.nurbsToPolygonsPref(q=1, vNumber=1) self.sel_list = [ sel for sel in pm.ls(sl=1, ni=1) if hasattr(sel, "getShape") and type(sel.getShape()) == pm.nodetypes.Mesh ] if not self.sel_list: pm.warning(u"请选择 Mesh 模型") pm.headsUpMessage(u"请选择 Mesh 模型") return cam = self.getActiveCamera() if not cam: pm.warning(u"请打开视窗 获取当前激活的摄像机") pm.headsUpMessage(u"请打开视窗 获取当前激活的摄像机") return pm.nurbsToPolygonsPref(polyType=1) pm.nurbsToPolygonsPref(format=2) pm.nurbsToPolygonsPref(uType=3) pm.nurbsToPolygonsPref(uNumber=1) pm.nurbsToPolygonsPref(vType=3) pm.nurbsToPolygonsPref(vNumber=1) self.Adjust_Layout.setEnabled(True) pm.undoInfo(ock=1) self.crv_dict = {} for sel in self.sel_list: # NOTE 通过 Toon 创建轮廓 mel.eval('assignPfxToon "" 0;') # NOTE 获取 Toon 节点 profile_node = pm.ls(sl=1)[0] # NOTE 链接当前摄像机 外轮廓 cam.t.connect(profile_node.cameraPoint, f=1) # NOTE 生成描边曲线 base_crv_list = self.generateProfileCurve(profile_node) mesh_list = [] inflate_crv_list = [] nurbsTessellate_list = [] # NOTE 曲线放样成描边模型 for base in base_crv_list: pm.rebuildCurve(base, ch=0, rpo=1, rt=0, end=1, kr=1, kcp=0, kep=1, kt=0, s=0, d=3, tol=0.01) inflate = self.inflateCurveOnMesh(base, sel, scale=0.5) inflate_crv_list.append(inflate) mesh = pm.loft(base, inflate, ch=1, u=1, c=0, ar=1, d=3, ss=1, rn=1, po=1, rsn=1)[0] node = mesh.history(type="nurbsTessellate") if node: nurbsTessellate_list.extend(node) mesh_list.append(mesh) self.crv_dict[sel] = { "base": base_crv_list, "inflate": inflate_crv_list, "mesh": mesh_list, "nurbsTessellate": nurbsTessellate_list, } base_grp = pm.group(base_crv_list, n="base_grp") inflate_grp = pm.group(inflate_crv_list, n="inflate_grp") # mesh_grp = pm.group(mesh_list,n="inflate_mesh_grp") self.profile_grp = pm.group(base_grp, inflate_grp, mesh_list, n="profile_grp") self.Profile_LE.setText(str(self.profile_grp)) # if len(mesh_list) > 2: # pm.polyUnite(mesh_list,n="%s_profile"%sel,ch=0) # pm.delete(base_grp,inflate_grp) pm.delete(profile_node.getParent()) pm.undoInfo(cck=1) pm.nurbsToPolygonsPref(polyType=n_polyType) pm.nurbsToPolygonsPref(format=n_format) pm.nurbsToPolygonsPref(uType=n_uType) pm.nurbsToPolygonsPref(uNumber=n_uNumber) pm.nurbsToPolygonsPref(vType=n_vType) pm.nurbsToPolygonsPref(vNumber=n_vNumber)
def surfaceCreation(self, curve): bindJntChain = self.jointCreation(curve) loftCurves = [] i = -1 for x in range(2): jntPosList = [] chain = pm.duplicate(bindJntChain) chain[0].translateZ.set(i) i += 2 # Getting the children of the joint chains for k in chain: jntChildPos = k.getTranslation(space='world') jntPosList.append(jntChildPos) loftCurve = pm.curve(n='curve_' + str(x), degree=1, point=jntPosList) loftCurves.append(loftCurve) pm.delete(chain) surface = pm.loft(loftCurves[0], loftCurves[1], n='Ribbon_Surface', ar=True, reverseSurfaceNormals=False, degree=1, ss=1, object=True, ch=False, polygon=0) surface = pm.rebuildSurface(surface, ch=0, rpo=1, rt=0, end=1, kr=2, kcp=0, kc=0, su=0, du=3, sv=0, dv=3, tol=0.01, fr=0, dir=2 ) pm.delete(surface, ch=True) for j in loftCurves: pm.delete(j) # Unparenting joints and duplicate joints for skin bindJntList = [] skinJntList = [] for b in range(len(bindJntChain)): pm.parent(bindJntChain[b], w=True) bindJnt = pm.PyNode(bindJntChain[b]) bindJntList.append(bindJnt) #Here we add the method to nodelling if b == len(bindJntChain)-1: for l in range(len(bindJntChain)): name = bindJntChain[l].replace('Bind', 'Skin') skinJnt = pm.duplicate(bindJntChain[l], name=name) skinJntList.append(skinJnt) # Skinning the surface to the bind joint pm.skinCluster(surface, bindJntList, tsb=True, skinMethod=0, maximumInfluences=1, dropoffRate=10.0) # Creating all the nodes to for the skin Joints surfaceShape = surface[0].getShape() for r in range(len(skinJntList)): skinJnt = skinJntList[r] distance = (1.0 / (len(skinJntList)-1)) * r self.skinJntControl(skinJnt, surfaceShape, distance)
def plane_proxy(joints_chain, name , axis = 'z', scale = 1, type = 'mesh'): """ Create a plane proxy for a joint chain @param joints_chain: list. List of the joints from which to create a curve @param name: String. Name of the final plane proxy @param axis: String {'x','y' or 'z'} NOTES!! : The joint chain need to be proprely oriented ## EXTERIOR CLASS BUILD #------------------------ import adb_utils.adb_script_utils.Script__ProxyPlane as adbProxy reload (adbProxy) Proxy_plane = adbProxy.plane_proxy(pm.selected(), 'adb', 'z') """ all_xmax_locs = [] all_xmin_locs = [] all_loc_groups = [] def createLocs(subject): loc_align = pm.spaceLocator() pm.matchTransform(loc_align,subject, rot=True, pos=True) loc_align.sx.set(scale) loc_align.sy.set(scale) loc_align.sz.set(scale) return loc_align def createCurve(pos ,curve_name): knot = [] for i in range(len(joints_chain)): knot.append(i) _curve= pm.curve(p = pos, k =knot, d=1, n=curve_name) # pm.rebuildCurve(_curve, rt=0, ch=0, end=1, d=3, kr=0, s=len(joints_chain), kcp=0, tol=0.1, kt=0, rpo=1, kep=1) return _curve starting_locs = [createLocs(x) for x in joints_chain] for each in starting_locs: posBox = adbBBox.Bbox([each]) posLocs = posBox.createPosLocs() posLocs_grp = pm.group(posLocs, n= '{}__grp__'.format(each) ) all_loc_groups.append(posLocs_grp) pm.xform(posLocs_grp, cp=True) pm.matchTransform(posLocs_grp, each, pos=True, rot=True) if axis == 'y': max_value = posLocs[1] all_xmax_locs.append(max_value) min_value = posLocs[4] all_xmin_locs.append(min_value) elif axis == 'x': max_value = posLocs[3] all_xmax_locs.append(max_value) min_value = posLocs[0] all_xmin_locs.append(min_value) elif axis == 'z': max_value = posLocs[-1] all_xmax_locs.append(max_value) min_value = posLocs[2] all_xmin_locs.append(min_value) pos_locs_xmax = [createLocs(x) for x in all_xmax_locs] all_xmax_values = [x.getTranslation() for x in pos_locs_xmax] pos_locs_xmin = [createLocs(x) for x in all_xmin_locs] all_xmin_values = [x.getTranslation() for x in pos_locs_xmin] curve1 = createCurve(all_xmax_values, 'max_curve') curve2 = createCurve(all_xmin_values, 'min_curve') if type == 'mesh': nurbs_plane = pm.loft(curve1, curve2, c=0, ch=0, reverseSurfaceNormals = True, d=1, ar=1, u=1, rn=1, po=0)[0] plane_msh = pm.nurbsToPoly(nurbs_plane, n=name, uss=1, ch=0, ft=0.01, d=0.1, pt=1, f=2, mrt=0, mel=0.001, ntr=0, vn=1, pc=100, chr=0.1, un=len(pm.PyNode(curve2).getShape().getCVs()), vt=1, ut=1, ucr=0, cht=0.2, mnd=1, es=0, uch=0)[0] pm.delete(nurbs_plane) elif type == 'nurbs': pm.rebuildCurve(curve1, rt=0, ch=0, end=1, d=3, kr=0, s=len(joints_chain), kcp=0, tol=0.1, kt=0, rpo=1, kep=1) pm.rebuildCurve(curve2, rt=0, ch=0, end=1, d=3, kr=0, s=len(joints_chain), kcp=0, tol=0.1, kt=0, rpo=1, kep=1) plane_msh = pm.loft(curve1, curve2, n=name, c=0, ch=0, reverseSurfaceNormals = True, d=1, ar=1, u=1, rn=1, po=0)[0] mc.DeleteHistory(plane_msh) mc.CenterPivot(plane_msh) ## cleanUp pm.delete(starting_locs, all_loc_groups, pos_locs_xmax, pos_locs_xmin) pm.delete(curve1) pm.delete(curve2) return plane_msh # plane_proxy(pm.selected(), 'proxy' , axis = 'x', type = 'mesh')
def createHairMesh(profilesList, name="hairMesh#", cSet="hairCrease", mat="", lengthDivs=7, widthDivs=4): '''create a Hair Tube with auto crease and material from list of Curve Profiles''' print profilesList if not profilesList or all( [type(o.getShape()) != pm.nodetypes.NurbsCurve for o in profilesList]): print "no Profiles" return pm.select(profilesList) pm.nurbsToPolygonsPref(pt=1, un=4, vn=7, f=2, ut=2, vt=2) HairMesh = pm.loft(n=name, po=1, ch=1, u=1, c=0, ar=1, d=3, ss=1, rn=0, rsn=True) ### #lock all Transform lockTransform(HairMesh[0]) #custom Attribute add HairMesh[0].addAttr('lengthDivisions', min=1, at='long', dv=lengthDivs) HairMesh[0].addAttr('widthDivisions', min=4, at='long', dv=widthDivs) HairMesh[0].setAttr('lengthDivisions', e=1, k=1) HairMesh[0].setAttr('widthDivisions', e=1, k=1) HairTess = pm.listConnections(HairMesh)[-1] HairMesh[0].connectAttr('widthDivisions', HairTess + ".uNumber") HairMesh[0].connectAttr('lengthDivisions', HairTess + ".vNumber") HairMeshShape = HairMesh[0].getShape() ### #set Crease pm.select(HairMeshShape.e[0, 2], r=1) pm.runtime.SelectEdgeLoopSp() sideEdges = pm.selected() if bool(pm.ls(cSet, type=pm.nodetypes.CreaseSet)): hsSet = pm.ls(cSet, type=pm.nodetypes.CreaseSet)[0] else: hsSet = pm.nodetypes.CreaseSet(name=cSet) hsSet.setAttr('creaseLevel', 2.0) for e in sideEdges: pm.sets(hsSet, forceElement=e) #assign Texture HairUV = HairMeshShape.map pm.polyEditUV(HairUV, pu=0.5, pv=0.5, su=0.3, sv=1) pm.polyEditUV(HairUV, u=rand.uniform(-0.1, 0.1)) ### #Add Vray OpenSubdiv pm.select(HairMesh[0], r=1) addVrayOpenSubdivAttr() ### #set Smoothness pm.displaySmoothness(po=3) ### #set Material if bool(pm.ls(mat, type=pm.nodetypes.ShadingEngine)): pm.sets(pm.ls(mat)[0], forceElement=HairMesh[0]) return HairMesh
def __ikJj(self): self.ikJj = [] #create IKRibbonSpine #ribbon spine info: curveInfo = [0,(self.segment - 1) / 4,(self.segment - 1) / 2, ((self.segment - 1) / 2 + (self.segment - 1)) / 2, (self.segment - 1)] ribbonCurve = [] self.folList = [] #create curve for jjInfo in curveInfo: ribonJjPos = self.spineFkBlendChain.chain[jjInfo].getTranslation(space = 'world') ribbonCurve.append(ribonJjPos) #set ribbon offset offset = float(self.length * 0.05) #set ribbon cur ribbonCurveL = pm.curve(d = 3,p = [ribbonCurve[0],ribbonCurve[1],ribbonCurve[2],ribbonCurve[3],ribbonCurve[4]], k = [0,0,0,1,2,2,2],n = nameUtils.getUniqueName(self.side,self.baseName + '_ribbonL','gud')) pm.move(offset,0,0,ribbonCurveL) ribbonCurveR = pm.curve(d = 3,p = [ribbonCurve[0],ribbonCurve[1],ribbonCurve[2],ribbonCurve[3],ribbonCurve[4]], k = [0,0,0,1,2,2,2],n = nameUtils.getUniqueName(self.side,self.baseName + '_ribbonR','gud')) pm.move(-offset,0,0,ribbonCurveR) ribbonCurveR.setParent(self.guideGrp) ribbonCurveL.setParent(self.guideGrp) #create ribbon surf ribbonGeo = pm.loft(ribbonCurveR,ribbonCurveL,ch = 0,u = 1,c = 0,ar = 1,d = 3,ss = 1, rn = 0,po = 0,rsn = 1, n = nameUtils.getUniqueName(self.side,self.baseName + '_ribbon','surf')) ribbonClusList = [] self.ribbonJc = [] self.spineCc = [] #get loc pos for num,loc in enumerate(self.fkGuides): startLoc = self.fkGuides[0] midLoc = self.fkGuides[(len(self.fkGuides) - 1) / 2] endLoc = self.fkGuides[-1] startLocPos = pm.xform(startLoc,ws = 1,t = 1,q = 1)[1] midLocPos = pm.xform(midLoc,ws = 1,t = 1,q = 1)[1] endLocPos = pm.xform(endLoc,ws = 1,t = 1,q = 1)[1] #get Jc pos for num in [0,2,4]: pos = pm.select(ribbonGeo[0] + '.cv[' + str(num) + '][0:3]',r = 1) clus = pm.cluster() pm.rename(clus[1],nameUtils.getUniqueName(self.side,self.baseName + '_ribbon','cls')) ribbonClusList.append(clus) pm.select(cl = 1) #set cvpos for vert in [1,3]: for row in range(0,4): cvNum = pm.select(ribbonGeo[0] + '.cv[' + str(vert) + '][' + str(row) + ']',r = 1) oriPos = pm.xform(cvNum,ws = 1,t = 1,q = 1) if vert == 1: pm.xform(cvNum,ws = 1,t = (oriPos[0],(startLocPos + midLocPos) / 2,oriPos[2])) elif vert == 3: pm.xform(cvNum,ws = 1,t = (oriPos[0],(endLocPos + midLocPos) / 2,oriPos[2])) #set Jc and Jc ctrl for num,x in enumerate(ribbonClusList): jc = pm.joint(p = x[1].getRotatePivot(), n = nameUtils.getUniqueName(self.side,self.baseName + self.nameList[num],'jc'), radius = self.length / 3) self.ribbonJc.append(jc) pm.select(cl = 1) pm.delete(ribbonClusList[num]) pm.select(cl = 1) cc = control.Control(self.side,self.baseName + self.nameList[num],size = self.ikSize,aimAxis = self.ctrlAxis) cc.circleCtrl() pm.makeIdentity(cc.control,apply = True,t=0,r=1,s=0,n=0,pn=1) # self.bodyCtrl.control.ik_vis.connect(cc.controlGrp.v) self.bodyCtrl.control.ik_vis.connect(cc.control.getShape().v) self.spineCc.append(cc.control) control.lockAndHideAttr(cc.control,['sx','sy','sz','v']) pm.xform(cc.controlGrp,ws = 1,matrix = jc.worldMatrix.get()) #skin Jc for num,jc in enumerate(self.ribbonJc): jc.setParent(self.spineCc[num]) ribbonSkin = pm.skinCluster(self.ribbonJc[0],self.ribbonJc[1],self.ribbonJc[2],ribbonGeo[0], tsb = 1,ih = 1,mi = 3,dr = 4,rui = 1,n = nameUtils.getSkinName()) #skin pm.skinPercent(ribbonSkin,ribbonGeo[0] + '.cv[0][0:3]', transformValue=[(self.ribbonJc[0],1)]) pm.skinPercent(ribbonSkin,ribbonGeo[0] + '.cv[1][0:3]', transformValue=[(self.ribbonJc[1],0.5),(self.ribbonJc[0],0.5)]) pm.skinPercent(ribbonSkin,ribbonGeo[0] + '.cv[2][0:3]', transformValue=[(self.ribbonJc[1],1)]) pm.skinPercent(ribbonSkin,ribbonGeo[0] + '.cv[3][0:3]', transformValue=[(self.ribbonJc[1],0.5),(self.ribbonJc[2],0.5)]) pm.skinPercent(ribbonSkin,ribbonGeo[0] + '.cv[4][0:3]', transformValue=[(self.ribbonJc[2],1)]) #set fol #create / rename fol self.folGrp = pm.group(em = 1,n = nameUtils.getUniqueName(self.side,self.baseName + 'Fol','grp')) for fol in range(0,self.segment): #createNodeName follicleTransName = nameUtils.getUniqueName(self.side,self.baseName,'fol') follicleShapeName = nameUtils.getUniqueName(self.side,self.baseName,'folShape') #createNode follicleShape = pm.createNode('follicle',n = follicleShapeName) follicleTrans = pm.listRelatives(follicleShape, parent=True)[0] follicleTrans = pm.rename(follicleTrans, follicleTransName) # connect the surface to the follicle if ribbonGeo[0].getShape().nodeType() == 'nurbsSurface': pm.connectAttr((ribbonGeo[0] + '.local'), (follicleShape + '.inputSurface')) #Connect the worldMatrix of the surface into the follicleShape pm.connectAttr((ribbonGeo[0].getShape() + '.worldMatrix[0]'), (follicleShape + '.inputWorldMatrix')) #Connect the follicleShape to it's transform pm.connectAttr((follicleShape + '.outRotate'), (follicleTrans + '.rotate')) pm.connectAttr((follicleShape + '.outTranslate'), (follicleTrans + '.translate')) #Set the uValue and vValue for the current follicle pm.setAttr((follicleShape + '.parameterV'), 0.5) pm.setAttr((follicleShape + '.parameterU'), float(1.0 / float(self.segment - 1)) * fol) #Lock the translate/rotate of the follicle pm.setAttr((follicleTrans + '.translate'), lock=True) pm.setAttr((follicleTrans + '.rotate'), lock=True) pm.setAttr((follicleShape + '.degree'),1) #parent self.folList.append(follicleTrans) follicleTrans.setParent(self.folGrp) #rebuild fol pos self.spineIkBlendJoint = [] self.stretchCube = [] for num,fol in enumerate(self.folList): jj = pm.joint(p = (0,0,0),n = nameUtils.getUniqueName(self.side,self.baseName,'jj'), radius = self.length / 5) self.spineIkBlendJoint.append(jj) jj.setParent(fol) tempCube = pm.polyCube(ch = 1,o = 1,w = float(self.length / 5),h = float(self.length / 10), d = float(self.length / 5),cuv = 4,n = nameUtils.getUniqueName(self.side,self.baseName,'cube')) tempCube[0].setParent(jj) tempCube[0].v.set(0) self.stretchCube.append(tempCube[0]) jj.translateX.set(0) jj.translateY.set(0) jj.translateZ.set(0) self.ikJj.append(jj) #create spine grp self.spineIkGrp = pm.group(self.spineCc[0].getParent(),self.spineCc[1].getParent(),self.spineCc[2].getParent(),self.folGrp,ribbonGeo[0], n = nameUtils.getUniqueName(self.side,self.baseName + 'Ik','grp')) ribbonGeo[0].inheritsTransform.set(0) self.folGrp.inheritsTransform.set(0) #clean self.spineIkGrp.setParent(self.bodyCtrl.control) #temp self.spineIkGrp.v.set(1) '''put chest ctrl under chest cc''' '''put leg under hip cc'''
def ctrlCurve(self, parent=None): self.curve = pm.curve(n=self.name + '_curve', d=1, p=self.ikhCoordList) if parent: self.curve.setParent(parent) pm.rebuildCurve(self.curve, s=3, d=3) # criando cluster a cada dois cvs clusterDrivers = [] # clusters curveCtrls = [] # ctrls cvsToCluster = [] poleCoords = [] drvPtvList = [] # coords de pvt dos tres drivers drvOrientList = [] # orientacao dos drivers bendCtrlList = [] index = 0 curveDrvGrp = groupTools.makeGroup(name=self.name + '_curveDrv', parent=parent) curveDrvGrp.v.set(0) ctrlGrp = groupTools.makeGroup(name=self.name + '_ctrl', parent=parent) # criando ctrl master e parenteando os outros nele: masterZeroGrp = groupTools.makeGroup(name=self.name + '_master_zero', parent=ctrlGrp) self.masterCtrl = groupTools.makeGroup(name=self.name + '_master_ctrl', suffix='', parent=masterZeroGrp) masterShape = pm.duplicate(self.curve)[0] masterShape.translateZ.set(-25) # criando uma rbbn para orientar os pose readers das penas: rbbnName = self.name + '_aimRbbn' self.aimRbbn = pm.loft(self.curve, masterShape, ch=False, ar=True, d=1, n=rbbnName)[0] self.aimRbbn.setParent(parent) self.aimRbbn.v.set(0) for e, cv in enumerate(self.curve.cv): if e == 0 or e == len(self.curve.cv) - 1: poleCoords.append(vtxWalk.bbox(cv)['globalPvt']) cvsToCluster.append(cv) for eachSpam in range(2): cvsToCluster.append( str(self.aimRbbn.name()) + '.cv[' + str(eachSpam) + '][' + str(e) + ']') index += 1 if index == 2: cluster = pm.cluster(cvsToCluster, n=self.name + '_' + str((e / 2) + 1))[1] cluster.setParent(curveDrvGrp) clusterDrivers.append(cluster) index = 0 cvsToCluster = [] # ajustando pivos dos clusters das extremidades para os extremos pm.xform(clusterDrivers[0], rp=poleCoords[0], ws=1) pm.xform(clusterDrivers[2], rp=poleCoords[1], ws=1) # criando drv ctrls para a curva for e, drv in enumerate(clusterDrivers): currentPvt = pm.xform(clusterDrivers[e], rp=1, q=1, ws=1) ctrl = controlTools.cntrlCrv(name=self.name + '_' + str(e + 1), size=20, coords=(currentPvt, (0, 0, 0), (1, 1, 1)), parent=ctrlGrp, lockChannels=[ 'v', ], color=(.9, .9, 0)) drvPtvList.append(currentPvt) curveCtrls.append(ctrl) # orientando drv ctrls: for i, ctrl in enumerate(curveCtrls): target = ctrl.getParent() if i == 0: source = curveCtrls[1] aim = (1, 0, 0) elif i == 1: source = curveCtrls[2] aim = (1, 0, 0) elif i == 2: source = curveCtrls[1] aim = (-1, 0, 0) tempConstraint = pm.aimConstraint(source, target, wut='scene', aim=aim, mo=0) pm.delete(tempConstraint) drvOrientList.append(pm.xform(ctrl, q=1, ro=1, ws=1)) # contraint do controle para os clusters: pm.parentConstraint(ctrl, clusterDrivers[i], mo=1) pm.scaleConstraint(ctrl, clusterDrivers[i], mo=1) pm.xform(masterZeroGrp, t=drvPtvList[1], ro=drvOrientList[1], ws=1) masterShape.setParent(self.masterCtrl) pm.makeIdentity(masterShape, t=1, r=1, apply=1) pm.parent(masterShape.getShape(), self.masterCtrl, r=1, s=1) pm.delete(masterShape) self.curve.getShape().template.set(1) for ctrl in curveCtrls: ctrl.getParent().setParent(self.masterCtrl) # ctrls de bend: bendCtrl1 = controlTools.cntrlCrv(name=self.name + '_bend1', icone='trianguloZ', size=15, lockChannels=['v'], coords=(drvPtvList[0], drvOrientList[0], (1, 1, 1)), parent=ctrlGrp, color=(0, .1, .5)) pm.xform(bendCtrl1, t=(0, 0, 40), ro=(0, 90, 0), r=1) pm.makeIdentity(bendCtrl1, r=1, apply=1) bendCtrl1.getParent().setParent(curveCtrls[0]) bendCtrlList.append(bendCtrl1) bendCtrl2 = controlTools.cntrlCrv(name=self.name + '_bend2', icone='trianguloZ', size=15, lockChannels=['v'], coords=(drvPtvList[2], drvOrientList[2], (1, 1, 1)), parent=ctrlGrp, color=(0, .1, .5)) pm.xform(bendCtrl2, t=(0, 0, 40), ro=(0, -90, 0), r=1) pm.makeIdentity(bendCtrl2, r=1, apply=1) bendCtrl2.getParent().setParent(curveCtrls[2]) bendCtrlList.append(bendCtrl2) return self.masterCtrl, curveCtrls, bendCtrlList
locator_num = total_joint for i in range(locator_num): new_locator = pm.duplicate(startlocator) movelen = steplen * (i + 1) pm.move(movelen,new_locator, x = True,r=True, os = True) pointlist.append(pm.xform(new_locator,t = True, ws = True, q = True)) #create curve #move curve along z axis curve1 = pm.curve(p = pointlist,d = 1.0) curve2 = pm.duplicate(curve1) pm.move(2, curve1, x = True, r = True, os = True) pm.move(-2, curve2, x = True, r = True, os = True) flexymesh_transform = pm.loft(curve1, curve2, ar = True, d = 3, name = 'flexymesh', po = 0, rsn = True)[0] #surface need to rebuild pm.rebuildSurface(flexymesh_transform, du = 3, dv = 1, su = total_joint, sv = 1) flexymesh = flexymesh_transform.getShape() foll_grp = pm.group(em = True, w = True, n = 'FollicleNode') #create follicles for i in range (5): foll_transform = pm.createNode('transform', ss= True, name = 'follicle' + str(i)) follicle = pm.createNode('follicle', name = 'follicleshape' + str(i), p = foll_transform) flexymesh.local.connect(follicle.inputSurface) flexymesh.worldMatrix[0].connect(follicle.inputWorldMatrix) follicle.outRotate.connect(follicle.getParent().rotate) follicle.outTranslate.connect(follicle.getParent().translate) follicle.parameterU.set(0.1 + i * 0.2) follicle.parameterV.set(0.5)
def create_ribbons(self, side, components_type, selection, how_many_ctrls): if components_type != "face": if components_type == "edge": vertices_from_selection = pmc.polyListComponentConversion(selection, fromEdge=1, toVertex=1) vertices = pmc.ls(vertices_from_selection, flatten=1) vertices_from_first_edge = pmc.ls(pmc.polyListComponentConversion(selection[0], fromEdge=1, toVertex=1), flatten=1) edges_from_point = pmc.ls(pmc.polyListComponentConversion(vertices_from_first_edge[0], fromVertex=1, toEdge=1), flatten=1) vertices_from_edges = pmc.ls(pmc.polyListComponentConversion(edges_from_point, toVertex=1, fromEdge=1, border=1), flatten=1) next_vertex = [vertex for vertex in vertices_from_edges if vertex in vertices] if len(next_vertex) == 1: first_vertex = pmc.ls(vertices_from_first_edge[0])[0] else: first_vertex = pmc.ls(vertices_from_first_edge[1])[0] vertices.remove(first_vertex) vertices.insert(0, first_vertex) else: vertices = selection ordered_vertices = rig_lib.continuous_check_and_reorder_vertex_list(vertices, self.model.module_name) vertices_world_pos = [] skn_jnts = [] for i, vertex in enumerate(ordered_vertices): vertices_world_pos.append(pmc.xform(vertex, q=1, ws=1, translation=1)) pmc.select(cl=1) jnt = pmc.joint(p=(0, 0, 0), n="{0}_{1}_{2}_SKN".format(self.model.module_name, side, i)) jnt.setAttr("translate", vertices_world_pos[i]) jnt.setAttr("radius", 0.1) skn_jnts.append(jnt) front_curve = pmc.curve(d=3, p=vertices_world_pos, n="{0}_{1}_nurbsSurface_guide_01".format(self.model.module_name, side)) back_curve = pmc.duplicate(front_curve, n="{0}_{1}_nurbsSurface_guide_02".format(self.model.module_name, side))[0] if self.model.loft_axis == "X": front_curve.setAttr("translateX", 0.1) back_curve.setAttr("translateX", -0.1) elif self.model.loft_axis == "Y": front_curve.setAttr("translateY", 0.1) back_curve.setAttr("translateY", -0.1) else: front_curve.setAttr("translateZ", 0.1) back_curve.setAttr("translateZ", -0.1) surface = pmc.loft(back_curve, front_curve, ar=1, ch=0, d=1, uniform=0, n="{0}_{1}_ribbons_NURBSSURFACE".format(self.model.module_name, side))[0] surface = pmc.rebuildSurface(surface, ch=0, du=1, dv=3, dir=2, kcp=1, kr=0, rt=0, rpo=1)[0] pmc.delete(front_curve) pmc.delete(back_curve) pmc.parent(surface, self.parts_grp) self.jnts_to_skin.append(skn_jnts) follicles = [] for i, jnt in enumerate(skn_jnts): follicle_shape = pmc.createNode("follicle", n="{0}_{1}_{2}_FOLShape".format(self.model.module_name, side, i)) follicle = follicle_shape.getParent() follicle.rename("{0}_{1}_{2}_FOL".format(self.model.module_name, side, i)) follicle_shape.outTranslate >> follicle.translate follicle_shape.outRotate >> follicle.rotate surface.getShape().local >> follicle_shape.inputSurface surface.getShape().worldMatrix[0] >> follicle_shape.inputWorldMatrix point_on_surface = pmc.createNode("closestPointOnSurface", n=str(jnt) + "CPS") surface.getShape().local >> point_on_surface.inputSurface point_on_surface.setAttr("inPosition", pmc.xform(jnt, q=1, ws=1, translation=1)) follicle_shape.setAttr("parameterU", point_on_surface.getAttr("parameterU")) follicle_shape.setAttr("parameterV", point_on_surface.getAttr("parameterV")) pmc.delete(point_on_surface) pmc.parent(jnt, follicle, r=0) follicles.append(follicle) pmc.parent(follicle, self.jnt_input_grp) pmc.select(cl=1) start_jnt = pmc.joint(p=(0, 0, 0), n="{0}_{1}_start_JNT".format(self.model.module_name, side)) start_jnt.setAttr("radius", 0.2) pmc.select(cl=1) end_jnt = pmc.joint(p=(0, 0, 0), n="{0}_{1}_end_JNT".format(self.model.module_name, side)) end_jnt.setAttr("radius", 0.2) pmc.select(cl=1) mid_jnt = pmc.joint(p=(0, 0, 0), n="{0}_{1}_mid_JNT".format(self.model.module_name, side)) mid_jnt.setAttr("radius", 0.2) pmc.select(cl=1) start_mid_jnt = pmc.joint(p=(0, 0, 0), n="{0}_{1}_start_mid_JNT".format(self.model.module_name, side)) start_mid_jnt.setAttr("radius", 0.2) pmc.select(cl=1) mid_end_jnt = pmc.joint(p=(0, 0, 0), n="{0}_{1}_mid_end_JNT".format(self.model.module_name, side)) mid_end_jnt.setAttr("radius", 0.2) ctrl_jnts_pos = pmc.createNode("pointOnSurfaceInfo", n="{0}_{1}_PSI".format(self.model.module_name, side)) surface.getShape().local >> ctrl_jnts_pos.inputSurface ctrl_jnts_pos.setAttr("parameterU", 0.5) ctrl_jnts_pos.setAttr("parameterV", 0.0) pmc.refresh() start_jnt.setAttr("translate", ctrl_jnts_pos.getAttr("position")) if how_many_ctrls == "7": ctrl_jnts_pos.setAttr("parameterV", 0.3) else: ctrl_jnts_pos.setAttr("parameterV", 0.25) pmc.refresh() start_mid_jnt.setAttr("translate", ctrl_jnts_pos.getAttr("position")) ctrl_jnts_pos.setAttr("parameterV", 0.5) pmc.refresh() mid_jnt.setAttr("translate", ctrl_jnts_pos.getAttr("position")) if how_many_ctrls == "7": ctrl_jnts_pos.setAttr("parameterV", 0.7) else: ctrl_jnts_pos.setAttr("parameterV", 0.75) pmc.refresh() mid_end_jnt.setAttr("translate", ctrl_jnts_pos.getAttr("position")) ctrl_jnts_pos.setAttr("parameterV", 1.0) pmc.refresh() end_jnt.setAttr("translate", ctrl_jnts_pos.getAttr("position")) if how_many_ctrls == "7": pmc.select(cl=1) start_quarter_jnt = pmc.joint(p=(0, 0, 0), n="{0}_{1}_start_quarter_JNT".format(self.model.module_name, side)) start_quarter_jnt.setAttr("radius", 0.2) pmc.select(cl=1) quarter_end_jnt = pmc.joint(p=(0, 0, 0), n="{0}_{1}_quarter_end_JNT".format(self.model.module_name, side)) quarter_end_jnt.setAttr("radius", 0.2) ctrl_jnts_pos.setAttr("parameterV", 0.15) pmc.refresh() start_quarter_jnt.setAttr("translate", ctrl_jnts_pos.getAttr("position")) ctrl_jnts_pos.setAttr("parameterV", 0.85) pmc.refresh() quarter_end_jnt.setAttr("translate", ctrl_jnts_pos.getAttr("position")) ctrls_jnt = [start_jnt, start_quarter_jnt, start_mid_jnt, mid_jnt, mid_end_jnt, quarter_end_jnt, end_jnt] else: ctrls_jnt = [start_jnt, start_mid_jnt, mid_jnt, mid_end_jnt, end_jnt] pmc.delete(ctrl_jnts_pos) ctrls = [] ctrls_fol = [] for jnt in ctrls_jnt: if side == "bot": jnt.setAttr("jointOrientX", 180) if jnt.getAttr("translateX") < -0.05: jnt.setAttr("jointOrientY", 180) follicle_shape = pmc.createNode("follicle", n=str(jnt).replace("_JNT", "_FOLShape")) follicle = follicle_shape.getParent() follicle.rename(str(jnt).replace("_JNT", "_FOL")) follicle_shape.outTranslate >> follicle.translate follicle_shape.outRotate >> follicle.rotate self.mesh_to_follow.getShape().outMesh >> follicle_shape.inputMesh self.mesh_to_follow.getShape().worldMatrix[0] >> follicle_shape.inputWorldMatrix point_on_mesh = pmc.createNode("closestPointOnMesh", n=str(jnt) + "CPM") self.mesh_to_follow.getShape().outMesh >> point_on_mesh.inMesh point_on_mesh.setAttr("inPosition", pmc.xform(jnt, q=1, ws=1, translation=1)) follicle_shape.setAttr("parameterU", point_on_mesh.getAttr("parameterU")) follicle_shape.setAttr("parameterV", point_on_mesh.getAttr("parameterV")) pmc.delete(point_on_mesh) ctrls_fol.append(follicle) pmc.select(clear=1) ctrl_shape = pmc.circle(c=(0, 0, 0), nr=(0, 0, 1), sw=360, r=0.5, d=3, s=8, n=str(jnt).replace("_JNT", "_ctrl_Shape"), ch=0)[0] ctrl = rig_lib.create_jnttype_ctrl(name=str(jnt).replace("_JNT", "_CTRL"), shape=ctrl_shape) pmc.select(clear=1) ctrl_ofs = pmc.joint(p=(0, 0, 0), n=str(ctrl).replace("_CTRL", "_ctrl_OFS")) ctrl_ofs.setAttr("drawStyle", 2) ctrl_fix_r = pmc.joint(p=(0, 0, 0), n=str(ctrl).replace("_CTRL", "_ctrl_rotate_FIX")) ctrl_fix_r.setAttr("drawStyle", 2) ctrl_fix_r.setAttr("rotateOrder", 5) ctrl_fix_t = pmc.joint(p=(0, 0, 0), n=str(ctrl).replace("_CTRL", "_ctrl_translate_FIX")) ctrl_fix_t.setAttr("drawStyle", 2) pmc.parent(ctrl, ctrl_fix_t) pmc.parent(ctrl_ofs, follicle) ctrl_ofs.setAttr("translate", (0, 0, 0)) ctrl_ofs.setAttr("rotate", (0, 0, 0)) ctrl_ofs.setAttr("jointOrient", (0, 0, 0)) ctrl_ofs_orientation_loc = pmc.spaceLocator(p=(0, 0, 0), n="{0}_orientation_LOC".format(ctrl_ofs)) pmc.parent(ctrl_ofs_orientation_loc, jnt, r=1) pmc.parent(ctrl_ofs_orientation_loc, follicle, r=0) ctrl_ofs.setAttr("jointOrient", ctrl_ofs_orientation_loc.getAttr("rotate")) pmc.delete(ctrl_ofs_orientation_loc) invert_ctrl_translate = pmc.createNode("multiplyDivide", n=str(ctrl) + "invert_translate_MDL") invert_ctrl_rotate = pmc.createNode("multiplyDivide", n=str(ctrl) + "invert_rotate_MDL") ctrl.translate >> invert_ctrl_translate.input1 invert_ctrl_translate.setAttr("input2", (-1, -1, -1)) invert_ctrl_translate.output >> ctrl_fix_t.translate ctrl.rotate >> invert_ctrl_rotate.input1 invert_ctrl_rotate.setAttr("input2", (-1, -1, -1)) invert_ctrl_rotate.output >> ctrl_fix_r.rotate ctrl_cvs = ctrl.cv[:] for cv in ctrl_cvs: pmc.move(cv, 0.5, moveZ=1, ws=1, wd=1, r=1) pmc.move(cv, 0.1, moveY=1, ls=1, wd=1, r=1) jnt_ofs = pmc.duplicate(jnt, n=str(jnt).replace("_JNT", "_jnt_OFS"))[0] jnt_ofs.setAttr("drawStyle", 2) pmc.parent(jnt, jnt_ofs) ctrl.translate >> jnt.translate ctrl.rotate >> jnt.rotate ctrl.scale >> jnt.scale ctrls.append(ctrl) pmc.parent(jnt_ofs, self.parts_grp) pmc.parent(follicle, self.ctrl_input_grp) pmc.select(cl=1) pmc.skinCluster(ctrls_jnt, surface, bm=0, dr=4.0, mi=2, nw=1, sm=0, tsb=1, wd=0) return skn_jnts, surface, follicles, ctrls_jnt, ctrls_fol, ctrls else: pmc.error("faces aren't support yet")
def create_guideSurface(IdName, listOfJnts): loftCurves = [] for i in range(2): # duplicate and select hierarchy of joints listOfOffsetJnts = pm.duplicate(listOfJnts, name='b_' + IdName + '_offset1', parentOnly=True) # offset each joint on it's own z-axis for jnt in listOfOffsetJnts: if i == 0: pm.move(jnt, (0, 0, -0.5), relative=True, objectSpace=True, preserveChildPosition=True) if i == 1: pm.move(jnt, (0, 0, 0.5), relative=True, objectSpace=True, preserveChildPosition=True) # draw loftcurves loftCurvePoints = [] for each in listOfOffsetJnts: jntPosition = pm.xform(each, q=True, t=True, ws=True) loftCurvePoints.append(jntPosition) loftCurves.append( pm.curve(name=IdName + '_loftCurve' + str(i), degree=1, point=loftCurvePoints)) pm.delete(listOfOffsetJnts) # loft guideSurface guideSurface = pm.loft(loftCurves[0], loftCurves[1], name=IdName + '_guide_surface', ar=True, rsn=True, d=3, ss=1, object=True, ch=False, polygon=0) guideSurface = pm.rebuildSurface(guideSurface, ch=1, rpo=1, rt=0, end=1, kr=1, kcp=0, kc=0, su=0, du=3, sv=1, dv=3, tol=0.01, fr=0, dir=2) # cleanup pm.delete(loftCurves) guideSurface[0].inheritsTransform.set(False) guideSurface[0].overrideEnabled.set(True) guideSurface[0].overrideDisplayType.set(1) # guideSurface[0].visibility.set(False) print('Successfully lofted guide surface. Continuing...') return guideSurface
def create_jnts(self): tentacle_jnts_crv = pmc.curve(d=1, p=[ pmc.xform(self.guides[0], q=1, ws=1, translation=1), pmc.xform(self.guides[1], q=1, ws=1, translation=1) ], n="{0}_tentacle_curve_1".format( self.model.module_name)) tentacle_jnts_rebuilded = pmc.rebuildCurve(tentacle_jnts_crv, rpo=0, rt=0, end=1, kr=0, kep=1, kt=0, s=self.model.how_many_jnts, d=1, ch=0, replaceOriginal=1)[0] if self.model.how_many_jnts == 2: pmc.delete(tentacle_jnts_rebuilded.cv[-2]) pmc.delete(tentacle_jnts_rebuilded.cv[1]) vertex_list = tentacle_jnts_rebuilded.cv[:] self.created_tentacle_jnts = rig_lib.create_jnts_from_cv_list_and_return_jnts_list( vertex_list, "{0}_tentacle".format(self.model.module_name)) rig_lib.change_jnt_chain_suffix(self.created_tentacle_jnts, new_suffix="SKN") pmc.select(d=1) skin_selection = list(self.created_tentacle_jnts) for i, jnts in enumerate(self.created_tentacle_jnts): first_value = i second_value = float(((self.model.how_many_jnts))) default_value = float(first_value / second_value) jnts.addAttr("position", attributeType="float", defaultValue=default_value, hidden=0, keyable=1) pmc.select(d=1) tentacle_jnts_offset_name = str(self.created_tentacle_jnts[0]).replace( "_SKN", "_jnt_OFS") tentacle_jnts_offset = pmc.joint( p=pmc.xform(self.created_tentacle_jnts[0], q=1, ws=1, translation=1), o=pmc.xform(self.created_tentacle_jnts[0], q=1, ws=1, rotation=1), n=tentacle_jnts_offset_name) pmc.parent(self.created_tentacle_jnts[0], tentacle_jnts_offset, r=0) pmc.parent(tentacle_jnts_offset, self.jnt_input_grp, r=0) tentacle_jnts_rebuilded.setAttr("translate", (0, 0, 0.1)) tentacle_nurbs_crv_rebuilded = pmc.rebuildCurve( tentacle_jnts_rebuilded, rpo=0, rt=0, end=1, kr=0, kep=1, kt=0, s=self.model.how_many_jnts, d=3, ch=0, replaceOriginal=1)[0] tentacle_nurbs_crv = pmc.duplicate(tentacle_nurbs_crv_rebuilded, n="{0}_tentacle_curve_2".format( self.model.module_name))[0] tentacle_nurbs_crv.setAttr("translate", (0, 0, -0.1)) tentacle_jnts_nurbs = pmc.loft(tentacle_nurbs_crv_rebuilded, tentacle_nurbs_crv, u=1, ar=1, ss=1, rn=0, po=0, rsn=1, d=1, c=0, n="{0}_variableFK_nurbs".format( self.model.module_name)) pmc.delete(tentacle_nurbs_crv_rebuilded) pmc.delete(tentacle_nurbs_crv) pmc.select(d=1) pmc.skinCluster(skin_selection[0], tentacle_jnts_nurbs[0], sm=0, nw=2, mi=1, rui=1, dr=2, n='VFK_SkinCluster') self.nurbs_tentacle = tentacle_jnts_nurbs pmc.select(d=1)
def main(size=0.5): pm.nurbsToPolygonsPref(polyType=1) pm.nurbsToPolygonsPref(format=2) pm.nurbsToPolygonsPref(uType=3) pm.nurbsToPolygonsPref(uNumber=1) pm.nurbsToPolygonsPref(vType=3) pm.nurbsToPolygonsPref(vNumber=1) mel.eval(""" source "assignPfxToon.mel"; """) sel_list = pm.ls(sl=1, ni=1) cam = getActiveCamera() for sel in sel_list: # NOTE 通过 Toon 创建轮廓 mel.eval('assignPfxToon "" 0;') # NOTE 获取 Toon 节点 profile_node = pm.ls(sl=1)[0] # NOTE 链接当前摄像机 外轮廓 cam.t.connect(profile_node.cameraPoint, f=1) # NOTE 生成描边曲线 base_crv_list = generateProfileCurve(profile_node) mesh_list = [] inflate_crv_list = [] # NOTE 曲线放样成描边模型 for base in base_crv_list: pm.rebuildCurve(base, ch=0, rpo=1, rt=0, end=1, kr=1, kcp=0, kep=1, kt=0, s=0, d=3, tol=0.01) inflate = inflateCurveOnMesh(base, sel, scale=size) inflate_crv_list.append(inflate) mesh = pm.loft(base, inflate, ch=0, u=1, c=0, ar=1, d=3, ss=1, rn=0, po=1, rsn=1) mesh_list.append(mesh) base_grp = pm.group(base_crv_list, n="base_grp") inflate_grp = pm.group(inflate_crv_list, n="inflate_grp") if len(mesh_list) > 2: pm.polyUnite(mesh_list, n="%s_profile" % sel, ch=0) # pm.delete(base_grp,inflate_grp) pm.delete(profile_node.getParent())
def make(cls, start, end, name="soMuscle"): """Creates a new muscle positioned between start and end. start & end must both be locators. The locators are hijacked by the muscle and moved into its own special group. :param start: A locator describing where the muscle starts. :param end: A locator describing where the muscle ends. :param name: (optional) A descriptive name for the muscle (group.) """ snode = pm.PyNode(start) if snode is None: raise ValueError("Couldn't deduce Maya type for start.") enode = pm.PyNode(end) if enode is None: raise ValueError("Couldn't dedude Maya type for end.") def findshape(n): if n.nodeType() == "transform": children = n.getChildren() # Can probably use n.getShape() here. if len(children) > 0: return children[0], n else: raise TypeError("Expected a locator or its transform node in start") elif n.nodeType() == "locator": return n, n.getParent() else: raise TypeError("Expected a locator or its transform node in start") def getrottrans(trans): return trans.getRotation(space="world"), trans.getTranslation(space="world") # Find locator shapes, mostly to make sure they are locators. # Their transforms are needed though. snode, sloctrans = findshape(snode) enode, eloctrans = findshape(enode) mloctrans = pm.spaceLocator() # Point-constrain and orient constrain to other locators. pm.pointConstraint(sloctrans, eloctrans, mloctrans, maintainOffset=False) pm.orientConstraint(sloctrans, eloctrans, mloctrans) maingrp = pm.group(empty=True, name=name) maingrp.translate.lock(), maingrp.rotate.lock(), maingrp.scale.lock() grp = pm.group(empty=True, name="moveGroup") grp.setParent(maingrp) sloctrans.setParent(grp), sloctrans.rename("muscleStart") eloctrans.setParent(grp), eloctrans.rename("muscleEnd") mloctrans.setParent(grp), mloctrans.rename("muscleMid") # Make the locators smaller in the UI. for loctrans in [sloctrans, mloctrans, eloctrans]: loctrans.getShape().localScale.set(0.25, 0.25, 0.25) startdef = ("start", sloctrans) + getrottrans(sloctrans) enddef = ("end", eloctrans) + getrottrans(eloctrans) middef = ("mid", mloctrans) + getrottrans(mloctrans) circles = [] for name, parent, rot, pos in [startdef, middef, enddef]: transform, _ = pm.circle(radius=0.1) pm.delete(transform, ch=True) circles.append(transform) transform.setParent(parent) # Change name AFTER we've parented them, so we can avoid naming collisions. transform.rename(name) transform.setRotation(rot) transform.setTranslation(pos, space="world") loftrans, _ = pm.loft(*circles) loftrans.setParent(maingrp) # Put in maingrp, so we avoid double transforms. loftrans.rename("muscleSurface") midcircle = circles[1] def addfloat3(obj, attrname): obj.addAttr(attrname, at="float3") for suffix in ["X", "Y", "Z"]: obj.addAttr(attrname + suffix, at="float", parent=attrname, k=True) addfloat3(midcircle, "startPos") addfloat3(midcircle, "endPos") maingrp.addAttr("bulgeFactor", at="float", defaultValue=1.0, minValue=0.01, maxValue=1000, k=True) sloctrans.translate >> midcircle.startPos eloctrans.translate >> midcircle.endPos # Some horrible MEL to preserve volume. expression = """ vector $a = <<{0}.startPosX, {0}.startPosY, {0}.startPosZ>>; vector $b = <<{0}.endPosX, {0}.endPosY, {0}.endPosZ>>; float $len = `mag ($b - $a)`; $len += 0.0000001; float $f = {1}.bulgeFactor / $len; scaleX = $f; scaleY = $f; """.format(midcircle.name(), maingrp.name()) pm.expression(o=midcircle, s=expression)