def compute(self,plug,dataBlock): if plug == fakeSpring.outputA or plug == fakeSpring.outputB: start = dataBlock.inputValue(fakeSpring.start).asFloat3() startPos = om.MVector(start) end = dataBlock.inputValue(fakeSpring.end).asFloat3() endPos = om.MVector(end) stiffness = dataBlock.inputValue(fakeSpring.stiffness).asFloat() length = dataBlock.inputValue(fakeSpring.length).asFloat() directionalVector = endPos - startPos offset = (directionalVector.length() - length)/2.0 scalor = (offset / directionalVector.length()) * stiffness outputAPos = startPos + (directionalVector * scalor) outputBPos = endPos - (directionalVector * scalor) outputA = dataBlock.outputValue(fakeSpring.outputA) outputAPosition = om.MFloatVector(outputAPos.x, outputAPos.y, outputAPos.z) outputA.setMFloatVector(outputAPosition) outputA.setClean() outputB = dataBlock.outputValue(fakeSpring.outputB) outputBPosition = om.MFloatVector(outputBPos.x, outputBPos.y, outputBPos.z) outputB.setMFloatVector(outputBPosition) outputB.setClean() dataBlock.setClean(plug)
def calculateNewNormal(self, v): """ :type v: components.Vertex """ polySets = [] for polygon in v.polygons: ps = components.PolySet(polygon) ps.addPolygons(self.getGrownPolygons(polygon)) polySets.append(ps) numPolySets = len(polySets) if numPolySets == 1: return om.MFloatVector(polySets[0].normal) polySets.sort(key=operator.attrgetter('area'), reverse=True) if numPolySets == 2: if polySets[0] == polySets[1]: return om.MFloatVector( com.vectorsMean(polySets[0].normal, polySets[1].normal)) else: return om.MFloatVector(polySets[0].normal) midArea = polySets[0].area - (polySets[0].area - polySets[-1].area) * 0.5 masterNormals = [ps.normal for ps in polySets if ps.area >= midArea] return om.MFloatVector(com.vectorsMean(*masterNormals))
def vectorCalc(vec, matrix): if (not isinstance(matrix, om.MMatrix)): return vec vm = om.MMatrix([[vec.x, 0, 0, 1], [0, vec.y, 0, 1], [0, 0, vec.z, 1], [0, 0, 0, 1]]) res = vm * matrix result = om.MFloatVector(res.getElement(0, 0), res.getElement(1, 1), res.getElement(2, 2)) return om.MFloatVector(result)
def __init__(self): om.MPxNode.__init__(self) self._initialize = False self._currentPosition = om.MFloatVector() self._previousPosition = om.MFloatVector() self._currentTime = om.MObject() self._previousTime = om.MObject()
def expand_to(self, data, n, setRandom=False): if len(data) >= n: return old_size = len(data) add_size = n - old_size for i in range(add_size): if not setRandom: data.append(om.MFloatVector(0.0, 0.0, 0.0)) else: x = random.uniform(-1.0, 1.0) y = random.uniform(-1.0, 1.0) z = random.uniform(-1.0, 1.0) data.append(om.MFloatVector(x, y, z))
def intersect(mesh, point, ray): ''' This is probably some foundation for the yet-to-be surface follow stuff. ''' fnMesh = OpenMaya.MFnMesh(pdil.capi.asMObject(mesh.getShape()).object()) p = spaceLocator() p.t.set(point) p.setParent(mesh) objSpacePos = p.t.get() p.setTranslation(ray, space='world') objSpaceRay = p.t.get() - objSpacePos point = OpenMaya.MFloatPoint(objSpacePos) ray = OpenMaya.MFloatVector(objSpaceRay) res = fnMesh.allIntersections(point, ray, OpenMaya.MSpace.kObject, 50, False) # -> (hitPoints, hitRayParams, hitFaces, hitTriangles, hitBary1s, hitBary2s) if not len(res[0]): hits = [] else: hits = [] for hit in res[0]: p.t.set(hit.x, hit.y, hit.z) hits.append(p.getTranslation(space='world')) delete(p) return hits
def get_coord_on_drag(self, selected, ctx): vpX, vpY, _ = cmds.draggerContext(ctx, query=True, dragPoint=True) position = om.MPoint() # 3D point with double-precision coordinates direction = om.MVector() # 3D vector with double-precision coordinates omui.M3dView().active3dView().viewToWorld( int(vpX), int(vpY), position, # world point direction) # world vector for mesh in selected: selectionList = om.MSelectionList() selectionList.add(mesh) dagPath = selectionList.getDagPath(0) fnMesh = om.MFnMesh(dagPath) intersection = fnMesh.closestIntersection( om.MFloatPoint(position), # raySource om.MFloatVector(direction), # rayDirection om.MSpace.kWorld, # space 99999, # maxParam True) # testBothDirections hitPoint, hitRayParam, hitFace, hitTriangle, \ hitBary1, hitBary2 = intersection x, y, z, _ = hitPoint return x, y, z
def intersectionAPI2(): """ Select two objects. the second shot a ray at its X axis over the first. return: id face collision """ mSelList = OpenMaya.MGlobal.getActiveSelectionList() dagPath0 = mSelList.getDagPath(0) dagPath0.extendToShape() mfnMesh0 = OpenMaya.MFnMesh(dagPath0) dagPath1 = mSelList.getDagPath(1) mfnTransform = OpenMaya.MFnTransform(dagPath1) testBothDirections = False maxParamPtr = 9999999.0 space = OpenMaya.MSpace.kWorld spaceVector = OpenMaya.MSpace.kTransform raySource = OpenMaya.MFloatPoint(mfnTransform.rotatePivot(space)) # print raySource rayDirectionMatrix = mfnTransform.rotation(spaceVector).asMatrix() rayDirection = OpenMaya.MFloatVector(rayDirectionMatrix[0], rayDirectionMatrix[1], rayDirectionMatrix[2]) # http://zoomy.net/2009/07/31/fastidious-python-shrub/ hit = mfnMesh0.closestIntersection(raySource, rayDirection, space, maxParamPtr, testBothDirections) pm.select('%s.f[%s]' % (dagPath0, hit[2])) print(hit)
def convertToPointOnProjPlane(pointO, point, v2X, v2Y, distance): vectorTmp = ompy.MFloatVector(point.x - pointO.x, point.y - pointO.y, point.z - pointO.z) vectorTmp.normalize() pointTmp = pointO + vectorTmp * distance planeCoords = [ pointTmp.x, pointTmp.y, pointTmp.z, pointTmp.x + v2X.x, pointTmp.y + v2X.y, pointTmp.z + v2X.z, pointTmp.x + v2Y.x, pointTmp.y + v2Y.y, pointTmp.z + v2Y.z ] lineCoords = [pointO.x, pointO.y, pointO.z, point.x, point.y, point.z] iPoint = utils_getLinePlaneIntersectionPoint(lineCoords, planeCoords) return ompy.MFloatVector(iPoint[0], iPoint[1], iPoint[2])
def _closestIntersection(self, dagPath, worldPt, worldVector): """Return the closest intersection data for the given mesh with the given point and vector. :param dagPath: The MDagPath of the mesh object. :type dagPath: om2.MDagPath :param worldPt: The world point of the ray to test for intersection with. :type worldPt: om2.MPoint :param worldVector: The MVector of the intersection ray. :type worldVector: om2.MVector :return: The tuple with the intersection data: hitPoint: The intersection point. hitRayParam: The ray length to the intersection. hitFace: The face index of the intersection. hitTriangle: The relative index of the trangle. hitBary1: First barycentric coordinate. hitBary2: Second barycentric coordinate. :rtype: tuple(om2.MFloatPoint, float, int, int, float, float) """ meshFn = om2.MFnMesh(dagPath) accelParams = om2.MMeshIsectAccelParams() accelParams = meshFn.autoUniformGridParams() return meshFn.closestIntersection( om2.MFloatPoint(worldPt), om2.MFloatVector(worldVector), om2.MSpace.kWorld, 100000, # maxParam True)
def onPress(): vpX, vpY, _ = cmds.draggerContext(context, query=True, dragPoint=True) pos = om.MPoint() dir = om.MVector() omui.M3dView().active3dView().viewToWorld(int(vpX), int(vpY), pos, dir) for mesh in cmds.ls(type='mesh'): selectionList = om.MSelectionList() selectionList.add(mesh) dagPath = selectionList.getDagPath(0) fnMesh = om.MFnMesh(dagPath) hit = fnMesh.allIntersections(om.MFloatPoint(pos), om.MFloatVector(dir), om.MSpace.kWorld, 99999, False) if hit: try: hit1 = hit[0][0] hit2 = hit[0][1] mySel = cmds.ls(sl=True)[-1] pos = [(hit1[0] + hit2[0]) / 2, (hit1[1] + hit2[1]) / 2, (hit1[2] + hit2[2]) / 2] cmds.setAttr(mySel + '.translate', pos[0], pos[1], pos[2], type='double3') except: pass
def getLightDirection(name): selList = oom.MSelectionList() selList.add(name) lightDagPath = oom.MDagPath() selList.getDagPath(0, lightDagPath) lightFn = oom.MFnSpotLight(lightDagPath) rayDir = lightFn.lightDirection(0, oom.MSpace.kWorld) return om.MFloatVector(rayDir)
def click(s): try: # Grab mouse co-ords on screen viewX, viewY, viewZ = cmds.draggerContext(s.myTool, q=True, ap=True) position = om.MPoint() direction = om.MVector() # Convert 2D screen positions into 3D world positions omui.M3dView().active3dView().viewToWorld(int(viewX), int(viewY), position, direction) sel = om.MSelectionList() sel.add(s.sel) dagPath = sel.getDagPath(0) fnMesh = om.MFnMesh(dagPath) intersection = fnMesh.closestIntersection( om.MFloatPoint(position), om.MFloatVector(direction), om.MSpace.kWorld, 99999, False) # Did our ray intersect with the object? if intersection: hitPoint, hitRayParam, hitFace, hitTriangle, hitBary1, hitBary2 = intersection if hitTriangle != -1: # Grab Skin Cluster skin = mel.eval("findRelatedSkinCluster %s" % s.sel) if skin: # Get Face points cmds.select("%s.f[%s]" % (s.sel, hitFace)) face = cmds.polyInfo(fv=True) # Get vertexes verts = [ "%s.vtx[%s]" % (s.sel, v) for v in findall(r"\s(\d+)\s", face[0]) ] # Get Joints cmds.select(verts, r=True) joints = cmds.skinPercent(skin, q=True, t=None) # Get weights weights = sorted( [(j, cmds.skinPercent(skin, t=j, q=True)) for j in joints], key=lambda x: x[1], reverse=True) cmds.select(weights[0][0], r=True) else: print "No skin found" # Return to previous tool cmds.setToolTo(s.tool) cmds.refresh() except RuntimeError: print "There was an issue selecting the object."
def inMesh(meshObj, positions, maxRes=100): '''{'del_path':'Polygons/QueryMesh/inMesh()ONLYSE', 'icon':':/polyMesh.png', 'usage':'\ meshObj = cmds.ls(sl=True)[-1]\\n\ objs = cmds.ls(sl=True)[:-1]\\n\ positions = []\\n\ for obj in objs:\\n\ positions.append( cmds.getAttr(obj+".t")[0] )\\n\\n\ inMeshData = $fun(meshObj, positions )\\n\ inMeshObjs=[]\\n\ for obj in objs:\\n\ if inMeshData[ objs.index(obj) ]:\\n\ inMeshObjs.append( obj )\\n\ if inMeshObjs:\\n\ cmds.select(inMeshObjs, r=True)\\n\ mel:\\n\ string $object = "pCube1";\\n\ vector $pos = <<0,0,0>>;\\n\ python("$fun(\""+$object+"\",["+$pos.x+"," +$pos.y+"," +$pos.z+"])");', } ''' meshs = newom.MSelectionList() meshs.add(meshObj) meshDagPath = meshs.getDagPath(0) meshFn = newom.MFnMesh(meshDagPath) divSize = emfx_getVoxelSize(meshObj, maxRes) bbox = cmds.exactWorldBoundingBox(meshObj, ignoreInvisible=False) xDiv = math.fabs(bbox[3] - bbox[0]) / divSize yDiv = math.fabs(bbox[4] - bbox[1]) / divSize zDiv = math.fabs(bbox[5] - bbox[2]) / divSize meshAcceleration = meshFn.uniformGridParams(int(xDiv), int(yDiv), int(zDiv)) whethers = [] rayDirection = newom.MFloatVector(0, -1, 0) for pos in positions: hitPoints = meshFn.allIntersections(newom.MFloatPoint(pos), rayDirection, newom.MSpace.kWorld, 9999.0, False, accelParams=meshAcceleration)[0] whethers.append(True if len(hitPoints) % 2 == 1 else False) meshFn.clearGlobalIntersectionAcceleratorInfo() return whethers
def meshIntersect(edgeVertsCoord=None, mesh2Intersect=None): '''see if a given edge(2 verts) interesects with mesh2Intersect ''' # see if given mesh or edgeVertsCoord intersects with target mesh or not mSelList = om.MSelectionList() mDagPath = om.MDagPath() targetMesh = "%s" % mesh2Intersect mSelList.add(targetMesh) targetDagP = mSelList.getDagPath(0) targetMfnSet = om.MFnMesh(targetDagP) edgeCount = len(edgeVertsCoord) hitCount = 0 for coord in edgeVertsCoord: rayStartPos = om.MFloatPoint(coord[0]) rayEndPos = om.MFloatPoint(coord[1]) rayVec = om.MFloatVector(rayEndPos - rayStartPos) rayLen = rayVec.length() infoList = targetMfnSet.closestIntersection(rayStartPos, rayVec, om.MSpace.kWorld, 999, False) hitPos = infoList[0] hitParem = infoList[1] hitLen = om.MVector(hitPos - rayStartPos).length() if hitParem == 0: # not even hit at all continue elif hitParem != 0: if hitLen <= rayLen: #print True return True # once a function does return, it ends the function else: # hit point is further than the length of the edge, not intersecting hitCount += 1 if hitCount == edgeCount: #print hitCount,edgeCount #print "inside geo or target too small" return False #print hitCount,edgeCount #print False return False
def get_ray_mesh_intersection(mesh, direction=[0,-1 ,0], origin=[0,1,0]): direction_v = om.MFloatVector(direction[0],direction[1],direction[2]) origin_p = om.MFloatPoint(origin[0],origin[1],origin[2]) # return om.MVector(pnt1-pnt2).length() selectionList = om.MSelectionList() selectionList.add(mesh) nodeDagPath = selectionList.getDagPath(0) mfn = om.MFnMesh(nodeDagPath) intersection = mfn.closestIntersection(origin_p, direction_v, om.MSpace.kWorld, 99999999, False) #return intersection#list(intersection[0])[:-1] vector = list(intersection[0])[:-1] distance = maths.distanceBetween(origin, vector) return {'vector':vector, 'distance':distance}
def rayMeshIntersect(mesh, pos, vector): ''' Example: mover = cmds.ls(sl=1)[0] mesh = 'steel' pos = cmds.xform(mover, q=1, rp=1, ws=1) newPos = rayMeshIntersect(mesh, pos, -utils.getAxisWorldVectors(mover)[1]) cmds.xform(mover, t=newPos, ws=1) ''' nodePos = om2.MPoint(pos[0], pos[1], pos[2], 1.0) vector = om2.MVector(vector) obj, dag, stringPath = dagPathFromName(mesh) meshFn = om2.MFnMesh(dag) selectionList = om2.MSelectionList() selectionList.add(mesh) dagPath = selectionList.getDagPath(0) fnMesh = om2.MFnMesh(dagPath) intersection = fnMesh.closestIntersection(om2.MFloatPoint(pos), om2.MFloatVector(vector), om2.MSpace.kWorld, 99999, False) if intersection: hitPoint, hitRayParam, hitFace, hitTriangle, hitBary1, hitBary2 = intersection x, y, z, _ = hitPoint return (x, y, z)
def reader(self, fileObject, optionString, accessMode): drc = Draco() mesh = drc.decode(fileObject.fullName()) # vertices, normals, uvs vertices = [] normals = [] us = OpenMaya.MFloatArray() vs = OpenMaya.MFloatArray() poly_count = [3] * mesh.faces_num for n in range(mesh.vertices_num): i = 3 * n vertices.append( OpenMaya.MPoint(mesh.vertices[i], mesh.vertices[i + 1], mesh.vertices[i + 2])) if mesh.normals: normals.append( OpenMaya.MFloatVector(mesh.normals[i], mesh.normals[i + 1], mesh.normals[i + 2])) if mesh.uvs: i = 2 * n us.append(mesh.uvs[i]) vs.append(mesh.uvs[i + 1]) #create mesh fnMesh = OpenMaya.MFnMesh() newMesh = fnMesh.create(vertices, poly_count, mesh.faces) if mesh.normals: fnMesh.setVertexNormals(normals, range(len(vertices))) if mesh.uvs: uvSetsNames = fnMesh.getUVSetNames() fnMesh.setUVs(us, vs, uvSetsNames[0]) fnMesh.assignUVs(poly_count, mesh.faces) fnMesh.updateSurface() slist = OpenMaya.MGlobal.getSelectionListByName("initialShadingGroup") initialSG = slist.getDependNode(0) fnSG = OpenMaya.MFnSet(initialSG) if fnSG.restriction() == OpenMaya.MFnSet.kRenderableOnly: fnSG.addMember(newMesh)
def checkHit(): sel = om.MGlobal.getActiveSelectionList() mesh_fn = loc_fn = None if sel.length(): mesh_dag = sel.getDagPath(0) if mesh_dag.hasFn(om.MFn.kMesh): mesh_fn = om.MFnMesh(mesh_dag) loc_dag = sel.getDagPath(1) if loc_dag.hasFn(om.MFn.kTransform): loc_fn = om.MFnTransform(loc_dag) print mesh_fn, loc_fn ray_src = om.MFloatPoint(loc_fn.translation(om.MSpace.kWorld)) ray_dir = om.MFloatVector(0,0,1) hit_points = mesh_fn.allIntersections(ray_src, ray_dir, om.MSpace.kObject, 9999, False ) for p in hit_points[0]: loc = pm.spaceLocator() pm.move(loc, [p[0], p[1], p[2]])
def rayIntersect(pos, dir, mesh): pos2 = om.MFloatPoint(pos.x, pos.y, pos.z) dir = om.MFloatVector(dir.x, dir.y, dir.z) selectionList = om.MSelectionList() selectionList.add(mesh) dagPath = om.MDagPath() sel = selectionList.getDagPath(0) fnMesh = om.MFnMesh(sel) intersection = fnMesh.closestIntersection(pos2, dir, om.MSpace.kWorld, 9999, False) hitpoint = intersection[0] faceId = intersection[2] if intersection: x = hitpoint.x y = hitpoint.y z = hitpoint.z return x, y, z, faceId else: return None
def positionsOnMesh(meshObj, position, rayDirection=False): '''{'del_path':'Polygons/QueryMesh/positionsOnMesh()ONLYSE', 'usage':'\ meshObj = cmds.ls(sl=True)[-1]\\n\ objs = cmds.ls(sl=True)[:-1]\\n\ position = []\\n\ for obj in objs:\\n\ position.append( cmds.getAttr(obj+".t")[0] )\\n\ newPos = $fun(meshObj, position, rayDirection=(0,-1,0) )\\n\ for obj in objs:\\n\ pos = newPos[ objs.index(obj) ]\\n\ cmds.setAttr(obj+""t", pos[0], pos[1], pos[2], type="double3")', } ''' meshs = newom.MSelectionList() meshs.add(meshObj) meshDagPath = meshs.getDagPath(0) meshFn = newom.MFnMesh(meshDagPath) newPos = [] if rayDirection == False: print rayDirection for pos in position: newPos.append( tuple( meshFn.getClosestPoint(newom.MPoint(pos), newom.MSpace.kWorld)[0])) else: rayDirection = newom.MFloatVector(rayDirection) for pos in position: raySource = newom.MFloatPoint(pos) hitPoint = tuple( meshFn.closestIntersection(raySource, rayDirection, newom.MSpace.kWorld, 9999.0, False)[0]) hitPos = pos if hitPoint == (0, 0, 0, 1) else hitPoint newPos.append(hitPos) return newPos
def test_mesh_intersection(current_mesh, target_mesh): # get intersection bbox inter_bbox = get_inter_bbox(current_mesh.boundingBox(), target_mesh.boundingBox()) # check if edge of current mesh intersect to face of target mesh all_hit_faces = [] all_hit_points = [] for edge in target_mesh.edges: sour_point = om.MPoint(edge.getPoint(0, 'world')) end_point = om.MPoint(edge.getPoint(1, 'world')) # ignore edge not in inter bbox if not (inter_bbox.contains(sour_point) or inter_bbox.contains(end_point)): continue # do test current_mesh_om = om.MFnMesh(pynode_to_api2(current_mesh)) edge_vector = end_point - sour_point edge_len = edge_vector.length() edge_vector.normalize() speedup_param = current_mesh_om.autoUniformGridParams() hitPoints, _, hit_faces, _, _, _ = current_mesh_om.allIntersections( om.MFloatPoint(sour_point), # 射线起点 om.MFloatVector(edge_vector), # 射线方向 om.MSpace.kWorld, # 世界空间 edge_len, # 测试距离,超出此距离的命中不算 False, # 不进行双向测试 accelParams=speedup_param # 加速参数 ) all_hit_points.extend(hitPoints) all_hit_faces.extend( [current_mesh.f[face_id] for face_id in hit_faces]) # TODO locator 生成位置不对 # [pm.spaceLocator(p=(pt.x,pt.y,pt.z)) for pt in all_hit_points] return all_hit_faces
def getVoxels(self, pVoxelDistance, pMeshObj, pBoundingBox): ''' Obtain a list of voxels as a set of (x,y,z) coordinates in the mesh local space. We obtain these voxels by casting rays from points separated pVoxelDistance apart within the mesh bounding box, and test whether or not these points are contained within the mesh. A point is contained within a closed mesh if the ray shot from the point intersects an odd number of times with the surface of the mesh. ''' # Initialize a list of voxels contained within the mesh. voxels = [] # Get a reference to the MFnMesh function set, and use it on the given mesh object. meshFn = OpenMaya.MFnMesh(pMeshObj) # Compute an offset which we will apply to the min and max corners of the bounding box. halfVoxelDist = 0.5 * pVoxelDistance # Offset the position of the minimum point to account for the inter-voxel distance. minPoint = pBoundingBox.min minPoint.x += halfVoxelDist minPoint.y += halfVoxelDist minPoint.z += halfVoxelDist # Offset the position of the maximum point to account for the inter-voxel distance. maxPoint = pBoundingBox.max maxPoint.x += halfVoxelDist maxPoint.y += halfVoxelDist maxPoint.z += halfVoxelDist # Define an iterator which will allow us to step through the pVoxelDistance # point intervals contained within our bounding box. We use this iterator # in the for loops that follow to visit each voxel center in the bounding box. def floatIterator(start, stop, step): r = start while r < stop: yield r r += step # Iterate over every point in the bounding box, stepping by pVoxelDistance... for xCoord in floatIterator(minPoint.x, maxPoint.x, pVoxelDistance): for yCoord in floatIterator(minPoint.y, maxPoint.y, pVoxelDistance): for zCoord in floatIterator(minPoint.z, maxPoint.z, pVoxelDistance): # 2D representation of a ray cast from the point within the bounding box: # # (+) ^----------------- # | | # y | | - We are shooting the ray from the point: [*] # axis | <======[*] | - The direction of the ray is parallel to the -Z axis. # | | # | | # (-) ------------------> # (-) z axis (+) # # If the ray intersects with an odd number of points along the surface of the mesh, the # point is contained within the mesh (assuming a closed mesh). raySource = OpenMaya.MFloatPoint(xCoord, yCoord, zCoord) rayDirection = OpenMaya.MFloatVector(0, 0, -1) # intersectionPoints = OpenMaya.MFloatPointArray() tolerance = 0.0001 ret = meshFn.allIntersections( raySource, # raySource - where we are shooting the ray from. rayDirection, # rayDirection - the direction in which we are shooting the ray. OpenMaya.MSpace.kTransform, # coordinate space - the mesh's local coordinate space. float(9999), # maxParam - the range of the ray. False, # testBothDirections - we are not checking both directions from the raySource tolerance=tolerance, # tolerance - a numeric tolerance threshold which allow intersections to occur just outside the mesh. ) # Returns a tuple of: # -> (hitPoints, hitRayParams, hitFaces, hitTriangles, hitBary1s, hitBary2s) # If there is an odd number of intersection points, then the point lies within the mesh. Otherwise, # the point lies outside the mesh. We are only concerned with voxels whose centerpoint lies within the mesh if (len(ret[0]) % 2 == 1): voxels.append(raySource) # Return the list of voxel coordinates which lie within the mesh. return voxels
def doIt(self,args): """ The doIt method should collect whatever information is required to do the task, and store it in local class data. It should finally call redoIt to make the command happen. """ self.parseArguments(args) # GET Joint DATA jointFn=om.MFnDagNode(self.Joint_dagPath) if jointFn.childCount()==1: next_joint_obj=jointFn.child(0) elif jointFn.childCount()>1:# Belly, Neck for i in range(jointFn.childCount()): tmpObj=jointFn.child(i) tmpFn=om.MFnDagNode(tmpObj) tmpName=tmpFn.name() if ("Chest" in tmpName) or ("Head" in tmpName): next_joint_obj=jointFn.child(i) elif jointFn.childCount()==0 and jointFn.parentCount()==1:# Hip Hand Toe Top next_joint_obj=jointFn.parent(0) nextJointFn=om.MFnDagNode(next_joint_obj) self.nextJoint_dagPath = nextJointFn.getPath() self.nextJoint_name=nextJointFn.name() # To avoid issues like freezeTransform, recommend rotate pivot to attain the position joint_position=cmds.xform(self.joint_name,absolute=True,query=True,worldSpace=True,rotatePivot=True) joint_position=om.MVector(joint_position[0],joint_position[1],joint_position[2]) nextjoint_position=cmds.xform(self.nextJoint_name,absolute=True,query=True,worldSpace=True,rotatePivot=True) nextjoint_position=om.MVector(nextjoint_position[0],nextjoint_position[1],nextjoint_position[2]) ray_center=linear_interpolate_3D(joint_position,nextjoint_position,self.u_parameter) # GET THE LOCAL FRAME ON THE CHOOSEN JOINT VAxis=(joint_position-nextjoint_position).normalize() if VAxis.y<0: VAxis=-VAxis UAxis=om.MVector.kXaxisVector # this is not a real normal! just an intermiediate vector if abs(VAxis*UAxis)>0.99: UAxix=om.MVector.kZaxisVector WAxis=UAxis^VAxis WAxis.normalize() UAxis=VAxis^WAxis UAxis.normalize() # Find the quaternion that form the coordinate transformation of # joint's local framework: how the new coordinate get back into world coordinate quaternion=getQuaternion(UAxis,VAxis,WAxis) transform_name=self.joint_name+"_cross_section"+"_u_at_"+str(int(self.u_parameter*100))+"_percentage" dirPath=cmds.workspace(q=True, rootDirectory=True ) #EXTRACT CROSS SECTION CURVES meshFn=om.MFnMesh(self.mesh_dagPath) raySource=om.MFloatPoint(ray_center) eps=om.MPointArray() eps.clear() epsLocal=om.MPointArray() epsLocal.clear() for i in range(0,self.division): angle=2*math.pi*float(i)/float(self.division) ray=UAxis.rotateBy(om.MQuaternion(angle,VAxis)) rayDirection=om.MFloatVector(ray) try: hitPoint, hitRayParam, hitFace, hitTriangle, hitBary1, hitBary2 = meshFn.closestIntersection(raySource,rayDirection,om.MSpace.kWorld,9999,False,idsSorted=False,tolerance=0.001) except: raise else: eps.append(hitPoint) hitPointLocal=om.MVector(hitPoint[0],hitPoint[1],hitPoint[2]) hitPointLocal-=ray_center # This is the quaternion that transform a point from world coordinate into local coordinate # Hence, we need to inverse the quaternion we get above hitPointLocal=hitPointLocal.rotateBy(quaternion.inverse()) epsLocal.append(hitPointLocal) curveFn=om.MFnNurbsCurve() self.cross_section_obj=curveFn.createWithEditPoints(eps,2,om.MFnNurbsCurve.kClosed, False, False, True) dgFn=om.MFnDependencyNode(self.cross_section_obj) dgFn.setName(transform_name) # add custom attribute to node attrFn=om.MFnNumericAttribute() uAttr=attrFn.create("uParameter","u",om.MFnNumericData.kFloat,self.u_parameter) attrFn.readable=True attrFn.storable=True # fairly consistent, won't change in compute() or get updated by upstream node, etc attrFn.writable=True attrFn.keyable=True attrFn.hidden=False dgFn.addAttribute( uAttr) om.MPxCommand.setResult(om.MFnDependencyNode(self.cross_section_obj).name()) #,om.MFnDependencyNode(self.cross_section_obj_meta).name()]) save_path=dirPath+'data/' complete_name=os.path.join(save_path,transform_name+'.dat') outFile=open(complete_name,'w+')# Here we used "w" letter in our argument, which indicates write and the plus sign that means it will create a file if it does not exist in library for i in range(0,self.division): x=epsLocal[i].x y=epsLocal[i].y z=epsLocal[i].z outFile.write('{} {} {} \n'.format(x,y,z)) outFile.close()
def _mesh_to_ray_intersection(ray, mesh, both_dirs=True, clean_up=True, above_only=True): """Calculate ray/mesh intersections. Args: ray (HVRay): ray object mesh (HFnMehs): mesh object both_dirs (bool): check intersections in both directions (ie. if this if false then intersections coming out of faces will not be flagged) clean_up (bool): remove duplicate points - these can occur if a ray intersects an the edge between two faces above_only (bool): remove points behind the ray's start point Returns: (HPoint list): list of points """ from maya_psyhive import open_maya as hom _ray_src = om.MFloatPoint(*ray.pnt.to_tuple()) _ray_dir = om.MFloatVector(*ray.vec.to_tuple()) _space = om.MSpace.kWorld _max_param = 999999 _result = mesh.allIntersections( _ray_src, _ray_dir, _space, _max_param, both_dirs, ) # Convert to HPoints _pts = [] for _item in _result[0]: _pt = hom.HPoint(_item) _pts.append(_pt) lprint('FOUND {:d} PTS'.format(len(_pts)), _pts, verbose=0) # Remove duplicate points if clean_up: _clean_pts = [] while _pts: _clean_pts.append(_pts.pop()) for _pt in copy.copy(_pts): for _clean_pt in _clean_pts: if not (_pt - _clean_pt).length(): _pts.remove(_pt) _pts = _clean_pts # Remove points behind the ray's start point if above_only: _above_pts = [] _plane = ray.to_plane() for _pt in _pts: _dist = _plane.distanceToPoint(hom.HVector(_pt), signed=True) if _dist > 0.0001: _above_pts.append(_pt) _pts = _above_pts return _pts
def sang(chue_tem_file, satsuan=1, yaek_poly=False, ao_bs=True, ao_kraduk=True, watsadu=1): t_roem = time.time() # 開始 print('モデルインポート開始') sakun = os.path.splitext(chue_tem_file)[1] # 拡張子 try: if (sakun == '.pmx'): pmx_model = mmdio.pmx.load(chue_tem_file) elif (sakun == '.pmd'): pmx_model = mmdio.pmd.load2pmx(chue_tem_file) elif (sakun == '.x'): pmx_model = mmdio.xxx.load2pmx(chue_tem_file) else: print('pmxとpmdとxファイルしか使用できません') raise except: print('モデルに何か問題があって、ファイルの読み込みは失敗です') raise chue_nod_model = romaji(pmx_model.name) # モデルの名前をロマジに変換してモデルのノードの名前にする if (not chue_nod_model or set(chue_nod_model) == {'_'}): chue_nod_model = os.path.basename(chue_tem_file).split('.')[1] lis_chue_nod_kho_nok = [] # 一番外のジョイントのノードの名前を収めるリスト chue_nod_skin = None chue_nod_bs = None # その名前のノードがすでに存在している場合'_'を追加する while (mc.objExists(chue_nod_model)): chue_nod_model += '_' print('ポリゴン作成') if (yaek_poly): # ポリゴンを分割する場合、今まだ何もしなくていい lis_chue_nod_poly_mat = [] else: # pmxモデルから頂点の位置とuv一つずつ入れていく lis_xyz = [] # 頂点の位置を収めるリスト lis_u = [] # 頂点のuvを収めるリスト lis_v = [] lis_norm = [] # 頂点の法線を収めるリスト for vtx in pmx_model.vertices: try: lis_xyz.append( om.MFloatPoint(vtx.co[0] * satsuan, vtx.co[1] * satsuan, -vtx.co[2] * satsuan)) except: # 大きすぎたりとエラーが出る場合もあるので、(0,0,0)にする lis_xyz.append(om.MFloatPoint(0, 0, 0)) lis_u.append(vtx.uv[0]) # 頂点のuvをリストに収める lis_v.append(1. - vtx.uv[1]) if (vtx.normal): # 頂点の法線のデータがあった場合 lis_norm.append( om.MFloatVector(vtx.normal[0], vtx.normal[1], -vtx.normal[2])) lis_index_chut = [] # この面に使う頂点を収めるリスト lis_n_chut_nai_na = [] # この面に使う頂点の数を収めるリスト lis_na_ni_chai_mai = [] # この面が使うかどうかという情報を収めるリスト for i_chut_nai_na in pmx_model.faces: i_chut_nai_na = list(dict.fromkeys(i_chut_nai_na)) # この面に使う頂点 n_chut_nai_na = len(i_chut_nai_na) # この面に使う頂点の数 if (n_chut_nai_na >= 3): # 重複しない頂点が3以上ある場合のみ、この面を使う lis_index_chut.extend(i_chut_nai_na) lis_n_chut_nai_na.append(n_chut_nai_na) lis_na_ni_chai_mai.append(True) # この面を使う else: lis_na_ni_chai_mai.append(False) # この面を使わない chue_nod_poly = sang_poly(chue_nod_model, lis_xyz, lis_index_chut, lis_n_chut_nai_na, lis_u, lis_v, lis_norm) if (not watsadu): # 材質を使わないと選択したら全部ただのlambertにする mc.select(chue_nod_poly) mc.hyperShade(assign='lambert1') set_index_tex = set([mat.texture for mat in pmx_model.materials]) lis_chue_nod_file = [] # テクスチャファイルの名前を収めるリスト # テクスチャを作成する for i, tex in enumerate(pmx_model.textures): path_tem_tex = tex.path chue_tex = os.path.basename(path_tem_tex) # テクスチャの名前 chue_tex = re.sub(r'\W', '_', chue_tex) chue_tex = romaji(chue_tex) # テクスチャの名前をロマジにする chue_nod_file = chue_tex + '_file_' + chue_nod_model # 使われているテクスチャだけshadingNodeのノードを作る if (i in set_index_tex): # 同じ名前が既存である場合、ノードの名前が自動的に変更される chue_nod_file = mc.shadingNode('file', asTexture=True, name=chue_nod_file) mc.setAttr(chue_nod_file + '.ftn', path_tem_tex, typ='string') # place2dのノードを作る chue_nod_placed2d = mc.shadingNode('place2dTexture', asUtility=True, name=chue_tex + '_placed2d_' + chue_nod_model) # place2dノードの値とファイルノードの値を接続する for cp in chueam_placed2d: mc.connectAttr('%s.%s' % (chue_nod_placed2d, cp[0]), '%s.%s' % (chue_nod_file, cp[1]), force=1) lis_chue_nod_file.append(chue_nod_file) # 材質を作成する nap_na_nai_mat = 0 # すでに材質を付けた面の数 for i_mat, mat in enumerate(pmx_model.materials): if (mat.vertex_count == 0): # 面一つもないならスキップ continue n_na_nai_mat = int(mat.vertex_count / 3) # この材質を付ける面の数 chue_mat = romaji(mat.name) chue_nod_mat = chue_mat + '_mat_' + chue_nod_model i_tex = mat.texture # この材質に付けるテクスチャの番号 dc = mat.diffuse[:3] # 拡散色 ambc = mat.ambient # 環境色 spec = mat.specular[:3] # 反射色 alpha = mat.diffuse[3] # 不透明度 opa = [alpha, alpha, alpha] trans = [1 - alpha, 1 - alpha, 1 - alpha] # 透明度 sf = mat.specular[3] # 反射強度 if (watsadu == 1): chue_nod_mat = mc.shadingNode('blinn', asShader=True, name=chue_nod_mat) mc.setAttr(chue_nod_mat + '.specularColor', *spec, typ='double3') mc.setAttr(chue_nod_mat + '.specularRollOff', min(0.75**(math.log(max(sf, 2**-10), 2) + 1), 1)) mc.setAttr(chue_nod_mat + '.eccentricity', sf * 0.01) elif (watsadu == 2): chue_nod_mat = mc.shadingNode('phong', asShader=1, n=chue_nod_mat) mc.setAttr(chue_nod_mat + '.specularColor', *spec, typ='double3') mc.setAttr(chue_nod_mat + '.cosinePower', max((10000. / max(sf, 15)**2 - 3.357) / 0.454, 2)) elif (watsadu == 3 or not watsadu): chue_nod_mat = mc.shadingNode('lambert', asShader=1, name=chue_nod_mat) if (watsadu in [1, 2, 3]): mc.setAttr(chue_nod_mat + '.color', *dc, typ='double3') mc.setAttr(chue_nod_mat + '.ambientColor', *ambc, typ='double3') mc.setAttr(chue_nod_mat + '.transparency', *trans, typ='double3') elif (watsadu == 4): # arnoldを使う場合 chue_nod_mat = mc.shadingNode('standardSurface', asShader=True, name=chue_nod_mat) mc.setAttr(chue_nod_mat + '.baseColor', *dc, typ='double3') mc.setAttr(chue_nod_mat + '.specularColor', *spec, typ='double3') mc.setAttr(chue_nod_mat + '.opacity', *opa, typ='double3') mc.setAttr(chue_nod_mat + '.specular', 0.75**(math.log(max(sf, 0.5), 2) + 1)) mc.setAttr(chue_nod_mat + '.specularRoughness', min(sf * 0.01, 1)) mc.setAttr(chue_nod_mat + '.base', 1) # 日本語の名前も一応収めておく mc.addAttr(chue_nod_mat, longName='namae', niceName='名前', dataType='string') mc.setAttr(chue_nod_mat + '.namae', mat.name, typ='string') if (i_tex >= 0): chue_nod_file = lis_chue_nod_file[i_tex] if (watsadu != 4): mc.connectAttr(chue_nod_file + '.outColor', chue_nod_mat + '.color') else: mc.connectAttr(chue_nod_file + '.outColor', chue_nod_mat + '.baseColor') tex = pmx_model.textures[i_tex] if (mc.getAttr(chue_nod_file + '.fileHasAlpha') and tex.path[-3:].lower() in ['png', 'tga', 'dds', 'bmp']): # テクスチャノードのアルファを材質ノードに接続する if (watsadu in [1, 2, 3]): mc.connectAttr(chue_nod_file + '.outTransparency', chue_nod_mat + '.transparency') elif (watsadu == 4): mc.connectAttr(chue_nod_file + '.outAlpha', chue_nod_mat + '.opacityR') mc.connectAttr(chue_nod_file + '.outAlpha', chue_nod_mat + '.opacityG') mc.connectAttr(chue_nod_file + '.outAlpha', chue_nod_mat + '.opacityB') chue_nod_sg = mc.sets(renderable=1, noSurfaceShader=1, empty=1, name=chue_nod_mat + 'SG') mc.connectAttr(chue_nod_mat + '.outColor', chue_nod_sg + '.surfaceShader', force=True) if (yaek_poly): lis_index_chut_mat = [] lis_n_chut_nai_na_nai_mat = [] dic_chut = {} k = 0 for i_chut_nai_na in pmx_model.faces[ nap_na_nai_mat:nap_na_nai_mat + n_na_nai_mat]: i_chut_nai_na = list(dict.fromkeys(i_chut_nai_na)) n_chut_nai_na = len(i_chut_nai_na) if (n_chut_nai_na >= 3): for j in range(n_chut_nai_na): if (i_chut_nai_na[j] not in dic_chut): dic_chut[i_chut_nai_na[j]] = k # 元の番号と新しい番号を繋ぐ辞書 k += 1 lis_index_chut_mat.append(dic_chut[i_chut_nai_na[j]]) lis_n_chut_nai_na_nai_mat.append(n_chut_nai_na) lis_xyz_mat = [] lis_u_mat = [] lis_v_mat = [] lis_norm_mat = [] for ic in dic_chut: k = dic_chut[ic] vtx = pmx_model.vertices[ic] try: lis_xyz_mat.append( om.MFloatPoint(vtx.co[0] * satsuan, vtx.co[1] * satsuan, -vtx.co[2] * satsuan)) except: lis_xyz_mat.append(om.MFloatPoint(0, 0, 0)) lis_u_mat.append(vtx.uv[0]) lis_v_mat.append(1. - vtx.uv[1]) lis_norm_mat.append( om.MFloatVector(vtx.normal[0], vtx.normal[1], -vtx.normal[2])) # この材質のポリゴンを作成する chue_nod_poly_mat = sang_poly(chue_nod_model + '_%d' % (i_mat + 1), lis_xyz_mat, lis_index_chut_mat, lis_n_chut_nai_na_nai_mat, lis_u_mat, lis_v_mat, lis_norm_mat) n_na_chai_mat = len(lis_n_chut_nai_na_nai_mat) # 実際に使う面の数 mc.sets(chue_nod_poly_mat + '.f[%s:%s]' % (0, n_na_chai_mat - 1), forceElement=chue_nod_sg) lis_chue_nod_poly_mat.append(chue_nod_poly_mat) else: nap_na_chai0 = sum(lis_na_ni_chai_mai[:nap_na_nai_mat]) nap_na_chai1 = sum(lis_na_ni_chai_mai[:nap_na_nai_mat + n_na_nai_mat]) # 指定の面に材質を貼る mc.sets(chue_nod_poly + '.f[%s:%s]' % (nap_na_chai0, nap_na_chai1 - 1), forceElement=chue_nod_sg) nap_na_nai_mat += n_na_nai_mat # 面の数を数え続ける if (yaek_poly): chue_nod_poly = mc.group(lis_chue_nod_poly_mat, name=chue_nod_model) if (ao_bs and not yaek_poly): print('ブレンドシェープ作成') # 各パネル(眉、目、口、他) lis_chue_nod_poly_bs = [[], [], [], []] # ブレンドシェープを作るためのポリゴンのノードのリストを収める lis_chue_bs_doem = [[], [], [], []] # 元の名前(日本の名前)を収めるリスト for i, mo in enumerate(pmx_model.morphs): # 頂点モーフをブレンドシェープに変換する。他のモーフは変換できないので無視する if (mo.type_index() == 1): # ブレンドシェープの名前はロマジに変換しなければならない chue_bs = romaji(mo.name) # ブレンドシェープを作るために、元のポリゴンをコピーする chue_nod_poly_bs = mc.duplicate(chue_nod_poly, name=chue_bs)[0] selelis = om.MSelectionList() selelis.add(chue_nod_poly_bs) dagpath = selelis.getDagPath(0) fn_mesh = om.MFnMesh(dagpath) arr_chut = fn_mesh.getPoints() # 頂点の位置が入っている配列 for off in mo.offsets: vi = off.index # 動く頂点の番号 d = off.offset # 元の位置から動く距離 p = arr_chut[vi] # 元の頂点のいち arr_chut[vi] = [ p[0] + d[0] * satsuan, p[1] + d[1] * satsuan, p[2] - d[2] * satsuan ] # 頂点が動いた後の位置を配列に入れる fn_mesh.setPoints(arr_chut) lis_chue_nod_poly_bs[mo.category - 1].append(chue_nod_poly_bs) lis_chue_bs_doem[mo.category - 1].append(mo.name) # 一つのリストにする。順番はパネルによる lis_chue_nod_poly_bs = list(itertools.chain(*lis_chue_nod_poly_bs)) mc.select(lis_chue_nod_poly_bs, chue_nod_poly) # ブレンドシェープのノードを作成する chue_nod_bs = mc.blendShape(name='bs_' + chue_nod_poly)[0] mc.delete(lis_chue_nod_poly_bs) # すでにブレンドシェープを作るために使ったポリゴンは用済みだから消す if (ao_kraduk and not yaek_poly): print('ジョイント作成') lis_chue_nod_kho = [] # ジョイントの名前を収めるリスト for b in pmx_model.bones: mc.select(deselect=1) chue_kho = romaji(b.name) loc = b.location # ジョイントの位置 # ジョイントの半径 if ('yubi' in chue_kho): # 指は小さめ r_kho = satsuan / 4 elif (chue_kho == 'sentaa'): # サンターは大きめ r_kho = satsuan else: # その他 r_kho = satsuan / 2 # ジョイントのノードを作成する chue_nod_kho = mc.joint(position=[ loc[0] * satsuan, loc[1] * satsuan, -loc[2] * satsuan ], radius=r_kho, name=chue_nod_poly + '_' + chue_kho) mc.addAttr(chue_nod_kho, longName='namae', niceName='名前', dataType='string') # 日本語の名前も一応ここに収めておく mc.setAttr(chue_nod_kho + '.namae', b.name, typ='string') if (b.isIK or not b.visible): # 表示しないジョイント mc.setAttr(chue_nod_kho + '.drawStyle', 2) else: mc.setAttr(chue_nod_kho + '.drawStyle', 0) # ローカル軸が指定されている場合 if (b.localCoordinate or b.axis): if (b.axis): # x軸だけが指定されている場合 kaen_x = b.axis kaen_z = cross([0.0, 1.0, 0.0], kaen_x) else: # x軸もz軸も指定されている場合 kaen_x = b.localCoordinate.x_axis kaen_z = b.localCoordinate.z_axis kaen_y = cross(kaen_z, kaen_x) # ジョイントの方向を表すオイラー角に変換するための行列 matrix_mun = om.MMatrix([ kaen_x[0], kaen_x[1], -kaen_x[2], 0., kaen_y[0], kaen_y[1], -kaen_y[2], 0., kaen_z[0], kaen_z[1], -kaen_z[2], 0., 0., 0., 0., 1. ]) mum_euler = om.MTransformationMatrix(matrix_mun).rotation() # できたオイラー角の単位がラジアンなので角度に変換する ox = math.degrees(mum_euler.x) oy = math.degrees(mum_euler.y) oz = math.degrees(mum_euler.z) mc.setAttr(chue_nod_kho + '.jointOrient', ox, oy, oz) # ジョイントの方向 lis_chue_nod_kho.append(chue_nod_kho) for i, b in enumerate(pmx_model.bones): chue_nod_kho = lis_chue_nod_kho[i] if (b.parent >= 0): # ジョイントを結び合う chue_nod_parent = lis_chue_nod_kho[b.parent] mc.connectJoint(chue_nod_kho, chue_nod_parent, parentMode=1) else: lis_chue_nod_kho_nok.append(chue_nod_kho) # 回転角の不具合がある場合の解決 if (round(mc.getAttr(chue_nod_kho + '.rx')) % 360 == 0): mc.setAttr(chue_nod_kho + '.rx', 0) if (round(mc.getAttr(chue_nod_kho + '.ry')) % 360 == 0): mc.setAttr(chue_nod_kho + '.ry', 0) if (round(mc.getAttr(chue_nod_kho + '.rz')) % 360 == 0): mc.setAttr(chue_nod_kho + '.rz', 0) if (round(mc.getAttr(chue_nod_kho + '.rx')) % 360 == 180 and round(mc.getAttr(chue_nod_kho + '.ry')) % 360 == 180 and round(mc.getAttr(chue_nod_kho + '.rz')) % 360 == 180): mc.setAttr(chue_nod_kho + '.r', 0, 0, 0) if (b.hasAdditionalRotate): # 回転付与のあるジョイントの場合 chue_nod_effect = lis_chue_nod_kho[ b.additionalTransform[0]] # 影響を与えるノード jo = mc.getAttr(chue_nod_effect + '.jointOrient')[0] # このジョイントの方向を取得 mc.setAttr(chue_nod_kho + '.jointOrient', *jo) # 同じジョイントの方向にする # 回転付与をエクスプレッションにする ef = b.additionalTransform[1] # 付与率 s = '%s.rotateX = %s.rotateX * %s;\n' % (chue_nod_kho, chue_nod_effect, ef) s += '%s.rotateY = %s.rotateY * %s;\n' % (chue_nod_kho, chue_nod_effect, ef) s += '%s.rotateZ = %s.rotateZ * %s;\n' % (chue_nod_kho, chue_nod_effect, ef) mc.expression(string=s, name='expression_%s_%s' % (chue_nod_kho, chue_nod_effect)) if (b.hasAdditionalLocation): # 移動付与をエクスプレッションにする chue_nod_effect = lis_chue_nod_kho[ b.additionalTransform[0]] # 影響を与えるノード ef = b.additionalTransform[1] # 付与率 s = '%s.translateX = %s.translateX * %s;\n' % ( chue_nod_kho, chue_nod_effect, ef) s += '%s.translateY = %s.translateY * %s;\n' % ( chue_nod_kho, chue_nod_effect, ef) s += '%s.translateZ = %s.translateZ * %s;\n' % ( chue_nod_kho, chue_nod_effect, ef) mc.expression(string=s, name='expression_%s_%s' % (chue_nod_kho, chue_nod_effect)) selelis = om.MSelectionList() selelis.add(chue_nod_poly) dagpath_mesh = selelis.getDagPath(0) chue_nod_skin = 'skin_' + chue_nod_poly chue_nod_skin = mc.skinCluster(lis_chue_nod_kho, chue_nod_poly, maximumInfluences=4, toSelectedBones=True, name=chue_nod_skin)[0] # スキンのノードを作成する selelis = om.MSelectionList() selelis.add(chue_nod_skin) obj_skin = selelis.getDependNode(0) fn_skin = oma.MFnSkinCluster(obj_skin) n_kho = len(pmx_model.bones) lis_namnak = [] # 重みの値を収めるリスト for vtx in pmx_model.vertices: namnak = [0.] * n_kho # この頂点に対する各ジョイントの影響の重み if (vtx.weight.type == mmdio.pmx.BoneWeight.BDEF1): # 2つだけのジョイントの影響を受ける場合 namnak[vtx.weight.bones[0]] = 1. elif (vtx.weight.type == mmdio.pmx.BoneWeight.BDEF2): # 2つのジョイントの影響を受ける場合 namnak[vtx.weight.bones[0]] += vtx.weight.weights[0] namnak[vtx.weight.bones[1]] += 1. - vtx.weight.weights[0] elif (vtx.weight.type == mmdio.pmx.BoneWeight.SDEF): # SDEFの場合もBDEF2と同様に2つのジョイント扱い namnak[vtx.weight.bones[0]] += vtx.weight.weights.weight namnak[vtx.weight.bones[1]] += 1. - vtx.weight.weights.weight elif (vtx.weight.type == mmdio.pmx.BoneWeight.BDEF4): # 4つのジョイントの影響を受ける場合 namnak[vtx.weight.bones[0]] += vtx.weight.weights[0] namnak[vtx.weight.bones[1]] += vtx.weight.weights[1] namnak[vtx.weight.bones[2]] += vtx.weight.weights[2] namnak[vtx.weight.bones[3]] += 1. - vtx.weight.weights[ 0] - vtx.weight.weights[1] - vtx.weight.weights[2] lis_namnak.extend(namnak) n_chut = len(pmx_model.vertices) # 頂点の数 arr_index_chut = om.MIntArray(range(n_chut)) # 頂点の番号の配列 arr_namnak = om.MDoubleArray(lis_namnak) # 重みの値の配列 arr_index_influ = om.MIntArray(range(n_kho)) # ジョイントの番号の配列 fn_compo = om.MFnSingleIndexedComponent() compo = fn_compo.create(om.MFn.kMeshVertComponent) fn_compo.addElements(arr_index_chut) # ポリゴンに対するそれぞれのジョウントの影響の重みの値を設置する fn_skin.setWeights(dagpath_mesh, compo, arr_index_influ, arr_namnak, 1) for chue_nod_kho in lis_chue_nod_kho: if (chue_nod_kho not in lis_chue_nod_kho_nok): mc.rename(chue_nod_kho, chue_nod_kho.replace(chue_nod_poly + '_', '')) # 日本語の名前も一応収めておく mc.addAttr(chue_nod_poly, longName='namae', niceName='名前', dataType='string') mc.setAttr(chue_nod_poly + '.namae', pmx_model.name, typ='string') mc.select(chue_nod_poly) if (ao_kraduk): mc.select(lis_chue_nod_kho_nok) try: mc.setAttr('hardwareRenderingGlobals.transparencyAlgorithm', 3) mc.setAttr('defaultArnoldRenderOptions.autotx', 0) mc.setAttr('defaultArnoldRenderOptions.use_existing_tiled_textures', 0) except: 0 print('モデルインポート完了。%.2f秒かかりました' % (time.time() - t_roem)) return chue_nod_poly, lis_chue_nod_kho_nok, chue_nod_skin, chue_nod_bs
def compute(self, pPlug, pDataBlock): ''' Node computation method. - pDataBlock contains the data on which we will base our computations. - pPlug is a connection point related to one of our node attributes (either an input or an output). ''' if (pPlug == depthShader.outColorAttribute): # Get the data handles corresponding to your attributes among the values in the data block. surfacePointDataHandle = pDataBlock.inputValue( depthShader.surfacePointAttribute) nearDistanceDataHandle = pDataBlock.inputValue( depthShader.nearDistanceAttribute) farDistanceDataHandle = pDataBlock.inputValue( depthShader.farDistanceAttribute) nearColorDataHandle = pDataBlock.inputValue( depthShader.nearColorAttribute) farColorDataHandle = pDataBlock.inputValue( depthShader.farColorAttribute) gammaDataHandle = pDataBlock.inputValue(depthShader.gammaAttribute) # Obtain the (x,y,z) location of the currently rendered point in camera coordinates. surfacePoint = surfacePointDataHandle.asFloatVector() # Since the camera is looking along its negative Z axis (the Y axis is # the up vector), we must take the absolute value of the Z coordinate # to obtain the point's depth. depth = abs(surfacePoint.z) # Get the actual near and far threshold values. nearValue = nearDistanceDataHandle.asFloat() farValue = farDistanceDataHandle.asFloat() # Find the proportion of depth between the near and far values. if ((farValue - nearValue) == 0): # Avoid a division by zero if the near and far values somehow have the same value. depthProportion = 0 else: depthProportion = (depth - nearValue) / (farValue - nearValue) # Clamp the depthProportion value in the interval [0.0, 1.0] depthProportion = max(0, min(depthProportion, 1.0)) # Modify the depth proportion using the gamma roll-off bias. gammaValue = gammaDataHandle.asFloat() depthProportion = math.pow(depthProportion, gammaValue) # Linearly interpolate the output color based on the depth proportion. outColor = OpenMaya.MFloatVector(0, 0, 0) nearColor = nearColorDataHandle.asFloatVector() farColor = farColorDataHandle.asFloatVector() outColor.x = nearColor.x + ( (farColor.x - nearColor.x) * depthProportion) outColor.y = nearColor.y + ( (farColor.y - nearColor.y) * depthProportion) outColor.z = nearColor.z + ( (farColor.z - nearColor.z) * depthProportion) # Write to the output data. outColorDataHandle = pDataBlock.outputValue( depthShader.outColorAttribute) outColorDataHandle.setMFloatVector(outColor) outColorDataHandle.setClean() else: return OpenMaya.kUnknownParameter
def compute(self, pq, dt): for boid in range(pq.nb_items): kr = 0.0 kf = 0.0 a_avoid = om.MFloatVector(0.0, 0.0, 0.0) a_velMat = om.MFloatVector(0.0, 0.0, 0.0) a_center = om.MFloatVector(0.0, 0.0, 0.0) _amax = self.amax # If the boid is the leader if boid == self.leadBoid_index: boid_dir = (self.leadBoid_goal - pq.pos[boid]).normal() pq.accel[boid] = boid_dir * self.amax continue for neighbor in range(pq.nb_items): if neighbor == boid: continue xa = pq.pos[boid] #type: om.MFloatVector xb = pq.pos[neighbor] #type: om.MFloatVector va = pq.vel[boid] #type: om.MFloatVector vb = pq.vel[neighbor] #type: om.MFloatVector # Influence Range r = (xa - xb).length() if r < self.range: kr = 1 elif r > self.range and r < self.range_ramp: kr = (self.range_ramp - r) / (self.range_ramp - self.range) elif r > self.range_ramp: kr = 0 # Influence FOV t = (xb - xa).normalize() * va.normal() if t > self.cosfovshell: kf = 1 elif t > self.cosfov and t < self.cosfovshell: kf = (self.cosfov - t) / (self.cosfov - self.cosfovshell) elif t < self.cosfov: kf = 0 # Avoidance a_avoid += (self.A * (xa - xb).normalize() * (1 / (xa - xb).length()) * kr * kf ) #type: om.MFloatVector # Velocity Matching a_velMat += (self.V * (vb - va) * kr * kf) # Centering a_center += (self.C * (xb - xa) * kr * kf) # Acceleration Prioritization a_len = a_avoid.length() if a_len > self.amax: a_avoid = _amax * a_avoid.normal() a_velMat = a_center = om.MFloatVector(0.0, 0.0, 0.0) else: _amax = _amax - a_len a_len = a_velMat.length() if a_len > _amax: a_velMat = _amax * a_velMat.normal() a_center = om.MFloatVector(0.0, 0.0, 0.0) else: _amax = _amax - a_len a_len = a_center.length() if a_len > _amax: a_center = _amax * a_center.normal() aTotal = a_avoid + a_velMat + a_center # If the boid is the lead boid pq.accel[boid] = aTotal
def curveEditPointsOnMesh(*args, **kwargs): '''{'path':'Dynamics/Particles/Crowd/curveEditPointsOnMesh( )', 'icon':':/curveCV.png', 'tip':'把曲线吸附到多边形上', 'usage':""" #选择曲线,再选择mesh;当closest=False,曲线按垂直方向投射到mesh上,为True,投射到最终的mesh的位置上 $fun( closest=False )""" } ''' if len(args) > 1: nurCurves = args[0] if type(nurCurves) == type(''): nurCurve = (nurCurves, ) mesh = args[1] else: sel = cmds.ls(sl=True) if len(sel) > 1: nurCurves, mesh = sel[:-1], sel[-1] else: print 'Select two objects or assign arguments to the function!' return False mesh = checkArg(mesh, nodeType='mesh') if not mesh: print 'Least object is not mesh' return False closest = kwargs.get('closest', False) for nurCurve in nurCurves: nurCurve = checkArg(nurCurve, nodeType='nurbsCurve') if not nurCurve: print '%s is not nurbsCurve object' % (nurCurve) continue curveNode = nameToNode(nurCurve, old=True) curFn = om.MFnNurbsCurve(curveNode) numEPs = curFn.numCVs() - curFn.degree() + 1 meshNode = nameToNode(mesh) meshFn = newom.MFnMesh(meshNode) #print closest for i in range(numEPs): ep = '%s.ep[%s]' % (nurCurve, i) pos = newom.MPoint(cmds.pointPosition(ep)) meshPoint = meshFn.closestIntersection(newom.MFloatPoint(pos), newom.MFloatVector(0, 1, 0), newom.MSpace.kWorld, 9999.0, True) if meshPoint[2] != -1: #print meshPoint dis = (meshPoint[0][0] - pos[0], meshPoint[0][1] - pos[1], meshPoint[0][2] - pos[2]) cmds.move(dis[0], dis[1], dis[2], ep, r=True) elif closest == True: closestPoint = meshFn.getClosestPoint(pos, newom.MSpace.kWorld) dis = (closestPoint[0][0] - pos[0], closestPoint[0][1] - pos[1], closestPoint[0][2] - pos[2]) cmds.move(dis[0], dis[1], dis[2], ep, r=True)
def setPointFromVolume(self, distance, surface=False, rand=False): """ mesh にポイントを散布し、そのポイントのポジション情報を取得 引数: distance(float) : ポイント間の距離。値が小さいほど密度が濃い surface(bool) : True の場合、メッシュの表面に散布 rand(float) : random に配置。数値がそのままランダム強度値となる """ # 境界ボックスの最小角と最大角に適用するオフセットを計算 self.halfVoxelDist = 0.5 * distance # バウンディングボックスの最小値を取得 self.minPoint = self.getBoundingBox().min self.minPoint.x += self.halfVoxelDist self.minPoint.y += self.halfVoxelDist self.minPoint.z += self.halfVoxelDist # バウンディングボックスの最大値を取得 self.maxPoint = self.getBoundingBox().max self.maxPoint.x += self.halfVoxelDist self.maxPoint.y += self.halfVoxelDist self.maxPoint.z += self.halfVoxelDist def floatIterator(start, stop, step): """ start ~ stop 範囲内の数値で step で指定した数分繰り返し、計算値を格納 例) バウンディングボックスの最小値(start) ~ 最大値(stop) の間で指定した数(step) の均等なポジション情報を取得。 """ r = start while r < stop: yield r r += step # 計算後のポジション情報を宣言 self.voxels = [] for xCoord in floatIterator(self.minPoint.x, self.maxPoint.x, distance): for yCoord in floatIterator(self.minPoint.y, self.maxPoint.y, distance): for zCoord in floatIterator(self.minPoint.z, self.maxPoint.z, distance): # 交差判定のパラメータ self.raySource = om.MFloatPoint(xCoord, yCoord, zCoord) self.maxParam = 9999.0 self.tolerance = 0.0001 randX = random.uniform(-1, 1) * rand randY = random.uniform(-1, 1) * rand randZ = random.uniform(-1, 1) * rand # 引数設定時の分岐 if surface == True: if rand != False: self.raySource += om.MFloatPoint( randX, randY, randZ) self.rayDirection = om.MFloatVector( randX, randY, randZ) elif rand == False: rand = 1 self.raySource += om.MFloatPoint( randX, randY, randZ) self.rayDirection = om.MFloatVector( randX, randY, randZ) elif surface == False: if rand != False: self.raySource += om.MFloatPoint( randX, randY, randZ) self.rayDirection = om.MFloatVector( randX, randY, randZ) elif rand == False: self.rayDirection = om.MFloatVector(0, 0, -1) # 交差判定 self.ret = self.meshFn.allIntersections( self.raySource, # raySource ---------- レイスタートポイント self.rayDirection, # rayDirection ------- レイの方向 om.MSpace. kWorld, # coordinate space --- ヒットポイントが指定されている座標空間 self.maxParam, # maxParam ----------- ヒットを考慮する最大半径 False, # testBothDirections - 負のrayDirectionのヒットも考慮する必要があるかどうか tolerance=self. tolerance, # tolerance ---------- 交差操作の数値許容差 ) # 引数設定時の戻り値の分岐 if surface == True: if (len(self.ret[0]) % 2 == 1): self.voxels.append( (self.ret[0][0][0], self.ret[0][0][1], self.ret[0][0][2])) elif len(self.ret[0]) % 2 == 0 and len( self.ret[0]) != 0: self.voxels.append( (self.ret[0][0][0], self.ret[0][0][1], self.ret[0][0][2])) elif surface == False: # 飛ばしたレイが1回のみ当たった場合はメッシュの中、それ以外はメッシュの外と判定 if (len(self.ret[0]) % 2 == 1): self.voxels.append(self.raySource) return self.voxels