[Python]uValue disconnect


#1

I’ve seen posts that are sort of like this, but not clear enough or I couldn’t find the python equivalent.

def moPathGen():
	
	# Query user field entries
	usrPrefix = mc.textFieldGrp(fieldLocPrfx,q=True,text=True)
	usrMainName = mc.textFieldGrp(fieldMainName,q=True,text=True)
	usrPoints = mc.textFieldGrp(fieldCvAmt,q=True,text=True)
	
	# for loop to create locator(s)
	for i in range(1,int(usrPoints)+1):
		
		# create locator(s)
		theLoc = mc.spaceLocator(n = '{}_{}{}_loc'.format(usrPrefix, usrMainName, i))
		
		# Add locator to list name, spcLoc[].  
		spcLoc.append(theLoc)		
		
		# attach locator(s) to moPath
		theMoPath = mc.pathAnimation(theLoc,usrSel)
		
		# Store connection
		con=mc.listConnections(theLoc,c=True,t="motionPath")
		
		# Delete the key set for uValue
		# mc.cutKey(theMoPath, attribute='uValue', option='keys')
		
		# disconnectAttr
		mc.disconnectAttr(theLoc.uValue)

That’s sort of my code, there’s a lot more involved, but basically I take the input from the user(not shown) and feed to power the rest of the code.
Where I’m having issues is the uValue. Originally, I could manually break connections, however, for coding, it’s not that simple.

So I decided to isolate the connections and place them inside of loc. Problem is, as the for loop continues to create new motionPaths(1),(2), etc, it no longer recognizes, among quite a few other issues. I also was cutting the keys(it’s commented out trying to find another way of breaking connection as this command causes other issues making uValues greater than 1), so I instead decided to find another means of breaking connections.

I’ve been working on this code for several months. So I’m burning out quickly. This was my first code, so I didn’t want to give up on it, but it’s quite stressful as I can’t concentrate on anything else until I figure this danged thing out.

I’ve seen mel solutions that I totally don’t understand as their approach is, “of course we know, blah, blah” We do know? Really?

Also, I needed to add, once I do break the connection(each time through the loop), I then need to attach it via a variable that is determined in a called function based on an equation. So I need to setAttr but how the heck do I “setAttr” to the uValue when I’ve tried finding that channel, node or whatever and it says it doesn’t exist. :(.

Any help would be great!


#2

So I decided to attach this to my code, just to see all the connections

[

con = mc.listConnections(theLoc)
		print con

I get this:

[u’addDoubleLinear1’, u’addDoubleLinear2’, u’addDoubleLinear3’, u’addDoubleLinear1’, u’addDoubleLinear2’, u’addDoubleLinear3’, u’motionPath1’]

So the only thing I recognize is the motionPath1.

There was another readout from it being setup differently

when I added the c=True to the list connections code, this is what I get.

[u’pre_obj1_loc.translateX’, u’addDoubleLinear1’, u’pre_obj1_loc.translateY’, u’addDoubleLinear2’, u’pre_obj1_loc.translateZ’, u’addDoubleLinear3’, u’pre_obj1_loc.transMinusRotatePivotX’, u’addDoubleLinear1’, u’pre_obj1_loc.transMinusRotatePivotY’, u’addDoubleLinear2’, u’pre_obj1_loc.transMinusRotatePivotZ’, u’addDoubleLinear3’, u’pre_obj1_loc.specifiedManipLocation’, u’motionPath1’]

To limit it further to just the motionPath related:

[u’pre_object1_loc.specifiedManipLocation’, u’motionPath1’]
(the rest are just for each of the motion paths based on user input, in this case 4)
[u’pre_object2_loc.specifiedManipLocation’, u’motionPath2’]
[u’pre_object3_loc.specifiedManipLocation’, u’motionPath3’]
[u’pre_object4_loc.specifiedManipLocation’, u’motionPath4’]


#3

It isn’t clear at all to me what you’re trying to do. I suggest you manually set up your motion path how you want it, and graph the motionPath node in the node editor to see how things are actually connected. For example, uValue is an attribute of the motionPath node, and gets its input from a node of type animCurvTL.


#4

Indeed, you described problems, but you did not point out what exactly goes wrong. If it does not work, do you get an error message?

If I understand your posting correctly, then you want to disconnect the uValue but it did not work. Is this correct? And if I’m not completely mistaken, this expression:

mc.disconnectAttr(theLoc.uValue)

will not work, it should be defined as:

mc.disconnectAttr(theLoc + ".uValue")

If you use pymel, it would work because you have real objects instead of strings only.

Oh, and one more thing. Even if you did not ask for any tips. You have a lot of comments, too much comments I think. The meaning of comments is to understand complex code sections. Something like this:

# disconnectAttr
mc.disconnectAttr(theLoc.uValue)

is redundant. Such comments blow up your code and makes it more difficult to read.


#5

Ok,

First, I did say this was my first code. Secondly, I guess I don’t know how else to ask for help.
I posted the code as I had written it. The comments, I put in there for me to keep track of what steps I am performing, I was even instructed to do that from various tutorials as instructors. I even read where they said just the opposite of what you said, comments are great for people to read code, I guess from your comments, I was instructed incorrectly.

I didn’t want to put the other code, as there is a whole process, as it’s not part of the issue. I wanted to explain the entire process thinking that would assist someone in understanding where I was going with it, instead of putting a vague one line of code and saying, “Help me, I don’t know what to do.” Can’t seem to win here.

So let me rephrase the best that I can, as you can see, I don’t understand many of the workings of Maya which can lead to a lack of better communications. I’ve been told this is how I will learn to troubleshoot, without a good solid foundation of coding. HA. I digress.

Here we go.

The intended result of this whole code is, to take curves on a facial mesh, and attach 2 forms of joints, offsets and controls. This is based on the Digital Tutors/Pluralsight course:
https://app.pluralsight.com/library/courses/joint-based-facial-rigging-maya-1133/table-of-contents

He manually goes through and:
[ol]
[li]creates the curve first.
[/li][li]creates a locator.
[/li][li]creates a motion path, attaching locator to the curve
[/li][li]manually breaks the connection on the locator’s input(in the channel box), u.Value that has a key set on it.
[/li][li]manually enters a value between 0 and 1, for each locator he creates, e.g. locators = 0, .33, .66, .99{actually 1]
[/li][li]then parents a joint to each locator, and then another parent under that joint.
[/li][/ol]
The rest isn’t necessary at this point, as I haven’t been able to break the uValue connection. Well, I actually did with:

# Delete the key set for uValue
		mc.cutKey(theMoPath, attribute='uValue', option='keys')

(indentation is because of where it sits in the code)
I’ll paste my entire code, at the bottom with create window, etc. Just so you can see it all, if that helps to make sense.
The problem with the cutKey method is, when it deletes the key set, it causes other issues with the uValue; it no longer goes from 0-1, but 0-whatever and it’s not the curve length. So to avoid causing other issues, I need to find another way of disconnecting the uValue from the locator, without deselecting the locator selected at that time.
I’ve done a

con=mc.listConnections(theLoc,c=True,t="motionPath")

But it returns only:
[u’pre_object1_loc.specifiedManipLocation’, u’motionPath1’]
[u’pre_object2_loc.specifiedManipLocation’, u’motionPath2’]
[u’pre_object3_loc.specifiedManipLocation’, u’motionPath3’]
[u’pre_object4_loc.specifiedManipLocation’, u’motionPath4’]

when I input 4 :).

Ok. I think that’s it.


import maya.cmds as mc
# Declare variables
mainName = None
jntName = None
cvWin = None
cvAmt = None
mySel = None
spcLoc = []


# Get curve selected
def makeSelection():
	
	mySel = mc.ls(selection=True)
	#return name of selected objects
	return mySel
	
usrSel = makeSelection()

# Create Window for UI(eventually a function)
if mc.window("cvWin", ex=True):
	mc.deleteUI("cvWin", window=True)
	
mc.window("cvWin",t="Facial Curve",w=100, s=False)
mc.columnLayout("c_layout", adj =True)
mc.separator()
mc.text("Define Main Name")
mc.separator()

fieldLocPrfx = mc.textFieldGrp(l="Name of prefix:")
fieldMainName = mc.textFieldGrp(l="Name of object:")
fieldCvAmt = mc.textFieldGrp(l="Number of points:")

mc.separator()
mc.text("Please select your curve.")
mc.separator()
mc.button("Create", bgc=[0,0,1], c="moPathGen()")
mc.separator()

mc.showWindow("cvWin")
usrSel = makeSelection()

# Define moPathGen
def moPathGen():
	
	# Query user field entries
	usrPrefix = mc.textFieldGrp(fieldLocPrfx,q=True,text=True)
	usrMainName = mc.textFieldGrp(fieldMainName,q=True,text=True)
	usrPoints = mc.textFieldGrp(fieldCvAmt,q=True,text=True)
	
	# for loop to create locator(s)
	for i in range(1,int(usrPoints)+1):
		
		# create locator(s)
		theLoc = mc.spaceLocator(n = '{}_{}{}_loc'.format(usrPrefix, usrMainName, i))
		
		# Add locator to list name, spcLoc[].  
		spcLoc.append(theLoc)		
		
		# attach locator(s) to moPath
		theMoPath = mc.pathAnimation(theLoc,usrSel)
		
		# Store connection
		con=mc.listConnections(theLoc,c=True,t="motionPath")
		#con = mc.listConnections(theLoc, c=True)
		print con
		
		# Delete the key set for uValue		
		# mc.cutKey(theMoPath, attribute='uValue', option='keys')
		
		# disconnectAttr
		# mc.disconnectAttr(theMoPath.uValue)
		
		# call function points_along_curve to generate from list 
		points_along_curve(number_of_points = int(usrPoints))
		
		# create the offset joints
		mc.joint(n = '{}_{}{}_offset_Jnt'.format(usrPrefix, usrMainName, i))
		
		# create the control joints
		mc.joint(n = '{}_{}{}_control_Jnt'.format(usrPrefix, usrMainName, i))



def points_along_curve(number_of_points = 0):
	##User input determines uValues along the curve
	if number_of_points == 0:
		return None
		
	uValues = [0.0]
	
	if number_of_points ==1:
		print "Please enter a value greater than 1."
		return uValues
		
	for pt in range(1,number_of_points):
		uValues.append(float(pt) * (1.0/(number_of_points-1)))
		
	return uValues
	
	


#6

Ok that makes more sense now that you described the big picture. So, just focusing on the uValue since that’s where you say you’re stuck.

Firstly, you have a syntax error as haggi pointed out. But a bigger problem is that you’re trying to access uValue on the locator, which is the wrong node. Like I said before, it’s an attribute of motionPath, it’s not connected to the locator at all.

What is connected is an animCurvTL. You can get its name like:

animCurvTL = mc.listConnections(theMoPath + '.uValue')[0]

Now to break the connection, you could use disconnectAttr:

mc.disconnectAttr(animCurvTL + '.output', theMoPath + '.uValue')

but, since you don’t need animCurvTL and would want to get rid of it anyway, you could just delete it in the first place:

mc.delete(animCurvTL)

With uValue disconnected, you can set it how you like:

foo = 0.33
mc.setAttr(theMoPath + '.uValue', foo)

#7

Sorry, it was not my intention to be rude, I only tried to give a hint how to improve your code. Comments are extremely useful if they help to understand the code in cases where it would a problem without additional information.


#8

No worries. I’ve been badgered so many times, I apologize for taking the written comment as a snark response. That’s one of many reasons I don’t enjoy posting on forums. It’s so frustrating to try and learn when there are hundreds of different ways to do things and to try and learn 1 way and really be so lost that it only adds to the frustration.

Thanks for your assistance :).


#9

I’ll see if I can make this work in my code

Hopefully, I can. I’ve been working on this for almost 4 months now.

Thanks again.


#10

The node editor can be a bit of a spaghetti mess sometimes, you might have to move nodes around to see things clearly. Here’s a screenshot where I’ve highlighted the connection:

The connection editor is another way to see how things are hooked up… Also, the attribute names are always the “real” ones if you have trouble converting the “nice names” used in the node editor:

And there’s always listConnections, which you figured out already. If you had run it on the motionPath node, a name like “motionPath1_uValue” in the return probably would have tipped you off what to investigate. If you keep programming for Maya, you’ll quickly get good at hunting these things down :slight_smile:

P.S. I believe straight out deleting animCurvTL should be okay, I had tested it and the uValue stayed normalized from 0-1 along the length of the curve.


#11

Thanks for that.
Wasn’t it stated:
For example, uValue is an attribute of the motionPath node, and gets its input from a node of type animCurvTL.

And to work with that part, the animCurvTL. I never saw that node anywhere.
I ran the listConnections on the motionPath and got those outputs:
[B]con=mc.listConnections(theLoc,c=True,t=“motionPath”)

But it returns only:
[u’pre_object1_loc.specifiedManipLocation’, u’motionPath1’]
[u’pre_object2_loc.specifiedManipLocation’, u’motionPath2’]
[u’pre_object3_loc.specifiedManipLocation’, u’motionPath3’]
[u’pre_object4_loc.specifiedManipLocation’, u’motionPath4’]
[/B]

I don’t see any mention of animCurvTL in the above, nor anywhere else. Still not sure where you are getting that info from other than experience :). I also didn’t see that in the node editor, what you have. How would I even get that node? I’ve not come across that at all anywhere in my google searches.

Yeah, if I continue programming. Not at this rate. I graduated with honors and class Salutatorian (hah. meaningless) 3 years ago from FS, and still am not job worthy in any skill. I’m persistent, but perhaps I shouldn’t be as I’m not getting anywhere :(.

I do appreciate your assistance.


#12

Sorry,

I had read further where you said the uValue is not connected to the locator at all? If that’s the case, how would I have not known this when clearly listed in the input of the locator is: motionPath: uValue. That was why I trying to locate it and then disconnect from the locator, my bad :(.

The help docs were anything but helpful :(.


#13

You ran it on the locator (theLoc). If you run it on theMoPath, you will get different results:

print(mc.listConnections(theMoPath))
print(mc.listConnections(theMoPath + '.uValue'))
print(mc.listConnections(theMoPath + '.uValue', p=True))

I never knew about animCurveTL either before I responded to your question :slight_smile: Here is how I found it:

  1. I already knew uValue was an attribute of the motion path because I have used it manually before. So I selected the motionPath node (went to the tab in the attribute editor and clicked the select button).
  2. Opened the node editor and graphed connections.
  3. Expanded the little stack icons on the nodes so the connections were all visible.

If you repeat those steps you should get something like my screenshot. I can see how you were confused by the channel box, I’m not sure what governs which attributes of the input/output nodes get displayed there. Basically it’s showing you the names of nodes which are connected in some way, but the listed attributes aren’t necessarily the ones which are connected. Like in this case, it’s actually rotation values that are hooked up.


#14

Thanks so much. I really, really, really appreciate it.

I’m still a bit confused though, because I still wasn’t able to find what you had in your node editor. I manually connected the locator to the curve with the motionPath tool. Then looked it up in the node editor, I then selected the motionPath in the channel box, which it showed, but the other motionPath thing you showed, how it was connected via the uValue, I didn’t get :(.

Also, I still never saw the animCurveTL or whatever it was. :(. I made sure the stacks in the node editor was 3(little lights).


#15

So I’m trying to add the code into there but it stops after generating the first locator, attaching it and then disconnecting…got that far! But then I get an error.

 
import maya.cmds as mc
# Declare variables
mainName = None
jntName = None
cvWin = None
cvAmt = None
mySel = None
spcLoc = []


# Get curve selected
def makeSelection():
	
	mySel = mc.ls(selection=True)
	#return name of selected objects
	return mySel
	
usrSel = makeSelection()

# Create Window for UI(eventually a function)
if mc.window("cvWin", ex=True):
	mc.deleteUI("cvWin", window=True)
	
mc.window("cvWin",t="Facial Curve",w=100, s=False)
mc.columnLayout("c_layout", adj =True)
mc.separator()
mc.text("Define Main Name")
mc.separator()

fieldLocPrfx = mc.textFieldGrp(l="Name of prefix:")
fieldMainName = mc.textFieldGrp(l="Name of object:")
fieldCvAmt = mc.textFieldGrp(l="Number of points:")

mc.separator()
mc.text("Please select your curve.")
mc.separator()
mc.button("Create", bgc=[0,0,1], c="moPathGen()")
mc.separator()

mc.showWindow("cvWin")
usrSel = makeSelection()

# Define moPathGen
def moPathGen():
	
	# Query user field entries
	usrPrefix = mc.textFieldGrp(fieldLocPrfx,q=True,text=True)
	usrMainName = mc.textFieldGrp(fieldMainName,q=True,text=True)
	usrPoints = mc.textFieldGrp(fieldCvAmt,q=True,text=True)
	
	# for loop to create locator(s)
	for i in range(1,int(usrPoints)+1):
		
		# create locator(s)
		theLoc = mc.spaceLocator(n = '{}_{}{}_loc'.format(usrPrefix, usrMainName, i))
		
		# Add locator to list name, spcLoc[].  
		spcLoc.append(theLoc)		
		
		# attach locator(s) to moPath
		theMoPath = mc.pathAnimation(theLoc,usrSel)
		
		# Store name of connection
		animCurv = mc.listConnections(theMoPath + ".uValue")[0]
		
		#Disconnect the uValue connection
		mc.disconnectAttr(animCurv + ".output", theMoPath + ".uValue")
		
		# set uValues based on usrPoints e.g. 3 points [0,.5,1],5 points [0,.25,.50,.75,1.0]
		# call function points_along_curve to generate from list 
		points_along_curve(number_of_points = int(usrPoints))
		
		#Connect uValue with uValues generated from Function
		uValue = []
		mc.setAttr(theMoPath + ".uValue", uValue[i])
		
		# create the offset joints
		mc.joint(n = '{}_{}{}_offset_Jnt'.format(usrPrefix, usrMainName, i))
		
		# create the control joints
		mc.joint(n = '{}_{}{}_control_Jnt'.format(usrPrefix, usrMainName, i))
	
	###to figure out the number of points along uValue for attachments

def points_along_curve(number_of_points = 0):
	##User input determines uValues along the curve
	if number_of_points == 0:
		return None
		
	uValues = [0.0]
	
	if number_of_points ==1:
		print "Please enter a value greater than 1."
		return uValues
		
	for pt in range(1,number_of_points):
		uValues.append(float(pt) * (1.0/(number_of_points-1)))
		
	return uValues
	
		
	# Group locators into one group
	# Select all locators
	#mc.select(mc.ls(spcLoc), replace=True)
	
	#for sel in spcLoc:
	#	mc.sel(mc.ls(sel))
	
	# Create empty group node and name with mainName as root
	#locGrp = mc.group(n='{}_{}{}_grp'.format(usrPrefix, usrMainName,em=True)
	
	# Select all locators and add to locGrp

	
	
		

Not sure, but I get an error:

IndexError: list index out of range //


#16

I think you are graphing the wrong node still maybe, otherwise I can’t explain why it’s not showing up for you. One thing that sticks out to me is you say you selected it in the channel box; what you want is to select it in the attribute editor:

And then in the node editor press this button:

In my original screenshot of the graphed nodes, the animCurveTL is the one named “motionPath1_uValue”

As far as your current error, it’s because of this:

uValue = []
mc.setAttr(theMoPath + ".uValue", uValue[i])

You assign an empty list to uValue, and then try to dereference an element from it. Also, up above this, you call your function that generates the uValues but never save the result. I’m guessing what you want to do is:

uValues = points_along_curve(number_of_points = int(usrPoints))

A couple other tips:

  1. You are calling points_along_curve inside the loop. It’s not really an error, but it’s wasteful because it’s just generating identical values every iteration. So probably you want to set that up before the loop instead.
  2. When you issue the command mc.setAttr(theMoPath + “.uValue”, uValues[i]), the first element of uValues will be skipped because you started your loop index from 1. If you’re skipping it on purpose then nevermind, but I’m pointing it out in case.

#17

I’m still not clear what to do, sorry.

I’m a mess, LOL.

Yeah, the idea is, the other function creates the new uValues based on how many points the user selects from the UI. I’ve been testing 4 all the time for no real reason, but that’s neither here nor there.

I still don’t get how to “call” the value> uValues that the function returns. It holds the list as far as I can figure out. Just when I think I understand, I get totally blown away.

I’m not sure how to call the proper list from the uValues that the definition creates.


#18

Oh yeah, that’s right, the (i) was for the looping and couldn’t be 0, but got it :). If I ever figure this “easy” part out, I’ll bet sure to dress that part :).


#19

I hacked your code to do what you want (as I understand it) as far as creating locators on the motion paths is concerned, so you can see how you could make it work. I changed some names and other things for my convenience.

import maya.cmds as mc

# Declare variables
mainName = None
jntName = None
cvWin = "cvWin"
cvAmt = None
mySel = None
spcLoc = []


if mc.window(cvWin, ex=True):
	mc.deleteUI(cvWin, window=True)
	
mc.window(cvWin,t="Facial Curve",w=100, s=False)
mc.columnLayout("c_layout", adj =True)
mc.separator()
mc.text("Define Main Name")
mc.separator()

fieldLocPrfx = mc.textFieldGrp(l="Name of prefix:")
fieldMainName = mc.textFieldGrp(l="Name of object:")
fieldCvAmt = mc.textFieldGrp(l="Number of points:")

mc.separator()
mc.text("Please select your curve.")
mc.separator()
mc.button("Create", bgc=[0,0,1], c="moPathGen()")
mc.separator()

mc.showWindow(cvWin)


def moPathGen():
	
	usrSel = mc.ls(selection=True)[0]
	
	# Query user field entries
	usrPrefix = mc.textFieldGrp(fieldLocPrfx,q=True,text=True)
	usrMainName = mc.textFieldGrp(fieldMainName,q=True,text=True)
	usrPointsTxt = mc.textFieldGrp(fieldCvAmt,q=True,text=True)
	
	usrPoints = int(usrPointsTxt)
	if usrPoints < 2:
	    print 'Defaulting to 2 curve points'
	    usrPoints = 2
	    
	uValues = pointsAlongCurve(usrPoints)
	
	for i in xrange(usrPoints):
		
		# create locator(s)
		theLoc = mc.spaceLocator(n = '{}_{}{}_loc'.format(usrPrefix, usrMainName, i+1))
		spcLoc.append(theLoc)		
		
		# attach locator(s) to moPath
		theMoPath = mc.pathAnimation(theLoc, usrSel, fm=True)
		
		# Store name of connection
		animCurv = mc.listConnections(theMoPath + ".uValue")[0]
		
		#Disconnect the uValue connection
		#mc.disconnectAttr(animCurv + ".output", theMoPath + ".uValue")
		mc.delete(animCurv)
		
		#Connect uValue with uValues generated from Function
		mc.setAttr(theMoPath + ".uValue", uValues[i])
		
		# create the offset joints
		mc.joint(n = '{}_{}{}_offset_Jnt'.format(usrPrefix, usrMainName, i+1))
		
		# create the control joints
		mc.joint(n = '{}_{}{}_control_Jnt'.format(usrPrefix, usrMainName, i+1))
	

# Precondition: numPts must be >= 2
def pointsAlongCurve(numPts):
	
	uValues = [0.0]
	
	for pt in xrange(1,numPts):
		uValues.append(float(pt) * (1.0/(numPts-1)))

	return uValues

If you need more assistance I suggest we switch to private messages, so we don’t keep bumping this thread ahead of other users’ questions.


#20

Thank you spire2 for investing so much time helping others. Taking screenshots, making annotations and testing code takes a lot of time. Great to have people like you here in the community.