How to retrieve the created vertices of cmds.polyExtrude on Maya - python

I'm writing a script to change the position of the vertices created by an extrude command given a specific vector. But I can't find a way to get the newly generated vertices/faces/edges.
I tried looking in cmds.getAttr('polyExtrudeFace1') or the query mode of cmds.polyExtrudeFacet, but I can't find the right attribute/flag to get what I need.

Im not sure if there is a nice way to get the new extruded component ids but you can easily find it if you have a tool to get the before state.
One other way would be to desactivate every construction nodes , enable the polyExtrudeFace one by one and fill up a dic and then re-enable everything.
Here is an example to select the latest vertices on an extruded object :
'''
This script only work on the last polyExtrudeFace and on vertex
'''
# get the object
sel = cmds.ls(sl=True, o=True)
# get the extrude nodes, useful to create a dic with all polyExtrudeFace new component ids
extrudenodes = [e for e in cmds.listHistory(sel) if cmds.nodeType(e) == 'polyExtrudeFace']
#current vtx count
current_vtx_nb = cmds.polyEvaluate(sel, v=1)
# disable a polyExtude
cmds.setAttr("{}.nodeState".format(extrudenodes[0]), 1)
# get the previous number
previous_vtx_nb = cmds.polyEvaluate(sel, v=1)
# re-enable it
cmds.setAttr("{}.nodeState".format(extrudenodes[0]), 0)
# get the range
nb = current_vtx_nb - previous_vtx_nb
mrang = [current_vtx_nb-nb,current_vtx_nb]
# recreate the vtx s3election
out = ['{}.vtx[{}]'.format(sel[0], i) for i in range(*mrang)]
# select the vertex
cmds.select(out)
EDIT :
here is an example of the building dictionnary loop :
import maya.cmds as cmds
'''
This script build the vertices data loop
'''
class Counter:
idCounter = 0
def __init__(self):
Counter.idCounter += 1
def loopIncSel():
'relaunch the command to loop throught all key of the dic'
if sorted(dataExtrude.keys()):
count = Counter().idCounter % len(dataExtrude.keys())
k = dataExtrude.keys()[count]
cmds.select(dataExtrude[k])
# get the object
sel = cmds.ls(sl=True, o=True)
# get the extrude nodes, useful to create a dic with all polyExtrudeFace new component ids
extrudenodes = [e for e in cmds.listHistory(sel) if cmds.nodeType(e) == 'polyExtrudeFace']
# dic data :
dataExtrude = {}
for n in extrudenodes:
cmds.setAttr("{}.nodeState".format(n), 1)
# reverse the processus to re-enable,
# note that if there is node in between creating vertices and faces, it won't work
for n in extrudenodes[::-1]:
# get the previous number
previous_vtx_nb = cmds.polyEvaluate(sel, v=1)
# re-enable it
cmds.setAttr("{}.nodeState".format(n), 0)
#current vtx count
current_vtx_nb = cmds.polyEvaluate(sel, v=1)
# get the range
nb = current_vtx_nb - previous_vtx_nb
mrang = [current_vtx_nb-nb,current_vtx_nb]
# recreate the vtx s3election
dataExtrude[n] = ['{}.vtx[{}]'.format(sel[0], i) for i in range(*mrang)]
# select the vertex
# cmds.select(dataExtrude['polyExtrudeFace3'])
loopIncSel()

When applying cmds.polyExtrudeFacet onto a mesh, Maya will automatically select the new faces. Knowing this, it's easy to convert the face components to the new vertexes:
cmds.polySphere(name="pSphere1") # Create a sphere to test with.
cmds.polyExtrudeFacet("pSphere1.f[10]") # Extrude a random face.
sel = cmds.polyListComponentConversion(cmds.ls("*.f[*]", sl=True), fromFace=True, toVertex=True) # Convert faces to verts. Filter `ls` to only get face selections.
cmds.select(sel) # Select the newly created vertexes.

Related

Assign new material slot and random colors to existing objects

I am trying since days to assign new materials and random colors to meshes that already exist in a Blender scene.
I need to do it in Python but I cannot find a solution.
I would like each mesh to have different materials and different colors.
I have found two scripts that are very useful but I don't manage to combine them together, can anyone help please?
Thank you in advance
Script 1) assign a new material to all the meshes in a scene (but color not assigned):
import bpy
bpy.ops.object.select_all(action='SELECT')
# I separated the creation of nodes to a function so it's easier
# to edit later if needed
def create_nodes(mat):
mat.use_nodes = True
nodes = mat.node_tree.nodes
for every_node in nodes: # this removes all existing nodes
nodes.remove(every_node)
# creating Principled node and moving it:
node = nodes.new('ShaderNodeBsdfPrincipled')
node.location = (-190,100)
# creating Output node and moving it:
output_node = nodes.new('ShaderNodeOutputMaterial')
output_node.location = (40,100)
# creating the link between the two nodes:
links = mat.node_tree.links
link = links.new(node.outputs[0], output_node.inputs[0])
# this saves the currently active object so it can be restored later
active = bpy.context.object
# let's loop through all selected objects
for every_object in bpy.context.selected_objects:
# I only want to work with objects capable of having a material
if every_object.type in {'MESH','CURVE', 'SURFACE','META', 'FONT'}:
if every_object.name not in bpy.data.materials:
# if there is no material named after the object yet let's make one
mat = bpy.data.materials.new(every_object.name)
# and let's create the nodes for it
create_nodes(mat)
else:
# if the material already exists let's just use it
mat = bpy.data.materials.get(every_object.name)
if len(every_object.material_slots) == 0: # if there are no material slots
every_object.data.materials.append(mat)
# The only thing left now is to assign the material to
# all material slots. We probably do not want to loose the info
# about how the object is divided into separate materials
for every_slot in every_object.material_slots:
every_slot.material = mat
Script 2) assign a new material and a random color to an existing object in the scene (but works only for 1 object):
import bpy, random
ob = bpy.data.objects.get("Cube")
if ob != None:
# Create materials.
mat_one = bpy.data.materials.get("mat_one")
if mat_one == None:
mat_one = bpy.data.materials.new("mat_one")
mat_one.diffuse_color = (random.random(),random.random(),random.random(),random.random())
# Add materials to slots.
if len(ob.material_slots) != 1:
ob.data.materials.append(mat_one)

How to build gremlin query to add and drop vertex as part one transaction

I want to build a gremlin_python query dynamically that adds vertices and deletes vertices in single transaction.
For Ex: Lets say my graph has a vertex with property desc ='toBeDeleted'. I want to build a query to add vertices with desc = desc_1, desc_2, desc_3 and delete vertex with desc = toBeDeleted can I do something like this?
g = Graph().traversal().withRemote(DriverRemoteConnection('neptune_end_point', 'g'))
temp = g
i = 1
while i < 4:
temp = temp.addV('vertex_label').property('desc', 'desc_{}'.format(i))
i = i+1
temp = temp.V().has('vertex_label', 'desc', 'toBeDeleted').drop()
temp.toList()
note: I have tried this but it creates desc_1, desc_2, desc_3 twice.
I am also looking a way to delete edges as well as part of one transaction

I get the following error "NameError: name 'ref_atoms' is not defined" on my python code

I was wondering why i'm getting this error for the following code, as I have defined ref_atoms as ['CA']. The error occurs in line 121 where the superimposer is initiated for following line of code super_imposer.set_atoms(ref_atoms, sample_atoms)
def alignPDB(potentialTag,tagProtein):
# Select what residues numbers you wish to align
# and put them in a list
start_id = 1
end_id = 10
atoms_to_be_aligned = range(start_id, end_id + 1)
# Start the parser
pdb_parser = Bio.PDB.PDBParser(QUIET = True)
# Get the structures
ref_structure = pdb_parser.get_structure("tagProtein", "4ABN.pdb")
sample_structure = pdb_parser.get_structure("potentialTag", "2LYZ.pdb")
# Use the first model in the pdb-files for alignment
# Change the number 0 if you want to align to another structure
ref_model = ref_structure[0]
sample_model = sample_structure[0]
# Make a list of the atoms (in the structures) you wish to align.
# In this case we use CA atoms whose index is in the specified range
ref_atoms = ['CA']
sample_atoms = ['CA']
# Iterate of all chains in the model in order to find all residues
for ref_chain in ref_model:
# Iterate of all residues in each model in order to find proper atoms
for ref_res in ref_chain:
# Check if residue number ( .get_id() ) is in the list
if ref_res.get_id()[1] in atoms_to_be_aligned:
# Append CA atom to list
ref_atoms.append(ref_res['CA'])
# Do the same for the sample structure
for sample_chain in sample_model:
for sample_res in sample_chain:
if sample_res.get_id()[1] in atoms_to_be_aligned:
sample_atoms.append(sample_res['CA'])
# Now we initiate the superimposer:
super_imposer = Bio.PDB.Superimposer()
super_imposer.set_atoms(ref_atoms, sample_atoms)
super_imposer.apply(sample_model.get_atoms())
# Print RMSD:
print super_imposer.rms
# Save the aligned version of 1UBQ.pdb
io = Bio.PDB.PDBIO()
io.set_structure(sample_structure)
io.save("2LYZ_aligned.pdb")

How can I get a sorted array of selected verts in blender python

I have a loop of vertices selected in blender and I want to move each vertex to the position of its neighbour anti-clockwise.
def marchVerticesACW():
ob = bpy.context.scene.objects.active
mesh = ob.data
verts = [i.index for i in bpy.context.active_object.data.vertices if i.select]
covar=mesh.vertices[verts[0]].co
cx=covar.x
cy=covar.y
cz=covar.z
for x in range(len(verts)-1):
mesh.vertices[verts[x]].co=mesh.vertices[verts[x+1]].co
mesh.vertices[verts[len(verts)-1]].co.x=cx
mesh.vertices[verts[len(verts)-1]].co.y=cy
mesh.vertices[verts[len(verts)-1]].co.z=cz
works if the vertices happen to appear in the list in the right order but they don't always. is there a way to sort the list if it happens to be out of sequence?
I worked it out, based on the fact that each vert in the loop is joined to the next by an edge, so starting from any vert I just search the selected edges for the first that has that vertex at one end, make a note of the next vert on that edge, remove the edge from the collection then look for the edge that has the new vert at one end. It only works for closed loops and I haven't put in any error handling / checking but thought the basic idea might help someone else
import bpy
import bmesh
def OrderSelectedVerts(_bm):
edge=_edges[0]
startvert=edge.verts[0]
_edges.remove(edge)
_orderedVerts=[]
_orderedVerts.append(startvert)
while len(_edges)>0:
startvert=GetNextVert(startvert)
if startvert is not None:
_orderedVerts.append(startvert)
return _orderedVerts
def GetNextVert(sv):
for e in _edges:
if e.verts[0]==sv or e.verts[1]==sv:
if e.verts[0]==sv:
d=e.verts[1]
else:
d=e.verts[0]
_edges.remove(e)
return d
# Get the active mesh
obj = bpy.context.edit_object
me = obj.data
# Get a BMesh representation
bm = bmesh.from_edit_mesh(me)
_edges=[i for i in bm.edges if i.select]
#Get the selected verts in order
orderedVerts=OrderSelectedVerts(bm)
#Use the ordered verts
#Update the bmesh
bmesh.update_edit_mesh(me, True)

python maya: affect groups of nodes

I'm not quite sure where the problem is in this script. What I've done is this....
I have a scene with 2 curves. Each curve has three spheres linked to it.
I select the curves and run the script. It craps out and says I've got objects with matching names?
import maya.cmds as cmds
selection = cmds.ls(selection=True, type='dagNode')
# groups of ![enter image description here][1]nodes to be exported out
nodeBundles = []
for n in selection:
# list the children nodes
children = cmds.listRelatives(n, allDescendents=True, noIntermediate=True, fullPath=True, type="dagNode", path=True)
# list the transform nodes to each child node
childrenTransforms = maya.cmds.listRelatives(children, type='transform', parent=True)
# append each set of children to a unique array and then append to main array
nodeBundles.append(childrenTransforms)
# select the transform nodes
# cmds.select(childrenTransforms)
# MXS cache out each bundle of nodes
for n in nodeBundles:
cmds.select(clear=True)
cmds.xform(n, absolute=True, t=[0,0,10])
print n
FIXED CODE:
import maya.cmds as cmds
selection = cmds.ls(selection=True, type='dagNode')
# groups of ![enter image description here][1]nodes to be exported out
nodeBundles = []
for n in selection:
# list the children nodes
children = cmds.listRelatives(n, allDescendents=True, noIntermediate=True, fullPath=True, type="dagNode", path=True)
# list the transform nodes to each child node
# childrenTransforms = maya.cmds.listRelatives(children, type='transform', parent=True)
childrenTransforms = maya.cmds.listRelatives(children, type='transform', parent=True, fullPath=True)
# append each set of children to a unique array and then append to main array
nodeBundles.append(childrenTransforms)
# select the transform nodes
# cmds.select(childrenTransforms)
# MXS cache out each bundle of nodes
for n in nodeBundles:
cmds.select(clear=True)
cmds.xform(n, r=True, t=[0,0,10])
print n
By adding a list inside of a list I can then iterated based on groups of children. is this the correct method of doing so then?
nodes = []
for item in cmds.ls(sl=True, type = 'transform'):
descendants = cmds.listRelatives(ad=True, ni=True, f=True) or []
# nodes += descendants # append the list, not insert it
nodes.append(descendants)
val = 1
for grp in nodes:
for n in grp:
cmds.select(clear=True)
offset = val * 10
print offset
cmds.xform(n, r=True, t=[0,0,offset])
val += 1
Without seeing your scene or error message, my assumption is you have multiple nodes of the same name. Because Maya uses strings, it can't tell the difference between pSphere1 and... pSphere1
From the documentation on listRelatives, use the argument fullPath:
Return full pathnames instead of object names.
Like this:
childrenTransforms = maya.cmds.listRelatives(children, type='transform', parent=True, fullPath=True)
Assuming the error was in the last cmds.xform, this should make those transforms unambiguous (i.e. |group1|pSphere1)
listRelatives will work on selected objects if nothing is specified, so you can get the subnodes (with full paths) like this:
descendants = cmds.listRelatives(ad=True, ni=True, f=True) # f=True = long paths
If you were trying to use 'dagNode' to filter between shapes and geometry, it wont' work: dagNode will return both transforms and shapes. You can use 'geometryShape' to get only shapes:
descendant_shapes = cmds.listRelatives(ad=True, ni = True, f=True)
but in your case that would return the curveShape as well. You could filter out the curve with:
descendants = cmds.ls(descendants, type= surfaceShape, l=True) # l=True keeps long paths
Also: in you code you are passing lists-of-lists into nodeBundles, which Maya won't like. You should flatten the list by adding items one at a time:
nodes = []
for item in cmds.ls(sl=True, type = 'transform'):
descendants = cmds.listRelatives(ad=True, ni=True, f=True) or []
nodes += descendants # append the list, not insert it
for n in nodes:
cmds.select(clear=True)
cmds.xform(n, r=True, t=[0,0,10])

Categories

Resources