how do you calculate blendShape inputTargetItem indices for negative inbetweens?

how do you calculate blendShape inputTargetItem indices for negative inbetweens?

jwlove
Advocate Advocate
1,329 Views
4 Replies
Message 1 of 5

how do you calculate blendShape inputTargetItem indices for negative inbetweens?

jwlove
Advocate
Advocate

I'm writing something to create/save/re-create blendShapes programatically and I would really like to make use of the supportNegativeWeights capabilities.  Here's some code to create a quick simple example of what I'm trying to figure out - as well as some odd behavior I'm noticing (this is in maya 2017)

 

import maya.cmds as mc

# create base and 'control'
#
base = mc.polyCube(n='base', ch=False)[0]
ctrl = mc.circle(n='ctrl', nr=(0,1,0), ch=False)[0]
mc.addAttr(ctrl, ln='test', at='float', k=True)

# create targets
#
pos10_tgt = mc.polyCube(n='pos10_tgt', ch=False)[0]
neg10_tgt = mc.polyCube(n='neg10_tgt', ch=False)[0]
mc.xform(pos10_tgt, ws=True, t=(1.5, 0, 0))
mc.xform(neg10_tgt, ws=True, t=(3.0, 0, 0))
mc.move(0, 1, 0, '%s.cp[2:5]' %pos10_tgt, r=True)
mc.move(0, -1, 0, ['%s.cp[0:1]' %neg10_tgt, '%s.cp[6:7]' %neg10_tgt], r=True)

# create blendShape
#
bs = mc.blendShape(base, n='test_bs')[0]
mc.setAttr('%s.supportNegativeWeights' %bs, 1)
mc.blendShape(bs, e=True, t=(base, 0, pos10_tgt, 10.0))
mc.blendShape(bs, e=True, t=(base, 0, neg10_tgt, -10.0))

# alias attr and connect it
#
mc.aliasAttr('test', '%s.weight[0]' %bs)
mc.connectAttr('%s.test' %ctrl, '%s.test' %bs)

Ok, so, here I'm creating a cube and hooking in a positive 10 target and a negative 10 target for the first target index of the blendShape, then driving it with the 'test' attr on a circle.  And it works!  I have a blendShape with inbetween targets at 10 and -10 and it all works as I would expect (even past 10/-10).  I'm doing this instead of a 1/-1 value because I will be using this for some facial controls that will have a 10/-10 range, and it would be really nice to do a direct connection instead of needing a multiplyDivide or multDoubleLinear between the driver plug and the blendShape weight attr...  Also, a minor note - 'bs' is what I use for a 'blendShape' variable; it does not stand for 'bullsh**'

 

One part of the tool I'm writing checks to see if an inbetween already exists if you're trying to add a new one (through the tool).  It does this by calculating the inputTargetItem index and checking if it's in the list returned when you run mc.getAttr('%s.it[0].itg[%d].iti' %(bs, target_index), mi=True).  I calculate the inputTargetItem index with a helper function that returns this: int((inbetween_value * 1000) + 5000).  This works great for everything with an inbetween value of -5.0 up.  I also have a corresponding helper function that takes the index value and returns the inbetween value like so: (index - 5000) / 1000.0.  This is why anything -5.0 and up works (-5.0 results in an index value of 0)

 

So in this case, the positive 10 inbetween has an index of 15000 ((10 * 1000) + 5000 = 15000); and I can plug in the index value 15000 to determine the inbetween value of 10 ((15000 - 5000) / 1000.0 = 10). Awesome and expected.  But, the negative 10 inbetween index value is -2147478650. I don't know how this number is calculated: (-10 * 1000) + 5000 = -5000 (not -2147478650) and (-2147478650 - 5000) / 1000.0 = -2147483.65 (not -10)

 

First of all, I didn't even realize you could have a negative index in maya (mind blown on this one).  So, does anyone know the formula for calculating the inputTargetItem index for inbetween values < -5?  Also, the formula for calculating the inbetween value from a negative index would be nice too (but I could probably figure it out if I had the other...)

 

 

Before I close this massive wall of text, there's some odd stuff I've noticed with this too...

 

- The weight attr does not show up in the channel box for the blendShape until it's connected - not a huge deal since I'm doing this with code and it still works, but I thought it was worth mentioning since it may be a bug... (btw - it does show up if I add a target with a target value of 1).

 

- If I have the input/output connections of the blendShape pulled up in the node editor and mouse over the circle/dot in front of the negative inbetween's inputGeomTarget attr, maya spits out this error: // Error: line 1: No object matches name: test_bs.inputTarget[0].inputTargetGroup[0].inputTargetItem[-2147478650] //.

 

- Also, I can list connections from the target world mesh attr and get the corresponding inputGeomTarget on the blendShape, but if I list connections from the inputGeomTarget for the negative target I get an error:

 

pos_igt = mc.listConnections('%s.worldMesh[0]' %pos10_tgt, p=True)[0]
neg_igt = mc.listConnections('%s.worldMesh[0]' %neg10_tgt, p=True)[0]

pos_igt  # Result: u'test_bs.inputTarget[0].inputTargetGroup[0].inputTargetItem[15000].inputGeomTarget' #
neg_igt  # Result: u'test_bs.inputTarget[0].inputTargetGroup[0].inputTargetItem[-2147478650].inputGeomTarget' #

mc.listConnections(pos_igt)  # Result: [u'pos10_tgt'] #
mc.listConnections(neg_igt)  # ValueError: No object matches name: test_bs.inputTarget[0].inputTargetGroup[0].inputTargetItem[-2147478650].inputGeomTarget #

I'm pretty sure that the -2147478650 index item exists because it is connected and it's returned from listing the connections of the target geometry, so I'm assuming this is a bug...

 

Thank you for taking the time to read this, and for any help you can provide on that formula!

0 Likes
Accepted solutions (1)
1,330 Views
4 Replies
Replies (4)
Message 2 of 5

jwlove
Advocate
Advocate
Accepted solution

Ok... I may have just posted this way too prematurely....  Looks like to get the index from the inbetween value, you use -((ib_value * 1000) + 2147488650); and to get the inbetween value from the index, you use (-index - 2147488650) / 1000.0

 

I don't understand the significance of 2147486580... seems like a pretty random number, but here's a few tests that seem to work...

 

ib = -5.5
idx = -2147483150

ib = -6.0
idx = -2147482650

ib = -10.0
idx = -2147478650

ib = -20.0
idx = -2147468650

-((ib * 1000) + 2147488650) == idx
(-idx - 2147488650) / 1000.0 == ib

I basically tested this by sourcing a ib/idx pair, then running the last two lines one at a time and checking that the output in maya was # Result: True #.  It took a lot of added inbetweens to try and figure out the pattern...

 

Anyone have any idea why 2147486580?  It's actually simplified from 5000 + 2147483650 that I was using when I first got an equation that worked... so what's the significance of 2147483650, I suppose is the true question...?

0 Likes
Message 3 of 5

jwlove
Advocate
Advocate

odd... I must have mis-copied and pasted in my last post... it should have been 2147488650 instead of 2147486580 that I was asking the significance of...

 

For anyone looking at this thread to use the formulas, it is correct in the code snippet used to test them.  Of course, as I said in the bottom of that last post the true number I'm confused about is 2147483650 since the expanded formula I got to work before I simplified it is (((ib_value * 1000) + 5000) + 2147483650) * -1.  Just a note for clarity - this is only for inbetween values < -5.0...

 

I would have preferred to just edit the post instead of make a whole new one - but I can't seem to find an edit button anywhere....  Anyway, I hope someone will know what the deal is with that number and can let us know - seems rather random and maybe unnecessary to me since the original formula (for -5.0 and up) should have still worked fine?

 

thanks again!

0 Likes
Message 4 of 5

y_mistry
Participant
Participant

Hey thank you so much jwlove on that beautifully explained article. I came here in search of: how to know if a blendshape target is using any inbetween and at what value? Actually I was making a script to convert a rigged NURBS (with blendshapes) into a poly (Keeping all connections same).
The only area I was stuck, is extracting inbetweens info. Fortunately, I am working with all values between 0 and 1.

 

Thanks a lot for all the explanations!  You made my day! 🙂

0 Likes
Message 5 of 5

jwlove
Advocate
Advocate

You're quite welcome!  I'm glad it was helpful to someone (kinda doubted anyone would ever even see the thread, haha).  Yes, 0 to 1 is much simpler to determine, so you are in quite a bit of luck for some relatively simple code!

 

Good luck with your script, and thanks for the feedback!

0 Likes