Using a variable name as parameter that accepts only floats


#1

Hi everybody,

I am new to python and scripting in general, and trying hard to make sense of it. A little background about this particular issue I am having :

I am rigging a bird, and for the feathers my approach is to point constrain them to the arm joints then orient constrain them to three controllers, one at the shoulder, the second one at the elbow and the last one at the wrist.
I would like the feathers in between two of these controllers to be affected by both, proportionally to the distance from them - the math poses no problem. The problem arises when I try to enter a variable name (which is the normalized distance value for this particular feather) into the weight parameter of the orientConstraint command - Maya says it wants only floats. Is there a way I can do this ?

Same issue for the actual names of the objects I want to constrain/be constrained : only strings are accepted and I would like to insert a variable in there (obj1, obj2…).

For reference, this is the current state of my code. It is most likely very ugly, please bear with me.


import maya.cmds as cmds

pos0 = [0, 0, 0];
pos1 = [0, 0, 0];
pos2 = [0, 0, 0];

dist1 = 0;
dist2 = 0;

# finding world space position of objects
pos0[0, 1, 2] = cmds.xform('obj0',q=1,ws=1,rp=1);
pos1[0, 1, 2] = cmds.xform('obj1',q=1,ws=1,rp=1);
pos2[0, 1, 2] = cmds.xform('obj2',q=1,ws=1,rp=1);

def get_dist(base, tip):
	# vector substract hack I found on stackexchange
	[m - n for m, n in zip(pos2, pos1)]

def get_normalized_dist(dist1, dist2):
	1/(dist1+dist2)
	return normalized_dist

sel = cmds.ls(selection=True)

for obj in sel:
	cmds.pointConstraint( 'obj1', 'obj0', w='weight1' )

My second problem is : how to feed the returned values of the xform command into my lists (pos0[], pos1[] and pos2[]) ? Right now Maya returns an error saying “list indices must be integers, not tuples”.

I hope my english was understandable. It’s not easy to explain. Could anyone please help ?

Hadrien


#2

The result of the “xform” already is a list, so simply:

pos0 = cmds.xform('obj0',q=1,ws=1,rp=1)

is okay.

For the constraint cmd, variables should work fine:

o1 = "obj1"
o2 = "obj2"
for obj in sel:
	weight = 1.23456
	cmds.pointConstraint(o1, o2, w=weight )

BTW: There is no need to use a semicolon “;” at the end of a line


#3

double post


#4

Thanks haggi, I rewrote it and it works ! I feel fantastic ! :slight_smile:


  import maya.cmds as cmds
  
  # find world space position of targets
  base_pos = cmds.xform('base',q=1,ws=1,rp=1)
  tip_pos = cmds.xform('tip',q=1,ws=1,rp=1)
  
  def relative_dist_from_pos(pos, ref):
  # vector substract to get relative pos
  	pos_from_ref = [m - n for m, n in zip(pos, ref)]
  # pythagoras to get distance from vector
  	dist_from_ref = (pos_from_ref[0]**2 + pos_from_ref[1]**2 + pos_from_ref[2]**2)**.5
  	return dist_from_ref
  
  def weight_from_dist(dist_from_base, dist_to_tip):
  	normalize_fac = (1/(dist_from_base + dist_to_tip))
  	dist_from_base *= normalize_fac
  	dist_to_tip *= normalize_fac
  	return dist_from_base, dist_to_tip
  
  sel = cmds.ls(sl=True)
  
  for obj in sel:
  # find world space pos of feather
  	feather_pos = cmds.xform(obj, q=1, ws=1, rp=1)
  
  # call relative_dist_from_pos
  	dist_from_base = relative_dist_from_pos(feather_pos, base_pos)
  	dist_to_tip = relative_dist_from_pos(feather_pos, tip_pos)
  
  # normalize distances
  	weight_from_dist(dist_from_base, dist_to_tip)
  
  # constrain the feather - weights are inverted
  # because the smaller the distance, the stronger the constraint
  	cmds.orientConstraint('base', obj, w=dist_to_tip)
  	cmds.orientConstraint('tip', obj, w=dist_from_base)
  

Now I tried passing the normalized distances through math.sin() but the result is strange, my feathers are rotating erratically… I had hoped they would spin in a smoother fashion… any idea where that could come from ?

As for the semicolon, I think I had python and mel confused…

I wonder, is the vector substract method above advisable ? The one using zip ? What does one usually resort to when in need for simple vector math ?

Hadriscus


#5

if you want to keep the code clear do it clear way:

x = pos[0]-ref[0]
y = pos[1]-ref[1]
z = pos[2]-ref[2]
(x*x + y*y + z*z)**0.5

if you want to be ‘pythonic’:

(sum(map(lambda x,y: (x-y)**2, pos, ref)))**.5

:slight_smile:


#6

i’m not sure that i can easy recognize the ‘distance between two points’ in the second expression

also in my opinion it’s hard to do vector algebra without vectors now.
i would do for example:

from maya.api.OpenMaya import MVector
## distance between a and b where a and b are three components list(or tuples):
(MVector(a) - MVector(b)).length()
## angle between a and b:
MVector(a).angle(MVector(b))


#7

Thanks a lot for your help Denis ! And sorry for the late reply. These were two loaded weeks.

I am not sure what pythonic means, from what I gather it’s a quality your code acquires after a few years, right ? 8) I cannot say I understand your example… that’s a lot of syntax in a single line. Can I ask you to break it down for me ? I am looking up map() right now but I could probably use some explaining of this particular case.

And thanks for your example of clarity, that I understood.

Seems like I reinvented the wheel… this is a library for manipulation of vectors ? Looks super cool… I can’t seem to find a manual with the functions listed, does such a thing exist ?

Thanks again

Hadriscus

edit if I remember correctly tuples are immutable right ? Does that means lists would be a better option for storing vectors I plan on manipulating ?


#8

For the MVector, have a look at the Maya manual. There you will find the MVector class with all methods.

Concerning the ‘pythonic’ example. This is a personal preference how you use python. You can do it in a very cryptic way (if you want it more cryptic, use Perl), but you will get the same result if you use it in a more descriptive way. The problem (at least my problem) is that I always stumble on these lines because I have to remember how it works and what it exactly does. If it is more descriptive, it is easier to understand.


#9

I see. Pythonic means something like “concise” then. I’ll rtfm also. :slight_smile:


#10

You sound like you should try…

import this

Everything will make sense then

David


#11

Actually I just stumbled on this page (http://blog.startifact.com/posts/older/what-is-pythonic.html) on which is suggested I try “import this”. Makes a little more sense now hehe.