I'm quite a noob in Python.
I can write a simple script to assign a cluster to vertexes of the selected objects.
Like this:
import maya.cmds as cmds
activeSelection = cmds.ls(selection=True)
for i in activeSelection:
cmds.polyListComponentConversion( i, ff=True, tv=True, internal=True )
cmds.cluster( i, rel=True )
But it turned out I need to assign a cluster to vertexes of each individual polygon shell of the object. I've spent few hours searching and trying different scripts and trying to modify them but nothing seems to really work.
Would you guys be so kind to give a hint?
Thank you,
Anton
If you don't want to separate and then re-combine your mesh (to keep clean history, or you're restricted from modifying the geo in any way except deformers for some reason...), you could use this to "separate" your shells out non-destructively
import maya.cmds as mc
shells = []
face_count = mc.polyEvaluate(geom, f=True)
faces = set(range(face_count))
for face in xrange(face_count):
if face in faces:
shell_indices = mc.polySelect(geom, q=True, extendToShell=face)
shell_faces = ['%s.f[%d]' %(geom, i) for i in shell_indices]
shells.append(mc.polyListComponentConversion(shell_faces, toVertex=True))
faces -= set(shell_indices)
elif not faces:
break
this will give you a list where each item is a list of cps for a shell. All that's left to do is to cluster each item of the shells list
I'd try using cmds.polySeparate() to split the mesh into shells, then cluster the pieces and re-assemble them into a combo mesh. Something like this:
sel = cmds.ls(sl=True)
pieces = cmds.listRelatives(cmds.polySeparate(sel), c=True)
clusters = [cmds.cluster(p, rel=True) for p in pieces]
cmds.polyUnite(pieces)
Depending on the application you might not really need the clusters, since the polySeparate will give you one transform per shell and you'll be able to animated the original shell transforms directly while keeping the combined mesh
Related
[I have been trying many solutions posted here and there, yet I cannot make this work]
I have a python script on blender side exporting object rotations like this
m = obj.matrix_world.to_euler('XYZ')
rot = mathutils.Vector((math.degrees(m.x),math.degrees(m.y),math.degrees(m.z)))
on unreal side, still in python, setting up rotators for imported objects :
def createRotator(actor_rotation):
rotatorX = unreal.MathLibrary.rotator_from_axis_and_angle(unreal.Vector(0.1,0.0,0.0),actor_rotation.x)
rotatorY = unreal.MathLibrary.rotator_from_axis_and_angle(unreal.Vector(0.0,0.1,0.0),actor_rotation.y)
rotatorZ = unreal.MathLibrary.rotator_from_axis_and_angle(unreal.Vector(0.0,0.0,0.1),actor_rotation.z)
temp = unreal.MathLibrary.compose_rotators(rotatorX,rotatorY)
rotator = unreal.MathLibrary.compose_rotators(temp,rotatorZ)
return rotator
yet the objects are not placed correctly (in term of rotation) in unreal
I tried:
adding - in front of different rotation members in blender
flipping the order of the unreal rotators are combined in unreal
tried y=z and z=-y
tried z = -z or y=-y
(I could go on since I been busting my head on this for a whole week)
I been through so many posts, every answer is different, and none of them is working
can someone more clever than I am end my misery and tell me how to solve this ?
thanks
[edit:]
I spawn the actor like this
pos = unreal.Vector(float(row["posx"]),float(row["posy"]),float(row["posz"]))
rot = unreal.Vector(float(row["rotx"]),float(row["roty"]),float(row["rotz"]))
rotator = createRotator(rot)
staticMeshActor = unreal.EditorLevelLibrary.spawn_actor_from_object(staticMesh, pos, rotator)
I'm quite a newbie with networkx and it seems that i'm having RAM issues when running a function that merges two different graphs. This function adds up the weight of edges that are common to both graphs.
I have a list of 8~9 graphs each containing about 1000-2000 nodes which I merge in this loop:
FinalGraph = nx.Graph()
while len(graphs_list)!=0:
FinalGraph = merge_graphs(FinalGraph,graphs_list.pop())
using this function
def merge_graphs(graph1, graph2):
edges1 = graph1.edges
edges2 = graph2.edges
diff1 = edges1 - edges2
if diff1==edges1:
return nx.compose(graph1,graph2)
else:
common_edges = list(edges1 - diff1)
for edges in common_edges:
graph1[edges[0]][edges[1]]['weight'] += graph2[edges[0]][edges[1]]['weight']
return nx.compose(graph2, graph1)
When running my script, my computer will always freeze when reaching this loop. Am i doing some kind of bad reference cycle or something ? Am i missing something in the networkx doc more effective that could help me not use this function for my purpose ?
Thanks for reading me, I hope i'm making sense
There seems to be a lot of extra work going on here caused by you trying to check if the conditions allow you to use compose. This may be contributing to the trouble. I think it might work better to just iterate through the edges and nodes of the graph. The following looks like a more direct way to do it (and doesn't require creating as many variables, which might be contributing to the memory issues)
final_graph = nx.Graph()
for graph in graphs_list:
final_graph.add_nodes_from(graph.nodes())
for u, v, w in graph.edges(data=True):
if final_graph.has_edge(u,v):
final_graph[u][v]['weight'] += w
else:
final_graph.add_edge(u,v,weight = w)
I am trying to create a script that would help me automate the creation of a spine rig, but I am running into a problem. I am following the tutorial provided here and I am working on the step where you skin the curve to the IK joints.
However, when I try to use mc.bindSkin(), I keep getting an error:
Error: RuntimeError: file[directory]/maya/2016.5/scripts\createRigSpine.py line 200: Maya command error)
It's too late right now to for me to do much experimenting, but I was hoping someone could help me, or tell me if I'm using the wrong commands.
mc.select(crvSpine, jntIkMidSpine, jntIkChest)
mc.bindSkin(crvSpine, jntIkMidSpine, jntIkChest, tsb=True)
(have also tried mc.bindSkin() and mc.bindSkin(tsb=True))
Ideally, I want the settings to be:
Bind To: Selected Joints
Bind Method: Closest Distance
Skinning Method: Classic Linear
Normalize Weights: Interactive
Edit: I wanted to use skinCluster, not bindSkin.
you should use the skinCluster command to bind your curve to the joints - and you can actually do it without selecting anything!
Try this:
import maya.cmds as mc
influences = [jntIkMidSpine, jntIkChest]
scls = mc.skinCluster(influences, crvSpine, name='spine_skinCluster', toSelectedBones=True, bindMethod=0, skinMethod=0, normalizeWeights=1)[0]
# alternatively, if you don't want such a long line of code:
#
influences = [jntIkMidSpine, jntIkChest]
kwargs = {
'name': 'spine_skinCluster', # or whatever you want to call it...
'toSelectedBones': True,
'bindMethod': 0,
'skinMethod': 0,
'normalizeWeights': 1
}
scls = mc.skinCluster(influences, crvSpine, **kwargs)[0]
# OR just use the short names for the kwargs...
#
influences = [jntIkMidSpine, jntIkChest]
scls = mc.skinCluster(influences, crvSpine, n='spine_skinCluster', tsb=True, bm=0, sm=0, nw=1)[0]
If you wanted to, you could also explicitly set the weights you want for each cv of the curve. You could use the skinPercent command, or even just use setAttr for the various weight attrs in the skinCluster (that's a little more difficult, but not much)
cmds.bindSkin() command made for binding bones to geometry. It's not suitable for binding to IK's only. So you need to assign what joint you need to bind to.
For example:
import maya.cmds as mc
mc.select('ikHandle1','nurbsCircle1','joint5')
mc.bindSkin('ikHandle1','nurbsCircle1','joint5')
# the order of selection is vital
For constraining selected objects use the commands like this:
mc.pointConstraint('ikHandle1','nurbsCircle1', weight=5.0)
To find out what constraints are available to you, use Rigging module – Constrain menu – Parent, Point, Orient, Scale, Aim, Pole Vector.
I was using the wrong command. mc.skinCluster is what I wanted to use, not mc.bindSkin.
The Maya python code below gives a nurbs boolean surface by first taking the difference of two nurbs spheres, nurbsSphere1 and nurbsSphere2, to give the nurbs surface nurbsBooleanSurface1. It then takes the difference of this surface and a third sphere, nurbsSphere3. The result, as seen in the outliner, is the three nurbs spheres plus a surfaceVarGroup, nurbsBooleanSurface1, which 'parents' three transform nodes nurbsBooleanSurface1_1, nurbsBooleanSurface1_2 and nurbsBooleanSurface1_3.
import maya.cmds as cmds
cmds.sphere(nsp=10, r=50)
cmds.sphere(nsp=4, r=5)
cmds.setAttr("nurbsSphere2.translateX",-12.583733)
cmds.setAttr("nurbsSphere2.translateY",-2.2691557)
cmds.setAttr("nurbsSphere2.translateZ",48.33736)
cmds.nurbsBoolean("nurbsSphere1", "nurbsSphere2", nsf=1, op=1)
cmds.sphere(nsp=4, r=5)
cmds.setAttr("nurbsSphere3.translateX",-6.7379503)
cmds.setAttr("nurbsSphere3.translateY",3.6949043)
cmds.setAttr("nurbsSphere3.translateZ",49.40595)
cmds.nurbsBoolean("nurbsBooleanSurface1", "nurbsSphere3", nsf=1, op=1)
print(cmds.ls("nurbsBooleanSurface1_*", type="transform"))
Strangley (to me), the list command, cmds.ls("nurbsBooleanSurface1_*", type="transform") only yields [u'nurbsBooleanSurface1_1', u'nurbsBooleanSurface1_2']; nurbsBooleanSurface1_3 is missing.
But when, after having executed the above code, the print command
print(cmds.ls("nurbsBooleanSurface1_*", type="transform"))
is re-executed, the result is [u'nurbsBooleanSurface1_1', u'nurbsBooleanSurface1_2', u'nurbsBooleanSurface1_3'].
I've tried delaying the execution of the final print command using time.sleep(n) to no avail. I've played with the idea that the missing node might have spun off into another namespace and then re-appeared at the completion of the execution block (desperate, I know!). I've experimented with renaming the spheres and surfaces, using functions and threads (the latter only superficially). The cause of the unlisted nurbsBooleanSurface1_3 on the first execution of
print(cmds.ls("nurbsBooleanSurface1_*", type="transform"))
remains a mystery. Any help would be much appreciated.
A dirty way (but only way I could find) is to call cmds.refresh() during the script.
I have rewritten your script here. Notice that I store each sphere in a variable, this is good practice to make sure it'll work, even if an existing object is already called nurbsSphere3 for example.
import maya.cmds as cmds
sphere1 = cmds.sphere(nsp=10, r=50)
sphere2 = cmds.sphere(nsp=4, r=5)
cmds.setAttr(sphere2[0] + ".translateX",-12.583733)
cmds.setAttr(sphere2[0] + ".translateY",-2.2691557)
cmds.setAttr(sphere2[0] + ".translateZ",48.33736)
nurbsBool1 = cmds.nurbsBoolean("nurbsSphere1", "nurbsSphere2", nsf=1, op=1)
sphere3 = cmds.sphere(nsp=4, r=5)
cmds.setAttr(sphere3[0] + ".translateX",-6.7379503)
cmds.setAttr(sphere3[0] + ".translateY",3.6949043)
cmds.setAttr(sphere3[0] + ".translateZ",49.40595)
nurbsBool2 = cmds.nurbsBoolean(nurbsBool1[0], sphere3[0], nsf=1, op=1)
cmds.refresh(currentView=True) # Force evaluation, of current view only
print(cmds.listRelatives(nurbsBool2[0], children=True, type="transform"))
When you create an object using cmds.sphere() it returns a list of the object name and more. To access this, you can use
mySphere = cmds.sphere()
print(mySphere)
# Result: [u'nurbsSphere1', u'makeNurbSphere1']
print(mySphere[0]) # the first element in the list is the object name
# Result: nurbsSphere1
The same is true for the boolean operation. Look in the documentation for the command under Return value http://help.autodesk.com/cloudhelp/2016/ENU/Maya-Tech-Docs/CommandsPython/index.html
I am basically building a 3D scatter plot using primitive UV spheres and am running into memory issues when attempting to create more than a couple hundred points at one time. I am limited on my laptop with a 2.1Ghz processor but wanted to know if there is a better way to write this:
import bpy
import random
while count < 5:
bpy.ops.mesh.primitive_uv_sphere_add(size=.3,\
location=(random.randint(-9,9), random.randint(-9,9),\
random.randint(-9,9)), rotation=(0,0,0))
count += 1
I realize that with such a simple script any performance increase is likely negligible but wanted to give it a shot anyway.
Some possible suggestions
I would pre-calculate the x,y,z values, store them in a mathutil vector and add it to a dict to be iterated over.
Duplication should provide a smaller memory footprint than
instantiating new objects. bpy.ops.object.duplicate_move(OBJECT_OT_duplicate=(linked:false, TRANSFORM_OT_translate=(transform)
Edit:
Doing further research it appears each time a bpy.ops.* is called the redraw function . One user documentented exponential increase in time taken to genenerate UV sphere.
CoDEmanX provided the following code snippet to another user.
import bpy
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.mesh.primitive_uv_sphere_add()
sphere = bpy.context.object
for i in range(-1000, 1000, 2):
ob = sphere.copy()
ob.location.y = i
#ob.data = sphere.data.copy() # uncomment this, if you want full copies and no linked duplicates
bpy.context.scene.objects.link(ob)
bpy.context.scene.update()
Then it is just a case of adapting the code to set the object locations
obj.location = location_dict[i]