485 lines
12 KiB
Plaintext
Executable File
485 lines
12 KiB
Plaintext
Executable File
--remapSkinning.ms
|
|
--March 2013
|
|
--Matt Rennie
|
|
|
|
--tool to remap skinning from bones in initialBonesToRemove array to bones which remain present in the skin modifier
|
|
|
|
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
escapeEnable = true
|
|
|
|
-- arrayOfBones = #( --list of all bones in skin modifier this can eventually be queried via skin mod
|
|
-- $A,
|
|
-- $B,
|
|
-- $C,
|
|
-- $D,
|
|
-- $E,
|
|
-- $F,
|
|
-- $G
|
|
-- )
|
|
|
|
boneNames = #()
|
|
|
|
initialBonesToRemove = # --initial list of bones to remove
|
|
(
|
|
$F,
|
|
$C,
|
|
$E
|
|
)
|
|
|
|
bonesToRemove = #() --dynamically generated array of all bones which need to be removed (if we were to remove bone C then its children will need removing also
|
|
|
|
boneMapping = #( --dynamically generated 2d array. id1 = initial bone, id2 = bone to remap to
|
|
)
|
|
|
|
|
|
newVertData = #() --dynamically generated array if final vert data. Id1 = vertId, id2 = bone index, id3 = weightValue
|
|
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
fn reNomalize vertexId skinMod =
|
|
(
|
|
skinOps.unNormalizeVertex skinMod vertexID false
|
|
)
|
|
|
|
--if the vert has already been weighted tyhen the denormalizing will nacker up so we have to be a bit funky here!
|
|
fn deNormalize vertexID skinMod =
|
|
(
|
|
skinOps.unNormalizeVertex skinMod vertexID false
|
|
skinOps.SetVertexWeights skinMod vertexID 1 1.0
|
|
skinOps.unNormalizeVertex skinMod vertexID true
|
|
skinOps.SetVertexWeights skinMod vertexID 1 0.0
|
|
)
|
|
|
|
fn applyReMappedSkinning obj vertData =
|
|
(
|
|
skinMod = obj.modifiers[#Skin]
|
|
|
|
vertCount = undefined
|
|
|
|
if classof obj == Editable_mesh then
|
|
(
|
|
vertCount = meshop.getNumVerts obj.baseobject
|
|
)
|
|
else
|
|
(
|
|
vertCount = polyOp.getNumVerts obj.baseobject
|
|
)
|
|
|
|
--unnormalize weights
|
|
|
|
for vertexID = 1 to vertCount do
|
|
(
|
|
--now set all weights to 1 on the 1st bone
|
|
skinOps.SetVertexWeights skinMod vertexId 1 1
|
|
|
|
|
|
deNormalize vertexID skinMod
|
|
|
|
--now set the weights to 0
|
|
|
|
skinOps.setVertexWeights skinMod vertexId 1 0
|
|
|
|
weightCount = skinOps.GetVertexWeightCount skinMod vertexId
|
|
--now loop via the weightCount
|
|
for wt = 1 to weightCount do
|
|
(
|
|
for vtw = 1 to vertData.count do
|
|
(
|
|
if vertData[vtw][1] == vertexId do
|
|
(
|
|
--now we need to find vertexId in the newVertData array
|
|
boneArray = #()
|
|
WeightArray = #()
|
|
|
|
for val = 1 to newVertData.count do
|
|
(
|
|
if newVertData[val][1] == vertexId do
|
|
(
|
|
append boneArray newVertData[val][2]
|
|
append weightArray newVertData[val][3]
|
|
)
|
|
)
|
|
|
|
|
|
if weightArray.count != 0 do
|
|
(
|
|
skinOps.SetVertexWeights skinMod vertexId boneArray weightArray
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
--now renormalize the weights
|
|
|
|
reNomalize vertexId skinMod
|
|
)
|
|
|
|
print "Reskin complete."
|
|
)
|
|
|
|
fn compareSubArrays first second count =
|
|
(
|
|
|
|
result = true
|
|
|
|
if first.count != second.count then
|
|
(
|
|
result = false
|
|
)
|
|
else
|
|
(
|
|
for i = 1 to first.count do
|
|
(
|
|
if first[i] != second[i] do
|
|
(
|
|
result = false
|
|
)
|
|
)
|
|
)
|
|
result
|
|
|
|
)
|
|
|
|
|
|
|
|
fn conCatVertData vertData =
|
|
(
|
|
newVertData = #()
|
|
|
|
for vert = 1 to vertData.count do
|
|
(
|
|
--we need to find any duplicates of index 1 and index 2
|
|
|
|
currV = vertData[vert][1]
|
|
currentBoneId = vertData[vert][2]
|
|
|
|
for i = 1 to vertData.count do
|
|
(
|
|
if i != vert do
|
|
(
|
|
thisV = vertData[i][1]
|
|
thisBoneId = vertData[i][2]
|
|
|
|
if currV == thisV do
|
|
(
|
|
if thisBoneId == currentBoneId do
|
|
(
|
|
--ok we need to concat this data
|
|
currentWeight = vertData[vert][3]
|
|
newWeight = (vertData[i][3] + currentWeight)
|
|
|
|
tmpArr = #(thisV, currentBoneId, newWeight)
|
|
--print ("Appending "+(tmpArr as string))
|
|
appendIfUnique newVertData tmpArr
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
-- for i = 1 to newVertData.count do
|
|
-- (
|
|
-- print ("i:"+(i as string)+" ! "+(newVertData[i][1] as string)+", "+(newVertData[i][2] as string)+", "+(newVertData[i][3] as string))
|
|
-- )
|
|
|
|
--print ("newVertData.count:"+(newVertData.count as string))
|
|
--this is a hacky way of ensuring we dont get array duplicates
|
|
|
|
for nv = 1 to newVertData.count do
|
|
(
|
|
for dV = newVertData.count to nv+1 by -1 do
|
|
(
|
|
if dV != nv do --check that we're not the same array element
|
|
(
|
|
|
|
test = (compareSubArrays newVertData[nv] newVertData[dV] 3)
|
|
|
|
--print test
|
|
|
|
if test do
|
|
(
|
|
deleteItem newVertData dv
|
|
|
|
--format "Deleting %\n" dv
|
|
)
|
|
|
|
|
|
)
|
|
)
|
|
)
|
|
|
|
--print ("newVertData.count: "+(newVertData.count as string))
|
|
-- break()
|
|
--now we've concatted everythign we now need to parse through the vertData and copy over any items which dont have the first 2 indexes matching the newVertData
|
|
|
|
for vert = 1 to vertData.count do
|
|
(
|
|
currV = vertData[vert][1]
|
|
currB = vertData[vert][2]
|
|
|
|
--print ("currV: "+(currV as string))
|
|
--print ("currB: "+(currB as string))
|
|
|
|
newVertDataCount = newVertData.count
|
|
|
|
-- for newV = 1 to newVertDataCount do
|
|
-- (
|
|
-- if currV != newVertData[newV][1] do
|
|
-- (
|
|
-- if currB != newVertData[newV][2] do
|
|
-- (
|
|
-- tmpArr = #(currV, currB, vertData[vert][3])
|
|
-- appendIfUnique newVertData tmpArr
|
|
-- )
|
|
-- )
|
|
-- )
|
|
|
|
for newV = 1 to newVertDataCount do
|
|
(
|
|
test = (compareSubArrays newVertData[newV] VertData[vert] 2)
|
|
|
|
if test do
|
|
(
|
|
appendIfUnique newVertData vertData[vert]
|
|
)
|
|
)
|
|
--print ("newvertData.count: "+(newvertData.count as string))
|
|
)
|
|
)
|
|
|
|
fn reMapSkinning obj =
|
|
(
|
|
skinMod = obj.modifiers[#Skin]
|
|
|
|
vertCount = undefined
|
|
|
|
if classof obj == Editable_mesh then
|
|
(
|
|
vertCount = meshop.getNumVerts obj.baseobject
|
|
)
|
|
else
|
|
(
|
|
vertCount = polyOp.getNumVerts obj.baseobject
|
|
)
|
|
|
|
-- weightCount = skinOps.GetVertexWeightCount skinMod
|
|
|
|
--now loop through each vert in the mesh and query the weight
|
|
vertData = #() --multi dimensional array of vertIndex, boneIndex, boneWeight
|
|
|
|
for vert = 1 to vertCount do
|
|
(
|
|
weightCount = skinOps.GetVertexWeightCount skinMod vert
|
|
--now loop via the weightCount
|
|
for wt = 1 to weightCount do
|
|
(
|
|
boneItem = skinOps.GetVertexWeightBoneID skinMod vert wt --gets the index of the bone wt
|
|
boneWeight = skinOps.GetVertexWeight skinMod vert wt --gets the weight value applied to bone wt
|
|
|
|
|
|
|
|
tmpArr = #(vert, boneItem, boneWeight)
|
|
|
|
append vertData tmpArr
|
|
)
|
|
)
|
|
|
|
--now we have a full list of verts & their weighting, we need to look through boneNames and then also the bones to remove dynamic array and for any matches,
|
|
--we then need to find a match for that in the id 2 of vertData and remap that weight
|
|
|
|
for vert = 1 to vertData.count do
|
|
(
|
|
--now find the index of the current boneItem in index 2
|
|
|
|
currentVertBoneIndex = vertData[vert][2]
|
|
|
|
foundMatch = undefined
|
|
|
|
--need to find the index in the main bone array that matches boneMapping[currentVertBoneIndex][2]
|
|
|
|
|
|
|
|
foundmatch = findItem boneNames boneMapping[currentVertBoneIndex][2]
|
|
|
|
if foundMatch == undefined do ( break())
|
|
|
|
--now we have found the node we need to rpelace with we will change the value in vertData[vert][2] to match
|
|
|
|
if vertData[vert][2] != foundMatch do
|
|
(
|
|
fromBone = boneNames[vertData[vert][2]]
|
|
toBone = boneNames[foundMatch]
|
|
|
|
print ("For vert "+(currentVertBoneIndex as string)+" replacing "+(fromBone.name as string)+" with "+(toBone.name as string))
|
|
vertData[vert][2] = foundMatch
|
|
|
|
|
|
)
|
|
)
|
|
|
|
print ("vertData.count: "+(vertData.count as string))
|
|
|
|
conCatVertData vertData
|
|
|
|
applyReMappedSkinning obj vertData
|
|
)
|
|
|
|
fn buildBonesToRemove bonesToLose =
|
|
(
|
|
--go through the initialBonesToRemove array and add all of their children
|
|
|
|
for b in initialBonesToRemove do
|
|
(
|
|
boneChildren = b.children
|
|
|
|
appendIfUnique bonesToRemove b
|
|
|
|
for c in boneChildren do
|
|
(
|
|
appendIfUnique bonesToRemove c
|
|
)
|
|
)
|
|
|
|
format ("Initial removal nodes:"+"\n")
|
|
for i in initialBonesToRemove do
|
|
(
|
|
format (i.name+"\n")
|
|
)
|
|
|
|
format ("Total removal nodes:"+"\n")
|
|
for b in bonesToRemove do
|
|
(
|
|
format (b.name+"\n")
|
|
)
|
|
format ("---------------"+"\n")
|
|
)
|
|
|
|
fn boneRemap =
|
|
(
|
|
--first off build the total list of all nodes we will need to remove
|
|
buildBonesToRemove bonesToLose
|
|
|
|
for i in boneNames do
|
|
(
|
|
parBone = i.parent
|
|
|
|
if parBone != undefined then
|
|
(
|
|
--ok now we have a parent bone we need to see if i is in bonesToRemove
|
|
foundToRemove = finditem bonesToRemove i
|
|
|
|
if foundToRemove != 0 then
|
|
(
|
|
--ok so we need to remove bone 'i'
|
|
--now wee need to iterate up through its parents until we find a bone that is not to be removed
|
|
|
|
isValid = false
|
|
|
|
boneToUse = parBone
|
|
|
|
while isValid == false do
|
|
(
|
|
parValid = findItem bonesToRemove parBone
|
|
|
|
if parValid != 0 then --ok this parent is one we need to remove so we need to go higher
|
|
(
|
|
parBone = parBone.parent
|
|
isValid = false
|
|
)
|
|
else
|
|
(
|
|
--ok we can stick weights to this bone
|
|
boneToUse = parBone
|
|
isValid = true
|
|
)
|
|
)
|
|
|
|
tmpArr = #(i, boneToUse)
|
|
print ((i.name)+" mapped to "+(boneToUse.name)+" <-- CHANGE")
|
|
append boneMapping tmpArr
|
|
)
|
|
else
|
|
(
|
|
tmpArr = #(i, i)
|
|
print ((i.name)+" mapped to "+(i.name))
|
|
append boneMapping tmpArr
|
|
)
|
|
)
|
|
else
|
|
(
|
|
tmpArr = #(i, i)
|
|
print ((i.name)+" mapped to "+(i.name))
|
|
append boneMapping tmpArr
|
|
)
|
|
)
|
|
)
|
|
|
|
fn skinXfer obj =
|
|
(
|
|
skinMod = obj.modifiers[#Skin]
|
|
|
|
--first off build a list of all the bones in the skin modifier
|
|
totalSkinBones = skinOps.GetNumberBones skinMod
|
|
|
|
boneNames = #()
|
|
boneNamesTmp = #()
|
|
|
|
select obj
|
|
|
|
max modify mode
|
|
modPanel.setCurrentObject $.modifiers[#Skin]
|
|
|
|
for i = 1 to totalSkinBones do
|
|
(
|
|
thisBone = skinops.GetBoneName skinMod i 1
|
|
|
|
append boneNamesTMP thisBone
|
|
)
|
|
|
|
--now remap from bone names to bone objects
|
|
for i in boneNamesTmp do
|
|
(
|
|
tb = getNodeByName i
|
|
append boneNames tb
|
|
)
|
|
|
|
--now do the bone remapping
|
|
|
|
boneRemap()
|
|
|
|
-- for f = 1 to boneMapping.count do
|
|
-- (
|
|
-- print ((f as string)+": "+(boneMapping[f] as string))
|
|
-- )
|
|
|
|
--now we have the bone remapping done we need to transfer the skinning
|
|
reMapSkinning obj
|
|
)
|
|
|
|
|
|
if ((skinReMapGUI != undefined) and (skinReMapGUI.isDisplayed)) do
|
|
(destroyDialog skinReMapGUI)
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------
|
|
|
|
rollout skinReMapGUI "SkinRemap"
|
|
(
|
|
button btnSkinRemap "Remap Skinning on selected"
|
|
|
|
on btnSkinRemap pressed do
|
|
(
|
|
sela = selection as array
|
|
if sela.count == 1 then
|
|
(
|
|
skinXfer $
|
|
)
|
|
else
|
|
(
|
|
messagebox ("Please run with only one mesh selected.") beep:true
|
|
)
|
|
)
|
|
)
|
|
|
|
CreateDialog skinReMapGUI |