How to access blend shape target weights using maya api?

Target weights can be set with the path blendShape1.inputTarget[0].inputTargetGroup[0].targetWeights[].*

I manage to get to here blendShape1.inputTarget[0].inputTargetGroup[0].targetWeights but when I try and access the individual elements for the array I am unable to. The only way I can access the individual elements is if I run getAttr and setAttr on every target weight, which seems to open them up to being accessed by the api? Is there a way around this? I linked the relevant sections of my script below.

bsDepFn = om.MFnDependencyNode(bsNode)
bsInputTarget = bsDepFn.findPlug('inputTarget',False) #blendShape1.inputTarget

bsInputTarget = bsInputTarget.elementByPhysicalIndex(0) #blendShape1.inputTarget[0]

bsInputTargetGroups = bsInputTarget.child(0) #blendShape1.inputTarget[0].inputTargetGroup
inputTargetGroups = []
for i in range(bsInputTargetGroups.numElements()): #blendShape1.inputTarget[0].inputTargetGroup[*]
    targetGroup = bsInputTargetGroups.elementByPhysicalIndex(i)
    inputTargetGroups.append(targetGroup)

targetWeights = inputTargetGroups[0].child(1) #blendShape1.inputTarget[0].inputTargetGroup[0].targetWeights

targetWeights.elementByPhysicalIndex(0) #causes error unless attr previously set with mel

This is how I did it in the past. It’s C++, but you get the idea:

function_set = The Fn for blendshape node
target_alias = In my case I passed the target alias as an argument

MObject input_target_obj = function_set.attribute("inputTarget");
MObject targetgroup_obj = function_set.attribute("inputTargetGroup");
MObject targetweights_obj = function_set.attribute("targetWeights");

MPlug gral_input_target_plug(bs_object, input_target_obj);
MPlug input_target_plug = gral_input_target_plug.elementByPhysicalIndex(0);
MPlug gral_targetgroup_plug = input_target_plug.child(targetgroup_obj);
const int alias_index = aliases.indexOf(target_alias);
MPlug targetgroup_plug = gral_targetgroup_plug.elementByLogicalIndex(indexes[alias_index]);
MPlug gral_targetweights_plug = targetgroup_plug.child(targetweights_obj);

MIntArray weighted_vertexes;
gral_targetweights_plug.getExistingArrayAttributeIndices(weighted_vertexes);

Then you loop through gral_targetweights_plug.numElements() and get an MPlug for:
unsigned int weighted_vtx_index = weighted_vertexes[i];
MPlug weight_plug = gral_targetweights_plug.elementByLogicalIndex(weighted_vtx_index);
double weight_value = weight_plug.asDouble();

weighted_vtx_index, weight_value --> and then do whatever with these!!

Thanks, followed your code and got it working. Seems like the issue was using elementByPhysicalIndex when I should’ve used elementByLogicalIndex. Not sure I completely understand the why but I think logical index is better for maya defined nodes?

Maya doesn’t store unneeded plugs. That’s very smart, and saves a TON of memory. But it can lead to confusion.
Also, I HATE the terms they used: Physical/Logical. But we’re stuck with 'em.

What Maya does is make internal lists kinda like this:

0 : PlugIndex[0]
1 : PlugIndex[5]
2 : PlugIndex[10]
3 : PlugIndex[6000]

Where the left column is all the numbers from 0 and up. And the numbers in the brackets are always increasing, but might skip over some numbers.

So, if you’re looking for PlugIndex[10], you can either access it with the number 2 (the physical index) OR the number 10 (the logical index)

But what does it do for something like PlugIndex[18]? In that case, you’re supposed to use the attribute’s default value. And annoyingly, if a plug index has the default value, Maya might or might not have that entry stored in its internal list.

So the way I would get the weights is by:

  1. Get the highest logical index
  2. Make a list that is the default value repeated maxLogicalIndex times
  3. Loop over the physical indices
  4. At each physical index, ask what its corresponding logical index is, and store its value in your list (overwriting the default)
1 Like

This is the method I have used before, and it was done using this API:cmds.blendShape()
code:

import maya.cmds as cmds
import os
bss=cmds.ls(type="blendShape")
bsnames=[]
for bs in bss:
    tbs=cmds.listAttr(bs+'.w', m=True)
    for i in range(len(tbs)):
        tbs[i]=bs+'.'+tbs[i]
    bsnames+=tbs
    weights = cmds.blendShape(bs,query=True,w=True)
    print(bsnames)
    print(weights)