819 lines
24 KiB
Plaintext
Executable File
819 lines
24 KiB
Plaintext
Executable File
|
|
-- Utility-functions for use by SkinDataTransfer tool:
|
|
struct RsSkinDataTransfer
|
|
(
|
|
-- Supplies list of verts adjacent to vertex vertNum, ordered anticlockwise
|
|
fn adjacentVerts obj vertNum listStartVert: startEdgeNum:1 =
|
|
(
|
|
--local DEBUGDATA = #(#ADJACENTVERTS, obj, vertNum, listStartVert, startEdgeNum)
|
|
|
|
-- Get the faces adjacent to vertNum:
|
|
local adjFaceNums = polyop.getFacesUsingVert obj vertNum
|
|
|
|
local adjFaceVertsList = #()
|
|
|
|
-- Get these faces' verts adjacent to vertNum, in anticlockwise order
|
|
local faceVerts, faceVertCount, initialVertIndex, faceVerts, firstAdj, lastAdj, insertAt
|
|
for faceNum in adjFaceNums collect
|
|
(
|
|
faceVerts = polyop.getFaceVerts obj faceNum
|
|
faceVertCount = faceVerts.count
|
|
|
|
initialVertIndex = findItem faceVerts vertNum
|
|
|
|
case initialVertIndex of
|
|
(
|
|
1:
|
|
(
|
|
firstAdj = faceVerts[2]
|
|
lastAdj = faceVerts[faceVertCount]
|
|
)
|
|
faceVertCount:
|
|
(
|
|
firstAdj = faceVerts[1]
|
|
lastAdj = faceVerts[faceVertCount - 1]
|
|
)
|
|
default:
|
|
(
|
|
firstAdj = faceVerts[initialVertIndex + 1]
|
|
lastAdj = faceVerts[initialVertIndex - 1]
|
|
)
|
|
)
|
|
|
|
faceVerts = #(#(firstAdj, lastAdj))
|
|
append adjFaceVertsList faceVerts
|
|
)
|
|
|
|
-- Order face-list
|
|
local vertList, firstVert, lastVert, checkList
|
|
|
|
local listRemoved = #{}
|
|
listRemoved.count = adjFaceVertsList.count
|
|
|
|
local changed = true
|
|
while changed do
|
|
(
|
|
changed = false
|
|
|
|
for n = 1 to adjFaceVertsList.count where not listRemoved[n] do
|
|
(
|
|
searchVertList = adjFaceVertsList[n]
|
|
lastVert = searchVertList[searchVertList.count][2]
|
|
|
|
for m = 1 to adjFaceVertsList.count where (m != n) and not listRemoved[m] do
|
|
(
|
|
checkList = adjFaceVertsList[m]
|
|
|
|
if (checkList[1][1] == lastVert) do
|
|
(
|
|
join searchVertList checkList
|
|
adjFaceVertsList[m] = undefined
|
|
listRemoved[m] = true
|
|
changed = true
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
-- Remove empty items left by sorting process:
|
|
adjFaceVertsList = for item in adjFaceVertsList where (item != undefined) collect item
|
|
|
|
if adjFaceVertsList.count > 1 do
|
|
(
|
|
format "Open?!?\t%\n" (adjFaceVertsList as string)
|
|
)
|
|
|
|
-- Output the verts adjacent to vertNum in clockwise order, using the first vert on each adjacent face:
|
|
outVal = for item in adjFaceVertsList[1] collect item[1]
|
|
|
|
-- Complete open vert-lists:
|
|
adjFaceVertsList = adjFaceVertsList[1]
|
|
local lastVert = adjFaceVertsList[adjFaceVertsList.count][2]
|
|
if (outVal[1] != lastVert) do
|
|
(
|
|
append outVal lastVert
|
|
)
|
|
|
|
-- Find requested start of list:
|
|
if (listStartVert != unsupplied) do
|
|
(
|
|
startEdgeNum = findItem outVal listStartVert
|
|
)
|
|
|
|
-- If startEdgeNum is used, rotate edge-order accordingly:
|
|
if (startEdgeNum > 1) do
|
|
(
|
|
local rotatedVerts = (for n = startEdgeNum to outVal.count collect outVal[n])
|
|
join rotatedVerts (for n = 1 to (startEdgeNum - 1) collect outVal[n])
|
|
outVal = rotatedVerts
|
|
)
|
|
|
|
--format "Rotated:%\n" (outVal as string)
|
|
|
|
outVal
|
|
),
|
|
|
|
fn expandTree obj item prevVert: doneVerts:#{} vertInfo:#() expandAll:false =
|
|
(
|
|
local vertNum = item[1]
|
|
|
|
case classOf item[2] of
|
|
(
|
|
UndefinedClass:
|
|
(
|
|
if expandAll or (not doneVerts[vertNum]) do
|
|
(
|
|
doneVerts[vertNum] = true
|
|
item[2] = for adjVert in (adjacentVerts obj vertNum listStartVert:prevVert) collect #(adjVert, undefined, undefined)
|
|
vertInfo[vertNum] = item[2]
|
|
)
|
|
)
|
|
Array:
|
|
(
|
|
for subItem in item[2] do
|
|
(
|
|
doneVerts[vertNum] = true
|
|
expandTree obj subItem prevVert:vertNum doneVerts:doneVerts vertInfo:vertInfo expandAll:expandAll
|
|
)
|
|
)
|
|
)
|
|
),
|
|
|
|
fn treeHash item =
|
|
(
|
|
if item[2][1][2] == undefined then
|
|
(
|
|
item[2].count
|
|
)
|
|
else
|
|
(
|
|
getHashValue (for subItem in item[2] collect (treeHash subItem)) 0
|
|
)
|
|
),
|
|
|
|
fn getUniquePatternHashLevel obj startVert maxPatternDepth:5 =
|
|
(
|
|
-- Increase side of adjacency-tree until only one rotation produces a unique hash
|
|
local adjVertNums = adjacentVerts obj startVert
|
|
local rootAdjacencies = for adjVert in adjVertNums collect #(adjVert, undefined)
|
|
local rootEdgeCount = rootAdjacencies.count
|
|
|
|
local adjacencyTree = #(startVert, rootAdjacencies)
|
|
|
|
local altTrees = for n = 2 to rootEdgeCount collect
|
|
(
|
|
local rotatedEdges = (for m = n to rootEdgeCount collect rootAdjacencies[m])
|
|
join rotatedEdges (for m = 1 to (n - 1) collect rootAdjacencies[m])
|
|
#(startVert, rotatedEdges)
|
|
)
|
|
|
|
local patternDepth = 0
|
|
|
|
local lastDoneVertsCount
|
|
local doneVerts = #{}
|
|
|
|
-- Expand the tree out until its first tree-topology is unique, (to avoid upside-down matches or similar),
|
|
-- all verts have been accounted for (this will happen for radially-symmetrical objects),
|
|
-- or the maxPatternDepth has been reached (where the selected vert is in a radially-symmetrical region)
|
|
local patternFound, noMatch, patternHash, altHash
|
|
while
|
|
(
|
|
(patternDepth < maxPatternDepth) and
|
|
(lastDoneVertsCount != doneVerts.numberSet) and
|
|
(patternFound == undefined)
|
|
)
|
|
do
|
|
(
|
|
patternDepth += 1
|
|
lastDoneVertsCount = doneVerts.numberSet
|
|
|
|
expandTree obj adjacencyTree doneVerts:doneVerts expandAll:true
|
|
|
|
patternHash = treeHash adjacencyTree
|
|
|
|
--format "% hash 0: %\n" obj.name (patternHash as string)
|
|
|
|
noMatch = true
|
|
local treeNum = 0
|
|
for altTree in altTrees while noMatch do
|
|
(
|
|
treeNum += 1
|
|
altHash = treeHash altTree
|
|
|
|
--format "% hash %: %\n" obj.name treeNum (altHash as string)
|
|
|
|
noMatch = (altHash != patternHash)
|
|
|
|
if not noMatch do
|
|
(
|
|
--format "patternDepth %: treeNum % matched: %\n" patternDepth treeNum patternHash
|
|
)
|
|
)
|
|
|
|
if noMatch do
|
|
(
|
|
patternFound = patternHash
|
|
)
|
|
)
|
|
|
|
-- If matching-area has radially-symmetrical topology, supply the topmost vert to provide an initial edge to work from
|
|
-- This will most likely be the top vert of an eyeball, so should be the same on both models.
|
|
local topVertNum = if noMatch then unsupplied else
|
|
(
|
|
local adjVertPosZs = for adjVert in adjVertNums collect (polyop.getVert obj adjVert).z
|
|
local upperVertNum = 1
|
|
local upperVertZ = adjVertPosZs[1]
|
|
|
|
for n = 2 to adjVertNums.count do
|
|
(
|
|
if (adjVertPosZs[n] > upperVertZ) do
|
|
(
|
|
upperVertZ = adjVertPosZs[n]
|
|
upperVertNum = n
|
|
)
|
|
)
|
|
|
|
upperVertNum
|
|
)
|
|
|
|
struct RSskinXferPatternHash (patternDepth, patternHash, topVertNum)
|
|
|
|
return RSskinXferPatternHash patternDepth patternHash topVertNum
|
|
),
|
|
|
|
fn findPatternTreeMatch obj startVert patternHashData =
|
|
(
|
|
local DEBUGDATA = #(#findPatternTreeMatch, obj, patternHashData)
|
|
|
|
local patternDepth = patternHashData.patternDepth
|
|
local patternHash = patternHashData.patternHash
|
|
local sourceTopVert = patternHashData.topVertNum
|
|
|
|
local adjVertNums = adjacentVerts obj startVert
|
|
local rootAdjacencies = for adjVert in adjVertNums collect #(adjVert, undefined)
|
|
local rootEdgeCount = rootAdjacencies.count
|
|
|
|
local vertTrees = #(#(startVert, rootAdjacencies))
|
|
|
|
for n = 1 to patternDepth do
|
|
(
|
|
expandTree obj vertTrees[1] expandAll:true
|
|
)
|
|
|
|
for n = 2 to rootEdgeCount do
|
|
(
|
|
local rotatedEdges = (for m = n to rootEdgeCount collect rootAdjacencies[m])
|
|
join rotatedEdges (for m = 1 to (n - 1) collect rootAdjacencies[m])
|
|
append vertTrees #(startVert, rotatedEdges)
|
|
)
|
|
|
|
local foundTreeNum
|
|
|
|
for n = 1 to vertTrees.count while (foundTreeNum == undefined) do
|
|
(
|
|
if ((treeHash vertTrees[n]) == patternHash) do
|
|
(
|
|
foundTreeNum = n
|
|
)
|
|
)
|
|
|
|
format "TREENUM: %\n" foundTreeNum
|
|
-- If pattern matches, but has radially-symmetrical topology, a Top Vert will have been provided to match with:
|
|
if (foundTreeNum != undefined) and (sourceTopVert != unsupplied) do
|
|
(
|
|
-- print "Toppy time!"
|
|
|
|
local adjVertPosZs = for adjVert in adjVertNums collect (polyop.getVert obj adjVert).z
|
|
local upperVertZ = adjVertPosZs[1]
|
|
local topVertNum = 1
|
|
for n = 2 to adjVertNums.count do
|
|
(
|
|
if (adjVertPosZs[n] > upperVertZ) do
|
|
(
|
|
upperVertZ = adjVertPosZs[n]
|
|
topVertNum = n
|
|
)
|
|
format "Top vert: %: %\n" foundTreeNum adjVertNums[foundTreeNum]
|
|
)
|
|
|
|
-- Use the two meshes' Top Verts to work out which edge-number corresponds with Edge 1 on the source-mesh:
|
|
foundTreeNum = (mod (adjVertNums.count + topVertNum - sourceTopVert + 1) adjVertNums.count) as integer
|
|
if (foundTreeNum == 0) do (foundTreeNum = adjVertNums.count)
|
|
)
|
|
|
|
-- This number is the edge-number of the target-mesh's pattern-tree that corresponds to the first edge of the source
|
|
foundTreeNum
|
|
),
|
|
|
|
-- Provides a list of all verts sharing a mesh-element with "vert"
|
|
fn getConnectedVerts obj vert =
|
|
(
|
|
local vertFaces = polyop.getFacesUsingVert obj vert
|
|
local elementFaces = polyop.getElementsUsingFace obj vertFaces
|
|
polyop.getVertsUsedOnlyByFaces obj elementFaces
|
|
),
|
|
|
|
fn matchObjVerts baseSourceObj baseTargetObj sourceVert targetVert targetStartEdge:1 debugVertMove:false =
|
|
(
|
|
struct vertMatchData (sourceVert, targetVert)
|
|
|
|
local sourceNumVerts = polyop.getNumVerts baseSourceObj
|
|
local targetNumVerts = polyop.getNumVerts baseTargetObj
|
|
|
|
local sourceAdjVerts = adjacentVerts baseSourceObj sourceVert
|
|
local targetAdjVerts = adjacentVerts baseTargetObj targetVert startEdgeNum:targetStartEdge
|
|
|
|
local matchArray = #()
|
|
matchArray.count = sourceNumVerts
|
|
|
|
matchArray[sourceVert] = vertMatchData sourceVert:sourceVert targetVert:targetVert
|
|
|
|
-- Set up initial matched verts
|
|
local vertsMatched = #{sourceVert}
|
|
vertsMatched.count = sourceNumVerts
|
|
for n = 1 to sourceAdjVerts.count do
|
|
(
|
|
matchArray[sourceAdjVerts[n]] = vertMatchData sourceVert:sourceAdjVerts[n] targetVert:targetAdjVerts[n]
|
|
vertsMatched[sourceAdjVerts[n]] = true
|
|
)
|
|
|
|
local unmatchedVerts
|
|
if debugVertMove do
|
|
(
|
|
for vertNum in vertsMatched do
|
|
(
|
|
polyop.setVert baseTargetObj matchArray[vertNum].targetVert (polyop.getVert baseSourceObj vertNum) node:baseSourceObj
|
|
--polyop.setVertColor baseTargetObj 0 matchArray[vertNum].targetVert green
|
|
)
|
|
|
|
unmatchedVerts = getConnectedVerts baseTargetObj targetVert
|
|
)
|
|
|
|
-- Get edge-lists:
|
|
local sourceEdgeVerts = for edgeNum = 1 to (polyop.getNumEdges baseSourceObj) collect
|
|
(
|
|
(polyop.getEdgeVerts baseSourceObj edgeNum) as bitArray
|
|
)
|
|
local targetEdgeVerts = for edgeNum = 1 to (polyop.getNumEdges baseTargetObj) collect
|
|
(
|
|
(polyop.getEdgeVerts baseTargetObj edgeNum) as bitArray
|
|
)
|
|
|
|
local matchedSourceEdges = #{}
|
|
local matchedTargetEdges = #{}
|
|
|
|
local matchedSourceFaces = #{}
|
|
local matchedTargetFaces = #{}
|
|
|
|
local edgeMatches = #()
|
|
edgeMatches.count = sourceEdgeVerts.count
|
|
|
|
-- Function to re-order a face's vert-list, putting two particular verts to the start of the list:
|
|
fn edgeOrderFace faceVerts vertA vertB =
|
|
(
|
|
local firstVert = case of
|
|
(
|
|
(faceVerts[1] == vertA):
|
|
(
|
|
if (faceVerts[2] == vertB) then 1 else faceVerts.count
|
|
)
|
|
(faceVerts[1] == vertB):
|
|
(
|
|
if (faceVerts[2] == vertA) then 1 else faceVerts.count
|
|
)
|
|
default:
|
|
(
|
|
local findA = findItem faceVerts vertA
|
|
local findB = findItem faceVerts vertB
|
|
if (findA < findB) then findA else findB
|
|
)
|
|
)
|
|
|
|
local newList = (for n = firstVert to faceVerts.count collect faceVerts[n])
|
|
join newList (for n = 1 to (firstVert - 1) collect faceVerts[n])
|
|
newList
|
|
)
|
|
|
|
if not debugVertMove do
|
|
(
|
|
progressStart "Matching verts:"
|
|
)
|
|
|
|
local maxVertCount = (getConnectedVerts baseSourceObj sourceVert).count
|
|
local lastMatched = 0
|
|
local notCancelled = true
|
|
|
|
-- Predefine all variables that'll be reused a lot
|
|
local keepLooking, sourceEdge, targetEdge, sourceEdgeFaces, targetEdgeFaces, sourceFaceVertLists, targetFaceVertLists
|
|
local searchEdge, sourceVerts, sourceVert, targetVerts, targetVert, targetEdgeNum, newMatchedFaces, checkVert
|
|
|
|
-- Keep looping until loop stops making changes
|
|
while (lastMatched != vertsMatched.numberSet) \
|
|
and (notCancelled = progressUpdate (100.0 * vertsMatched.numberSet / maxVertCount)) \
|
|
-- for n = 1 to 1
|
|
do
|
|
(
|
|
lastMatched = vertsMatched.numberSet
|
|
|
|
-- MATCH UP EDGES FOR NEWLY-MATCHED VERTS --
|
|
|
|
local newMatchedEdges = #{}
|
|
newMatchedEdges.count = sourceEdgeVerts.count
|
|
|
|
-- For unmatched edges...
|
|
for sourceEdgeNum = 1 to sourceEdgeVerts.count where not matchedSourceEdges[sourceEdgeNum] do
|
|
(
|
|
sourceEdge = sourceEdgeVerts[sourceEdgeNum]
|
|
|
|
-- where a match for its verts has been found...
|
|
-- (sneaky bitArray matching!)
|
|
if ((sourceEdge * vertsMatched).numberSet == 2) do
|
|
(
|
|
-- Translate this edge over to the target-vert numbers:
|
|
searchEdge = (for vertNum in sourceEdge collect matchArray[vertNum].targetVert) as bitArray
|
|
|
|
-- find the matching edge on the target mesh:
|
|
keepLooking = true
|
|
for targetEdgeNum = 1 to targetEdgeVerts.count where not matchedTargetEdges[targetEdgeNum] while keepLooking do
|
|
(
|
|
if ((searchEdge - targetEdgeVerts[targetEdgeNum]).numberSet == 0) do
|
|
(
|
|
-- Convert edge-data to arrays, now we're done with checking them as bitArrays
|
|
edgeMatches[sourceEdgeNum] = targetEdgeNum
|
|
|
|
sourceEdgeVerts[sourceEdgeNum] = sourceEdgeVerts[sourceEdgeNum] as array
|
|
targetEdgeVerts[targetEdgeNum] = targetEdgeVerts[targetEdgeNum] as array
|
|
|
|
matchedSourceEdges[sourceEdgeNum] = true
|
|
matchedTargetEdges[targetEdgeNum] = true
|
|
newMatchedEdges[sourceEdgeNum] = true
|
|
keepLooking = false
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
-- USE THE NEWLY-MATCHED EDGES TO FIND FACES --
|
|
|
|
for edgeNum in newMatchedEdges do
|
|
(
|
|
-- Get unmatched faces using this source-mesh edge:
|
|
sourceEdgeFaces = (polyop.getFacesUsingEdge baseSourceObj edgeNum) - matchedSourceFaces
|
|
|
|
if (sourceEdgeFaces.numberSet != 0) do
|
|
(
|
|
sourceEdgeFaces = sourceEdgeFaces as array
|
|
|
|
-- Get unmatched faces using this target-mesh edge:
|
|
targetEdgeNum = edgeMatches[edgeNum]
|
|
targetEdgeFaces = ((polyop.getFacesUsingEdge baseTargetObj targetEdgeNum) - matchedTargetFaces) as array
|
|
|
|
sourceVerts = sourceEdgeVerts[edgeNum]
|
|
targetVerts = targetEdgeVerts[targetEdgeNum]
|
|
|
|
sourceFaceVertLists = for faceNum in sourceEdgeFaces collect (polyop.getFaceVerts baseSourceObj faceNum)
|
|
targetFaceVertLists = for faceNum in targetEdgeFaces collect (polyop.getFaceVerts baseTargetObj faceNum)
|
|
|
|
-- Order faceLists to put our edge-verts at start of list:
|
|
-- This allows us to compare vert-order on faces, then find further vert-matches.
|
|
for n = 1 to sourceEdgeFaces.count do
|
|
(
|
|
sourceFaceVertLists[n] = edgeOrderFace sourceFaceVertLists[n] sourceVerts[1] sourceVerts[2]
|
|
)
|
|
for n = 1 to targetEdgeFaces.count do
|
|
(
|
|
targetFaceVertLists[n] = edgeOrderFace targetFaceVertLists[n] targetVerts[1] targetVerts[2]
|
|
)
|
|
|
|
newMatchedFaces = #{}
|
|
for sourceFaceNum = 1 to sourceFaceVertLists.count do
|
|
(
|
|
-- Find the adjacent face to this edge where the matched verts go in the same direction,
|
|
-- and use those matched faces to match some more verts
|
|
|
|
sourceVerts = sourceFaceVertLists[sourceFaceNum]
|
|
checkVert = matchArray[sourceVerts[1]].targetVert
|
|
|
|
keepLooking = true
|
|
for targetFaceNum = 1 to targetFaceVertLists.count where not newMatchedFaces[targetFaceNum] while keepLooking do
|
|
(
|
|
targetVerts = targetFaceVertLists[targetFaceNum]
|
|
|
|
-- This makes sure the correct face is used of the two possible on this edge
|
|
if (targetVerts[1] == checkVert) do
|
|
(
|
|
-- Don't do vert-matching for faces with different vert-counts
|
|
if (sourceVerts.count == targetVerts.count) do
|
|
(
|
|
-- We have a winner!
|
|
|
|
matchedSourceFaces[sourceFaceNum] = true
|
|
matchedTargetFaces[targetFaceNum] = true
|
|
newMatchedFaces[targetFaceNum] = true
|
|
keepLooking = false
|
|
|
|
-- Now we can match up the unmatched verts on this face:
|
|
for vertNum = 1 to sourceVerts.count do
|
|
(
|
|
sourceVert = sourceVerts[vertNum]
|
|
if not vertsMatched[sourceVert] do
|
|
(
|
|
vertsMatched[sourceVert] = true
|
|
matchArray[sourceVert] = vertMatchData sourceVert:sourceVert targetVert:targetVerts[vertNum]
|
|
|
|
if debugVertMove do
|
|
(
|
|
polyop.setVert baseTargetObj targetVerts[vertNum] (polyop.getVert baseSourceObj sourceVert) node:baseSourceObj
|
|
--polyop.setVertColor baseTargetObj 0 targetVerts[vertNum] green
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
if debugVertMove do
|
|
(
|
|
redrawViews()
|
|
)
|
|
)
|
|
|
|
if not debugVertMove do
|
|
(
|
|
progressEnd()
|
|
)
|
|
|
|
if debugVertMove do
|
|
(
|
|
for item in matchArray where (item != undefined) do (unmatchedVerts[item.targetVert] = false)
|
|
--polyop.deleteVerts baseTargetObj unmatchedVerts
|
|
)
|
|
|
|
if notCancelled then
|
|
(
|
|
local outArray = #(#(),#())
|
|
|
|
for n = vertsMatched do
|
|
(
|
|
append outArray[1] matchArray[n].sourceVert
|
|
append outArray[2] matchArray[n].targetVert
|
|
)
|
|
|
|
outArray
|
|
)
|
|
else false
|
|
),
|
|
|
|
fn getStartVert obj =
|
|
(
|
|
local baseObj = if (isProperty obj #baseObject) then obj.baseObject else obj
|
|
local vertSel = (polyop.getVertsByFlag baseObj 1) as array
|
|
local objName = if (isProperty obj #name) then obj.name else ""
|
|
|
|
case of
|
|
(
|
|
(vertSel.count == 0):
|
|
(
|
|
messageBox ("No vertices selected on object " + objName) title:"No verts selected on object"
|
|
false
|
|
)
|
|
(vertSel.count > 1):
|
|
(
|
|
messageBox ((vertSel.count as string) + " verts selected on object " + objName + "\nPlease select only one!") title:"Too many verts selected on object"
|
|
false
|
|
)
|
|
default:
|
|
(
|
|
vertSel[1]
|
|
)
|
|
)
|
|
),
|
|
|
|
fn getVertTransferData obj =
|
|
(
|
|
local selObjs = selection as array
|
|
local baseObj = if (isProperty obj #baseObject) then obj.baseObject else obj
|
|
|
|
local skinMod = obj.modifiers[#skin]
|
|
if (getCommandPanelTaskMode() != #modify) do (setCommandPanelTaskMode #modify)
|
|
if (modPanel.getCurrentObject() != skinMod) do (modPanel.setCurrentObject skinMod)
|
|
|
|
local vertData
|
|
if ((skinOps.GetNumberBones skinMod) == 0) then
|
|
(
|
|
messageBox ((obj as string) + "\nObject's Skin modifier has no bones!")
|
|
)
|
|
else
|
|
(
|
|
local boneCount, boneIDs, boneWeights
|
|
vertData = for vertNum = 1 to (polyop.getNumVerts baseObj) collect
|
|
(
|
|
boneCount = skinOps.getVertexWeightCount skinMod vertNum
|
|
|
|
boneIDs = for boneNum = 1 to boneCount collect
|
|
(
|
|
skinOps.getVertexWeightBoneId skinMod vertNum boneNum
|
|
)
|
|
|
|
boneWeights = for boneNum = 1 to boneCount collect
|
|
(
|
|
skinOps.getVertexWeight skinMod vertNum boneNum
|
|
)
|
|
|
|
#(boneIDs, boneWeights)
|
|
)
|
|
)
|
|
|
|
select selObjs
|
|
|
|
if (vertData == undefined) then (return undefined) else
|
|
(
|
|
struct RSskinXferData (sourcePoly, vertData, transform, skinMod)
|
|
|
|
return RSskinXferData (copy obj.baseObject) vertData obj.transform (copy skinMod)
|
|
)
|
|
),
|
|
|
|
fn pasteVertTransferData obj copyData sourceStartVert targetStartVert =
|
|
(
|
|
local sourcePoly = copyData.sourcePoly
|
|
|
|
local sourcePatternHash = getUniquePatternHashLevel sourcePoly sourceStartVert
|
|
local vertData = copyData.vertData
|
|
|
|
obj.transform = copyData.transform
|
|
|
|
local skinMod = obj.modifiers[#skin]
|
|
if skinMod == undefined do
|
|
(
|
|
skinMod = copy copyData.skinMod
|
|
addModifier obj skinMod
|
|
)
|
|
|
|
local baseObj = obj.baseObject
|
|
local vertTreeNum = findPatternTreeMatch baseObj targetStartVert sourcePatternHash
|
|
|
|
-- Pattern-match failure:
|
|
if (vertTreeNum == undefined) do
|
|
(
|
|
return false
|
|
)
|
|
|
|
local matchVerts = matchObjVerts sourcePoly baseObj sourceStartVert targetStartVert targetStartEdge:vertTreeNum
|
|
|
|
local sourceVertNums = matchVerts[1]
|
|
local targetVertNums = matchVerts[2]
|
|
|
|
if (getCommandPanelTaskMode() != #modify) do (setCommandPanelTaskMode #modify)
|
|
if (modPanel.getCurrentObject() != skinMod) do (modPanel.setCurrentObject skinMod)
|
|
|
|
--skinOps.resetAllBones skinMod
|
|
local sourceVert, targetVert
|
|
for n = 1 to sourceVertNums.count do
|
|
(
|
|
sourceVert = sourceVertNums[n]
|
|
targetVert = targetVertNums[n]
|
|
|
|
local DEBUGDATA = #(#ReplaceVertexWeights, skinMod, n, sourceVert, targetVert, vertData[sourceVert])
|
|
skinOps.ReplaceVertexWeights skinMod targetVert vertData[sourceVert][1] vertData[sourceVert][2]
|
|
)
|
|
|
|
redrawViews()
|
|
return true
|
|
),
|
|
|
|
fn copyVerts =
|
|
(
|
|
local StartTime = TimeStamp()
|
|
|
|
local objSel = for obj in selection where (isKindOf obj.baseObject Editable_Poly) collect obj
|
|
|
|
case of
|
|
(
|
|
(objSel.count < 2):
|
|
(
|
|
messageBox ("Please select two Editable Poly objects") title:"Not enough suitable objects selected"
|
|
return false
|
|
)
|
|
(objSel.count > 2):
|
|
(
|
|
messageBox ("Please select only two Editable Poly objects") title:"Too many objects selected"
|
|
return false
|
|
)
|
|
)
|
|
|
|
local objA = $[1]
|
|
local objB = $[2]
|
|
|
|
-- Ensure that both meshes are nice and clean before examining them:
|
|
polyOp.collapseDeadStructs objA
|
|
polyOp.collapseDeadStructs objB
|
|
|
|
local objAstartVert = getStartVert objA
|
|
if objAstartVert == false do return false
|
|
|
|
local objBstartVert = getStartVert objB
|
|
if objBstartVert == false do return false
|
|
|
|
local patternHash = getUniquePatternHashLevel objA objAstartVert
|
|
local startEdgeNum = findPatternTreeMatch objB objBstartVert patternHash
|
|
|
|
if (startEdgeNum == undefined) do
|
|
(
|
|
messageBox ("Topology-match not found!") title:"Edges around selected verts are too different"
|
|
return false
|
|
)
|
|
|
|
|
|
local matchVerts = matchObjVerts objA objB objAstartVert objBstartVert targetStartEdge:startEdgeNum debugVertMove:true
|
|
|
|
local vertNumsA = matchVerts[1]
|
|
local vertNumsB = matchVerts[2]
|
|
|
|
format "Matched: %\n" vertNumsA.count
|
|
|
|
for n = 1 to matchVerts[1].count do
|
|
(
|
|
-- polyop.setVert objB vertNumsB[n] (polyop.getVert objA vertNumsA[n])
|
|
)
|
|
|
|
redrawViews()
|
|
select objB
|
|
|
|
format "\nTook % seconds\n\n" ((TimeStamp() - StartTime) / 1000.0)
|
|
|
|
print matchVerts
|
|
matchVerts
|
|
),
|
|
|
|
-- Called by on viewport-redraw by RStransferSkinDataDrawCallback:
|
|
fn viewportDraw =
|
|
(
|
|
gw.setTransform (Matrix3 1)
|
|
local objColours = #(green, red)
|
|
|
|
local objDataArray = ::RsSkinDataTransferRoll.objVertSelData
|
|
|
|
for dataNum = 1 to objDataArray.count do
|
|
(
|
|
local objData = objDataArray[dataNum]
|
|
local obj = objData.obj
|
|
|
|
if (isValidNode obj) and (not obj.isHidden) do
|
|
(
|
|
local objBase = if isProperty obj #baseObject then obj.baseObject else obj
|
|
|
|
local objColour = objColours[dataNum]
|
|
|
|
local vertNums = objData.elemStartVerts
|
|
local chooseVert = objData.chooseVert
|
|
|
|
local vertNum, drawPos
|
|
for n = 1 to vertNums.count where (vertNums[n] != undefined) do
|
|
(
|
|
vertNum = vertNums[n]
|
|
drawPos = gw.wtranspoint (polyop.getvert objBase vertNum node:obj) + [1,1,0]
|
|
--gw.wMarker drawPos #asterisk color:white--objColour
|
|
--gw.wMarker (drawPos + [-1,0,0]) #smallHollowBox color:white--objColour
|
|
gw.wRect (box2 [drawPos.x - 3, drawPos.y - 3] [drawPos.x + 4, drawPos.y + 3]) objColour
|
|
gw.wMarker drawPos #circle color:white
|
|
gw.wtext drawPos (n as string) color:white
|
|
)
|
|
|
|
if (chooseVert != undefined) and ((findItem vertNums chooseVert) == 0) do
|
|
(
|
|
drawPos = gw.wtranspoint (polyop.getvert objBase chooseVert node:obj) + [1,1,0]
|
|
gw.wMarker drawPos #asterisk color:yellow
|
|
--gw.wMarker drawPos #circle color:white
|
|
--gw.wtext drawPos (chooseVert as string) color:yellow
|
|
)
|
|
)
|
|
)
|
|
),
|
|
|
|
fn hideTheseElements obj verts =
|
|
(
|
|
if isValidNode obj do
|
|
(
|
|
local faceSelectWas = polyop.getFaceSelection obj
|
|
obj.unhideAll #Face
|
|
|
|
for vertNum in verts where (isKindOf vertNum integer) do
|
|
(
|
|
local vertFaces = polyop.getFacesUsingVert obj vertNum
|
|
local elementFaces = polyop.getElementsUsingFace obj vertFaces
|
|
|
|
polyop.setFaceSelection obj elementFaces
|
|
obj.hide #Face
|
|
)
|
|
|
|
polyop.setFaceSelection obj faceSelectWas
|
|
)
|
|
)
|
|
)
|
|
|
|
global gRsSkinDataTransfer = RsSkinDataTransfer()
|