Announcements

Between mid-October and November, the content on AREA will be relocated to the Autodesk Community M&E Hub and the Autodesk Community Gallery. Learn more HERE.

how do you calculate blendShape inputTargetItem indices for negative inbetweens?

how do you calculate blendShape inputTargetItem indices for negative inbetweens?

jwlove
Advocate Advocate
1,346 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,347 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