[Closed] skin weights to array?
I’m trying to build an array of all the vert weights of the selected bone in a skin modifier.
From what I can tell, this SHOULD do it. But it doesn’t work how I expect it to.
clearlistener()
skinMod = $.modifiers["skin"]
skinVertCount =skinOps.GetNumberVertices skinMod
selBone = skinOps.GetSelectedBone skinMod
vertWeight= #()
for i = 1 to skinVertCount do
(
vertWeight[i] = (skinOps.GetVertexWeight skinmod i selBone)
format ("%
")vertWeight[i]
)
if you load this file: http://home.iprimus.com.au/wickergray/SkinScriptFile.max
and goto the skin modifier and turn on edit envelopes, select point01 in the bones window and then execute the script, I would have thought that the values that pop up in the listener would be:
1.0
1.0
0.5
0.5
0.0
0.0
0.0
0.0
0.0
0.0
but I get:
1.0
1.0
0.5
0.5
1.0
1.0
0.5
0.5
1.0
1.0
Which makes no sense to me.
And if you select point02 and execute the script, you get an ” Exceeded the vertex weight list count” error. Which is confusing me to no end cause the vert count is found by using “skinOps.GetNumberVertices”
Can anyone help me with this? I’ve been trying for hours to understand… I’ve also tried using <Skin>.effect with very varied success.
Cheers,
Cg.
GetSelectedBone gives you the index of the bone in the list, not the ID.
professor420, I’m not sure what you mean… in the help file, it says
skinOps.GetVertexWeight <Skin> <vertex_integer> <vertex_bone_integer>
How is the vertex_bone_integer different to it’s index?
How do I find the vertex_bone_integer? I’ve been going in loops reading all the related stuff in skin section in the maxscript help.
I’ve tried this way too, but I don’t get results like I would have expected:
clearlistener()
skinMod = $.modifiers["skin"]
skinVertCount =skinOps.GetNumberVertices skinMod
vertweight=#()
for i = 1 to skinVertCount do
(
skinOps.SelectVertices skinMod i
vertWeight[i] = skinMod.effect
format ("% %
") i vertWeight[i]
)
The selection doesn’t seem to update and just returns the same value 10 times. Which is the value of the vert that was selected before the script was executed.
Cheers.
use .index
clearlistener()
skinMod = selection[1].modifiers["skin"]
skinVertCount =skinOps.GetNumberVertices skinMod
selBone = skinOps.GetSelectedBone skinMod
for v = 1 to skinVertCount do
(
print (skinOps.GetVertexWeight selection[1] selection[1].verts[(skinVertCount[v])].index selBone)
)
This is printing every verts weight with respect to your bone – i hope (not at max right now) This will allow, if you encapsulate it into another loop, to go through every bone and grab its weights for every vert.
What you were doing, i think, was looping through i of your mesh verts, i is not equal to the vert ID is associated with i.e i = 1,2,3,4,5,6 but the vert.index of ith would be 56,12,43,67,32,3 for example.
for v = 1 to selection[1].selectedVerts.count do
(
print selection[1].verts[v].index – this is wrong
print selection[1].selectedVerts[v].index – this is right
)
Hi Eek, thanks for posting. That code unfortunately returns the following:
OK
Skin:Skin
10
2
– Error occurred in V loop
– Frame:
– V: 1
– No ““get”” function for 10
OK
Surely someone has had experience with this kind of thing before?
Anyone?
<vertex_bone_integer> is just the index for the bones array that’s affecting the vertex.
For example your vertex skinning array might be
[1][50][0.2]
[2][31][0.3]
[3][18][0.5]
This will means your vertex is currently weighted between 3 bones, with a boneID of 50,31 and 18, and weighting of 0.2,0.3,0.5 respectively.
So your <vertex_bone_integer> currently is pointing at either 1, 2 or 3.
In order to get the proper boneID you will need to read out the 50,31,18 into your array instead to make the whole thing workable. So probably you will need to use
<skinOps.GetVertexWeightBoneID>
in order to access the boneID
Hope this helps :)[size=2]
[/size]
Thanks so much Teirz. That really helped. I’ve now got a working script that is part way there. This code will iterate thru the verts and print out the bone weights. All I need to do now is collect the VERT weights of the selected bone to an array.
(
clearlistener()
skinMod = $.modifiers["skin"]
for i = 1 to (skinOps.GetNumberVertices skinMod) do
(
format ("Vertex %
")i
for j = 1 to (skinOps.GetVertexWeightCount skinMod i) do
(
boneID = (skinOps.GetVertexWeightBoneID skinMod i j)
boneName = (skinOps.GetBoneName skinMod boneID 0)
VertWeight = (skinOps.GetVertexWeight skinMod i j)
format (" Bone% % %
")boneID boneName VertWeight
)
format("
")
)
)
Good to hear that. Here’s something similar that i had written quite sometimes ago. Hope it helps to give you more idea on how to get your skin tool to next level. Basically this scripts allows different ppl to work on skinning different body parts concurrently e.g. one rigger work on the skinning on the body and another modeller is finetuning the skinning of the facial. And once the modeller is done, the rigger can bring in whatever the modeller has changed and update it in the latest build file. I’m still working on a better version of this as it was done during the crunch time of a TV production and was put together in quite a messy way.
-- Written by Sean Soh @ April 2007--
-- Tiny Island Productions --
rollout SkinToolRollout "Skin Tools" width:160 height:315
(
groupBox grpImpSkin "Import Skin" pos:[0,0] width:160 height:100
label lblImpFile "File:" pos:[10,25] width:30 height:15
button btnImpSKF "Pick Import SkinFile" pos:[40,20] width:110 height:20
checkbox chkVertex "Load By Vertex ID" pos:[20,45] width:130 height:15
button btnImport "Import!!!" pos:[10,70] width:140 height:20
groupBox grpExpSkin "Export Skin" pos:[0,100] width:160 height:215
multilistBox mlbExpBones "Bones:" pos:[5,120] width:150 height:8
button btnExpBoneList "Get Bone List" pos:[70,115] width:80 height:20
label lblExpFile "File:" pos:[10,260] width:30 height:15
button btnExpSKF "Pick Export SkinFile" pos:[40,255] width:110 height:20
button btnExport "Export!!!" pos:[10,280] width:140 height:20
on btnImpSKF pressed do
(
btnImpSKF.caption = getOpenFileName caption:"Export Skin Files" types:"Skin Files (*.skf)|*.skf|All Files (*.*)|*.*|"
)
on btnImport pressed do
(
input_name = btnImpSKF.caption
in_file = openFile input_name
if in_file != undefined then
(
-- loading the bone name, original Bone ID etc
if ((readDelimitedString in_file ":") == "B") then
(
numImpBones = (readDelimitedString in_file ":") as Integer
tempBoneID = readDelimitedString in_file ";"
tempBoneName = readDelimitedString in_file "
"
oBoneIDArray = filterString tempBoneID ","
oBoneNameArray = filterString tempBoneName ","
)
-- Construct the new bone ID mapping array
numBones = skinOps.GetNumberBones $.modifiers[#Skin]
modPanel.setCurrentObject $.modifiers[#Skin]
nBoneIDArray = #()
for x = 1 to oBoneIDArray.count do
(
oBoneIDArray[x] = oBoneIDArray[x] as Integer
for y = 1 to numBones do
(
nBoneName = skinOps.GetBoneName $.modifiers[#Skin] y 1
if (nBoneName == oBoneNameArray[x]) then
(
nBoneIDArray = append nBoneIDArray y
exit
)
)
)
-- loading vertex skinning info
while not eof in_file do
(
vID = (readDelimitedString in_file ":") as Integer
vBoneCount = (readDelimitedString in_file ":") as Integer
vWeighting = readDelimitedString in_file "
"
tempBoneIDArray = #()
tempBoneWeightArray = #()
temptotalweight = 0.0
tempVertexWeight = filterString vWeighting ",;"
-- construct temp array for holding vertex skinning data in new skin
for x = 1 to vBoneCount do
(
print tempVertexWeight[x]
oBoneID = tempVertexWeight[x * 2 - 1] as Integer
oBoneWeight = tempVertexWeight[x * 2] as Float
nBoneIDInd = finditem oBoneIDArray oBoneID
tempBoneIDArray = append tempBoneIDArray nBoneIDArray[nBoneIDInd]
tempBoneWeightArray = append tempBoneWeightArray oBoneWeight
temptotalweight += oBoneWeight
)
-- load in the current vertex weighting
cBoneCount = skinOps.GetVertexWeightCount $.modifiers[#Skin] vID
cBoneIDArray = #()
cBoneWeightArray = #()
ctemptotalweight = 0
-- construct the retained weight part
for x = 1 to cBoneCount do
(
cBoneID = skinOps.GetVertexWeightBoneID $.modifiers[#Skin] vID x
if ((findItem tempBoneIDArray cBoneID) == 0) then
(
cBoneIDArray = append cBoneIDArray cBoneID
cBoneWeight = skinOps.GetVertexWeight $.modifiers[#Skin] vID x
cBoneWeightArray = append cBoneWeightArray cBoneWeight
ctemptotalweight += cBoneWeight
)
)
-- readjust the weighting
for x = 1 to cBoneIDArray.count do
(
cBoneWeightArray[x] = (cBoneWeightArray[x] / ctemptotalweight) * (1 - temptotalweight)
)
-- joint the array
newBoneIDArray = cBoneIDArray + tempBoneIDArray
newBoneWeightArray = cBoneWeightArray + tempBoneWeightArray
-- finally set weight!!!
skinOps.ReplaceVertexWeights $.modifiers[#Skin] vID newBoneIDArray newBoneWeightArray
)
)
)
on btnExpBoneList pressed do
(
modPanel.setCurrentObject $.modifiers[#Skin]
numBones = skinOps.GetNumberBones $.modifiers[#Skin]
for y = 1 to numBones do
(
tempBoneName = skinOps.GetBoneName $.modifiers[#Skin] y 1
mlbExpBones.items = append mlbExpBones.items tempBoneName
)
modPanel.setCurrentObject $.modifiers[1]
)
on btnExpSKF pressed do
(
btnExpSKF.caption = getSaveFileName caption:"Export Skin Files" types:"Skin Files (*.skf)|*.skf|All Files (*.*)|*.*|"
)
on btnExport pressed do
(
output_name = btnExpSKF.caption
modPanel.setCurrentObject $.modifiers[#Skin]
if output_name != undefined then
(
output_file = createfile output_name
numBones = mlbExpBones.selection.count
numExpBones = mlbExpBones.selection.numberset
numVerts = skinOps.GetNumberVertices $.modifiers[#Skin]
selVerts = #()
selBones = #()
selBonesName = #()
-- create vertex collection flag array
selVerts.count = numVerts
-- cycle thru the system bones list, construct Verts list
for x = 1 to numBones do
(
-- if this bone is being selected for export
if mlbExpBones.selection[x] == true then
(
-- record the selected bone ID & name
append selBones x
append selBonesName mlbExpBones.items[x]
-- select the bone, and the affected vertice that's gonna export out
skinOps.selectBone $.modifiers[#Skin] x
skinOps.selectVerticesByBone $.modifiers[#Skin]
-- go thru the vertices see if they are selected, and marked them to export later on
for y in 1 to numVerts do
(
if (skinOps.IsVertexSelected $.modifiers[#Skin] y) == 1 then
(
selVerts[y] = 1
)
)
)
)
format "B:%:" numExpBones to:output_file
for x = 1 to numExpBones do
(
format "%," selBones[x] to:output_file
)
format ";" to:output_file
for x = 1 to numExpBones do
(
format "%," selBonesName[x] to:output_file
)
format "
" to:output_file
for x = 1 to numVerts do
(
if selVerts[x] == 1 then
(
selBoneCount = skinOps.GetVertexWeightCount $.modifiers[#Skin] x
ExpBoneCount = 0
selBoneString = ""
for y = 1 to selBoneCount do
(
selBoneID = skinOps.GetVertexWeightBoneID $.modifiers[#Skin] x y
selBoneWeight = skinOps.GetVertexWeight $.modifiers[#Skin] x y
if ((findItem selBones selBoneID) > 0) then
(
ExpBoneCount += 1
selBoneString = selBoneString + (selBoneID as String) + "," + (selBoneWeight as String) + ";"
)
)
format "%:%:" x ExpBoneCount to:output_file
format "%" selBoneString to:output_file
format "
" to:output_file
)
)
close output_file
edit output_name
)
)
)
SKF_Floater = newRolloutFloater "Tiny Skin Tools" 180 345
addRollout SkinToolRollout SKF_Floater
Cheers for that. I think the things that had me stumped were the fact that in the UI, you work with bones and assign vert weights. Whereas with MS, you work with verts and assign bone weights. And the fact that not every vert has a value for every bone which I thought would be the case even if it was a zero weight.
Your tip with the <skinOps.GetVertexWeightBoneID> brought it all all together for me. That, from my understanding of what I have working, will give me the main ID of the bone as referenced from the vert ID of the bone.
Also very generous of you to post your script. I’ll definately have a good look at that when I get a chance.
Cheers,
Cg.