def run(params, rig): if not cmds.pluginInfo('matrixNodes', q=True, l=True): cmds.loadPlugin('matrixNodes') follicle = cmds.createNode('follicle') follicle_transform = cmds.listRelatives(follicle, p=True)[0] cmds.connectAttr('{}.outRotate'.format(follicle), '{}.rotate'.format(follicle_transform)) cmds.connectAttr('{}.outTranslate'.format(follicle), '{}.translate'.format(follicle_transform)) cmds.connectAttr('{}.worldMatrix'.format(params['geometry'].name()), '{}.inputWorldMatrix'.format(follicle)) cmds.parent(follicle_transform, rig['rigGroup']) geometry_dag_path = get_dag_path(params['geometry'].name()) m_point = om2.MPoint(cmds.xform(params['target'].name(), q=True, ws=True, t=True)) if geometry_dag_path.hasFn(om2.MFn.kTransform): dag_path = om2.MFnDagNode(geometry_dag_path).dagPath() dag_path.extendToShape(0) else: dag_path = geometry_dag_path if dag_path.hasFn(om2.MFn.kMesh): cmds.connectAttr('{}.worldMesh'.format(dag_path.partialPathName()), '{}.inputMesh'.format(follicle)) param_u_value, param_v_value, face_id = om2.MFnMesh(dag_path).getUVAtPoint(m_point, om2.MSpace.kWorld) elif dag_path.hasFn(om2.MFn.kNurbsSurface): cmds.connectAttr('{}.worldSpace'.format(dag_path.partialPathName()), '{}.inputSurface'.format(follicle)) param_u_value, param_v_value = om2.MFnNurbsSurface(dag_path).getParamAtPoint(m_point, om2.MSpace.kWorld) else: raise ValueError('`geometry` Parameter should be either a Mesh or Nurbs Surface') cmds.setAttr('{}.parameterU'.format(follicle), param_u_value) cmds.setAttr('{}.parameterV'.format(follicle), param_v_value) pc = cmds.parentConstraint(follicle_transform, params['target'].name(), mo=params['maintainOffset']) sc = cmds.scaleConstraint(follicle_transform, params['target'].name(), mo=params['maintainOffset']) cmds.parent(pc, sc, rig['noXformGroup'])
def populate_among_plane(surface, dag, num): sel = om.MSelectionList() sel.add(surface) plane = om.MFnNurbsSurface() plane.setObject(sel.getDagPath(0)) params = np.linspace(0, 1, num) new_dags = [] for par in params: new_dag = cmds.duplicate(dag)[0] pos = plane.getPointAtParam(0.5, par) cmds.xform(new_dag, t=(pos[0], pos[1], pos[2]), ws=True) new_dags.append(new_dag) for dag in new_dags: attach_to_surface(surface, dag, snap=True)
def closest_point_on_surface(surface, point): ''' find closest point on surface and it's UV values Args: surface (str): nurbs surface point tuple(float, float, float): position to reference Return: tuple(float, float, float), (int), (int): position, u param, v param ''' sel = om.MSelectionList() sel.add(surface) plane = om.MFnNurbsSurface() plane.setObject(sel.getDagPath(0)) point = om.MPoint(om.MVector(point)) pos, parU, parV = plane.closestPoint(point) return pos, parU, parV
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 compute(self, plug, dataBlock): if plug not in [self.output]: self.displayWarning(error='Unknown plug: {}'.format(plug)) return enabled = dataBlock.inputValue(self.enabled).asBool() offsetExtendsPosition = dataBlock.inputValue( self.offsetExtendsPosition).asBool() offset = dataBlock.inputValue(self.offset).asFloat() output_arrayHandle = dataBlock.outputArrayValue(self.output) output_builder = output_arrayHandle.builder() # get ray data indices = [] enablesExtra = [] inverseMatrices = [] raySources = [] rayDirections = [] hitPositions = [] hitDistances = [] offsetVectors = [] inputArrayHandle = dataBlock.inputArrayValue(self.input) for x in range(len(inputArrayHandle)): # get maya array input attributes inputArrayHandle.jumpToPhysicalElement(x) inputTargetHandle = inputArrayHandle.inputValue() index = inputArrayHandle.elementLogicalIndex() indices.append(index) position1 = om.MFloatPoint( inputTargetHandle.child(self.position1).asFloat3()) position2 = om.MFloatPoint( inputTargetHandle.child(self.position2).asFloat3()) eachOffset = offset + inputTargetHandle.child( self.offsetExtra).asFloat() inverseMatrices.append( inputTargetHandle.child( self.parentInverseMatrix).asFloatMatrix()) enablesExtra.append( inputTargetHandle.child(self.enabledExtra).asBool()) if not enabled or not enablesExtra[-1]: eachOffset = 0 # calculate ray rayDirection = position2 - position1 offsetVectors.append(rayDirection.normal() * eachOffset) if offsetExtendsPosition and eachOffset < 0: position1 += offsetVectors[-1] rayDirection -= offsetVectors[-1] hitDistances.append(rayDirection.length()) raySources.append(position1) rayDirections.append(rayDirection) hitPositions.append(position2) if enabled: # geometry loop inputGeometryArrayHandle = dataBlock.inputArrayValue( self.inputGeometry) for physicalGeoIndex in range(len(inputGeometryArrayHandle)): inputGeometryArrayHandle.jumpToPhysicalElement( physicalGeoIndex) inputGeometryHandle = inputGeometryArrayHandle.inputValue() targetData = inputGeometryHandle.data() if targetData.isNull(): continue targetType = inputGeometryHandle.type() if targetType == om.MFnMeshData.kMesh: meshFn = om.MFnMesh(targetData) def getClosestHit(source, direction): meshHit = meshFn.closestIntersection( source, direction, om.MSpace.kWorld, 1, False)[0] if meshHit == om.MFloatPoint(): return None return meshHit elif targetType == om.MFnNurbsSurfaceData.kNurbsSurface: nurbsFn = om.MFnNurbsSurface(targetData) def getClosestHit(source, direction): nurbsHit = nurbsFn.intersect(om.MPoint(source), om.MVector(direction), om.MSpace.kWorld) if nurbsHit is None: return None return om.MFloatPoint(nurbsHit[0]) else: raise ValueError( 'unknown targetType: {}'.format(targetType)) # ray loop for x, (index, enabledExtra, raySource, rayDirection) in enumerate( zip(indices, enablesExtra, raySources, rayDirections)): if not enabledExtra: continue hit = getClosestHit(raySource, rayDirection) if hit is None: continue hitDistance = (hit - raySource).length() if hitDistance < hitDistances[x]: hitPositions[x] = hit hitDistances[x] = hitDistance # set output for index, hitPosition, offsetVector, inverseMatrix in zip( indices, hitPositions, offsetVectors, inverseMatrices): output_handle = output_builder.addElement(index) outputPosition = (hitPosition - offsetVector) * inverseMatrix output_handle.set3Float(outputPosition[0], outputPosition[1], outputPosition[2]) output_arrayHandle.set(output_builder) output_arrayHandle.setAllClean() dataBlock.setClean(plug)
def attach_to_surface(surface, dag): """Takes a dag node and attaches it to the nearest point on a surface, replacement for a follicle Args: surface (str): name of the transform of the nurbs surface that the dag node will be attached to dag (str): name of the dag node which will be attached Returns: str: Name of transform that follows the surface """ # nodes to attach dag to surface POSI = cmds.createNode('pointOnSurfaceInfo', name=dag + '_POSI') matrix_node = cmds.createNode('fourByFourMatrix', name=dag + '_4X4') foll = cmds.createNode('transform', name=dag + '_custom_foll') foll_MSC = cmds.createNode('millSimpleConstraint', name=foll + '_MSC') MM = cmds.createNode('multMatrix', name=dag + '_MM') # find closest point on surface and it's UV values sel = om.MSelectionList() sel.add(surface) plane = om.MFnNurbsSurface() plane.setObject(sel.getDagPath(0)) point = om.MPoint(om.MVector(cmds.xform(dag, t=True, ws=True, q=True))) pos, parU, parV = plane.closestPoint(point) cmds.xform(dag, t=(pos[0], pos[1], pos[2]), ws=True) # attach dag to surface cmds.connectAttr(surface + '.local', POSI + '.inputSurface') cmds.setAttr(POSI + '.parameterU', parU) cmds.setAttr(POSI + '.parameterV', parV) # create matrix from POSI node cmds.connectAttr(POSI + '.normalizedTangentVX', matrix_node + '.in00') cmds.connectAttr(POSI + '.normalizedTangentVY', matrix_node + '.in01') cmds.connectAttr(POSI + '.normalizedTangentVZ', matrix_node + '.in02') cmds.connectAttr(POSI + '.normalizedNormalX', matrix_node + '.in10') cmds.connectAttr(POSI + '.normalizedNormalY', matrix_node + '.in11') cmds.connectAttr(POSI + '.normalizedNormalZ', matrix_node + '.in12') cmds.connectAttr(POSI + '.normalizedTangentUX', matrix_node + '.in20') cmds.connectAttr(POSI + '.normalizedTangentUY', matrix_node + '.in21') cmds.connectAttr(POSI + '.normalizedTangentUZ', matrix_node + '.in22') cmds.connectAttr(POSI + '.positionX', matrix_node + '.in30') cmds.connectAttr(POSI + '.positionY', matrix_node + '.in31') cmds.connectAttr(POSI + '.positionZ', matrix_node + '.in32') cmds.connectAttr(matrix_node + '.output', MM + '.matrixIn[0]') cmds.connectAttr(surface + '.worldMatrix[0]', MM + '.matrixIn[1]') cmds.connectAttr(MM + '.matrixSum', foll_MSC + '.inMatrix') cmds.connectAttr(foll + '.parentInverseMatrix[0]', foll_MSC + '.parentInverseMatrix') cmds.connectAttr(foll_MSC + '.outTranslate', foll + '.translate') cmds.connectAttr(foll_MSC + '.outRotate', foll + '.rotate') constraint.simple_constraint(foll, dag) return foll
def compute(self, plug, dataBlock): if plug not in [self.output]: self.displayWarning(error='Unknown plug: {}'.format(plug)) return enabled = dataBlock.inputValue(self.enabled).asBool() offsetExtendsPositions = dataBlock.inputValue( self.offsetExtendsPositions).asBool() offset = dataBlock.inputValue(self.offset).asFloat() output_arrayHandle = dataBlock.outputArrayValue(self.output) output_builder = output_arrayHandle.builder() indices = [] position1_list = [] position2_list = [] inverseMatrices = {} finalOffsets = [] enablesExtra = [] raySources = [] rayDirections = [] # get rays inputArrayHandle = dataBlock.inputArrayValue(self.input) for i in range(len(inputArrayHandle)): inputArrayHandle.jumpToPhysicalElement(i) inputTargetHandle = inputArrayHandle.inputValue() index = inputArrayHandle.elementLogicalIndex() indices.append(index) position1 = om.MFloatPoint( inputTargetHandle.child(self.position1).asFloat3()) position1_list.append(position1) position2 = om.MFloatPoint( inputTargetHandle.child(self.position2).asFloat3()) position2_list.append(position2) finalOffset = offset + inputTargetHandle.child( self.offsetExtra).asFloat() raySource = position1 rayDirection = position2 - position1 if offsetExtendsPositions and finalOffset: offsetVector = rayDirection.normal() * finalOffset if finalOffset > 0: rayDirection += offsetVector elif finalOffset < 0: raySource += offsetVector raySources.append(raySource) rayDirections.append(rayDirection) finalOffsets.append(finalOffset) inverseMatrices[index] = inputTargetHandle.child( self.parentInverseMatrix).asFloatMatrix() enablesExtra.append( inputTargetHandle.child(self.enabledExtra).asBool()) # find closest intersections closestHits = {i: None for i in indices} offsetVectors = {i: None for i in indices} if enabled: inputGeometryArrayHandle = dataBlock.inputArrayValue( self.inputGeometry) for i in range(len(inputGeometryArrayHandle)): inputGeometryArrayHandle.jumpToPhysicalElement(i) inputGeometryHandle = inputGeometryArrayHandle.inputValue() targetData = inputGeometryHandle.data() if targetData.isNull(): continue targetType = inputGeometryHandle.type() if targetType == om.MFnMeshData.kMesh: meshFn = om.MFnMesh(targetData) def getClosestHit(source, direction): meshHit = meshFn.closestIntersection( source, direction, om.MSpace.kWorld, 1, False)[0] if meshHit == om.MFloatPoint(): return None return meshHit elif targetType == om.MFnNurbsSurfaceData.kNurbsSurface: nurbsFn = om.MFnNurbsSurface(targetData) def getClosestHit(source, direction): nurbsHit = nurbsFn.intersect(om.MPoint(source), om.MVector(direction), om.MSpace.kWorld) if nurbsHit is None: return None return om.MFloatPoint(nurbsHit[0]) else: raise ValueError( 'unknown targetType: {}'.format(targetType)) for index, raySource, rayDirection, finalOffset, enabledExtra in zip( indices, raySources, rayDirections, finalOffsets, enablesExtra): if not enabledExtra: continue hit = getClosestHit(raySource, rayDirection) if hit is None: continue if closestHits[index] is None or \ (hit - raySource).length() < (closestHits[index] - raySource).length(): closestHits[index] = hit if finalOffset: closestHitVector = raySource - hit if finalOffset > closestHitVector.length(): offsetVectors[index] = closestHitVector else: offsetVectors[index] = closestHitVector.normal( ) * finalOffset # set output for index, hit in closestHits.iteritems(): output_handle = output_builder.addElement(index) if hit is None: hit = position2_list[indices.index(index)] elif offsetVectors[index]: hit += offsetVectors[index] hit *= inverseMatrices[index] output_handle.set3Float(hit[0], hit[1], hit[2]) output_arrayHandle.set(output_builder) output_arrayHandle.setAllClean() dataBlock.setClean(plug)
def Apply(self, matrix): maya_cmds.undoInfo(stateWithoutFlush=False) try: shapes = maya_cmds.ls(maya_cmds.listRelatives(self.transforms, path=True, allDescendents=True), shapes=True) pivR = [] pivS = [] for i in xrange(len(self.transforms)): pivR.append( maya_cmds.xform(self.transforms[i], q=True, worldSpace=True, rotatePivot=True)) pivS.append( maya_cmds.xform(self.transforms[i], q=True, worldSpace=True, scalePivot=True)) maya_cmds.xform(self.transforms[i], worldSpace=True, zeroTransformPivots=True) mPoints = [] for i in xrange(len(shapes)): mDagPath = OpenMaya.MGlobal.getSelectionListByName( shapes[i]).getDagPath(0) objectType = maya_cmds.objectType(shapes[i]) if objectType == 'mesh': mPoints.append( OpenMaya.MFnMesh(mDagPath).getPoints( OpenMaya.MSpace.kWorld)) elif objectType == 'nurbsCurve': mPoints.append( OpenMaya.MFnNurbsCurve(mDagPath).cvPositions( OpenMaya.MSpace.kWorld)) elif objectType == 'nurbsSurface': mPoints.append( OpenMaya.MFnNurbsSurface(mDagPath).cvPositions( OpenMaya.MSpace.kWorld)) else: raise TypeError('Not supported object type: ' + objectType) for i in xrange(len(self.transforms)): if self.matrixIs.movX: maya_cmds.setAttr(self.transforms[i] + '.translateX', matrix[i].movX) if self.matrixIs.movY: maya_cmds.setAttr(self.transforms[i] + '.translateY', matrix[i].movY) if self.matrixIs.movZ: maya_cmds.setAttr(self.transforms[i] + '.translateZ', matrix[i].movZ) if self.matrixIs.rotX: maya_cmds.setAttr(self.transforms[i] + '.rotateX', matrix[i].rotX) if self.matrixIs.rotY: maya_cmds.setAttr(self.transforms[i] + '.rotateY', matrix[i].rotY) if self.matrixIs.rotZ: maya_cmds.setAttr(self.transforms[i] + '.rotateZ', matrix[i].rotZ) if self.matrixIs.scaX: maya_cmds.setAttr(self.transforms[i] + '.scaleX', matrix[i].scaX) if self.matrixIs.scaY: maya_cmds.setAttr(self.transforms[i] + '.scaleY', matrix[i].scaY) if self.matrixIs.scaZ: maya_cmds.setAttr(self.transforms[i] + '.scaleZ', matrix[i].scaZ) maya_cmds.xform(self.transforms[i], worldSpace=True, rotatePivot=pivR[i], scalePivot=pivS[i]) for i in xrange(len(shapes)): mDagPath = OpenMaya.MGlobal.getSelectionListByName( shapes[i]).getDagPath(0) objectType = maya_cmds.objectType(shapes[i]) if objectType == 'mesh': mFnMesh = OpenMaya.MFnMesh(mDagPath) mFnMesh.setPoints(mPoints[i], OpenMaya.MSpace.kWorld) mFnMesh.updateSurface() elif objectType == 'nurbsCurve': mFnNurbsCurve = OpenMaya.MFnNurbsCurve(mDagPath) mFnNurbsCurve.setCVPositions(mPoints[i], OpenMaya.MSpace.kWorld) mFnNurbsCurve.updateCurve() elif objectType == 'nurbsSurface': mFnNurbsSurface = OpenMaya.MFnNurbsSurface(mDagPath) mFnNurbsSurface.setCVPositions(mPoints[i], OpenMaya.MSpace.kWorld) mFnNurbsSurface.updateSurface() except Exception as e: print >> stderr, str(e) maya_cmds.undoInfo(stateWithoutFlush=True)