Files
2025-09-29 00:52:08 +02:00

684 lines
20 KiB
Plaintext
Executable File

--mrFakeSSDSkinning
/**
you basically move each joint (also excluding movement of its children joints) to calculate how much this affects a vertex. You do that for each joint and vertex combination and apply the weighted normalized value over all joints?
E.g.
- joint1 moves vert1 by 2 units
- joint2 moves vert1 by 1 unit
Total movement is 3 units
- joint1 weight is 2/3
- joint2 weight is 1/3
*/
filein (RsConfigGetWildWestDir() + "script/3dsMax/_common_functions/FN_RSTA_Rigging.ms")
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
fn RSTA_inputDeltaSkinData geo envFile bonFile noOfInfluences =
(
/**
FUNTION TO LOAD BONE AND ENVELOPE FILES FOR SKINNED MESHES
**/
--now add a new skin modifier
addModifier geo (Skin ())
local skinMod = geo.modifiers[#Skin]
format ("Skin modifier added to "+geo.name+"\n")
skinMod.bone_Limit = noOfInfluences
skinMod.showNoEnvelopes = on
RSTA_inputBonesData geo bonFile
format ("Bones added to "+geo.name+"\n")
fn RSTA_EnvelopeCallbackFunction =
(
/**
THIS AUTO PRESSES THE LOAD BUTTONS ON THE SKIN ENVELOPE LOADING DIALOG
**/
WindowHandle = DialogMonitorOPS.GetWindowHandle()
theDialogName = UIAccessor.GetWindowText WindowHandle
if theDialogName != undefined and matchpattern theDialogName pattern:"*Load Envelopes*" do
UIAccessor.PressButtonByName WindowHandle "Match by Name"
if theDialogName != undefined and matchpattern theDialogName pattern:"*Load Envelopes*" do
UIAccessor.PressButtonByName WindowHandle "OK"
true
)
max modify mode
modPanel.setCurrentObject $.modifiers[#Skin]
DialogMonitorOPS.RegisterNotification RSTA_EnvelopeCallbackFunction ID:#ANoon_Envelopes
DialogMonitorOPS.Enabled = true
completeRedraw()
skinOps.loadEnvelope geo.modifiers[#Skin] envFile
completeRedraw()
DialogMonitorOPS.Enabled = false
DialogMonitorOPS.UnRegisterNotification ID:#ANoon_Envelopes
format ("Loaded Skin: "+envFile+" onto "+geo.name+"\n")
)
fn rsta_ApplyDeltaSkinning geo skinDataArray =
(
select geo
max modify mode
modPanel.setCurrentObject geo.modifiers[#Skin]
skinMod = geo.modifiers[#Skin]
fn rsta_reNormalize 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 rsta_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
)
--first we'll rsta_deNormalize all the weights
local meshVertCount = polyop.getNumVerts deltaMesh
for vertexID = 1 to meshvertCount do
(
rsta_deNormalize vertexID skinMod
)
for skinData in skinDataArray do
(
for sd = 1 to skinData.count do
(
vertId = skinData[sd][1]
boneId = skinData[sd][2]
weight = skinData[sd][3]
skinOps.SetVertexWeights skinMod vertId boneId weight
)
)
for vertexID = 1 to meshvertCount do
(
rsta_reNormalize vertexID skinMod
)
format ("Ssd skinning applied.\n")
)
fn rsta_calculateVertDifferences restVertArray poseVertArray jointToUse =
(
local vertDiffArray = #()
-- local jointToUseParent = jointToUse.parent
--
-- if jointToUseParent == undefined do
-- (
-- jointToUseParent = (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,0])
-- )
-- for r = 1 to restVertArray.count do
append vertDiffArray jointToUse.name
-- jointParent = jointToUse.parent
for r = 2 to restVertArray.count do
(
local rest = restVertArray[r]
local pose = poseVertArray[r]
local vertVector = (in coordsys jointToUse rest) - (in coordsys jointToUse pose)
-- local vertVector = (in coordsys jointParent rest) - (in coordsys jointParent pose)
-- local vertVector = (in coordsys jointToUseParent rest) - (in coordsys jointToUseParent pose)
local vertDiff = length vertVector
if abs(vertDiff) * 10 < 0.001 do
(
vertDiff = 0 as integer
)
append vertDiffArray vertDiff
)
return vertDiffArray
)
fn rsta_calculateVertPositions deltaMesh frame jointToUse =
-- fn rsta_calculateVertPositions deltaMesh frame =
(
local vertSpaceArray = #()
sliderTime = frame as time
if classof deltaMesh.modifiers[1] != Edit_Poly do
(
addModifier deltaMesh (Edit_Poly())
deltaMesh.modifiers[1].name = "DeltaMush_Edit_Poly"
)
local meshVertCount = polyop.getNumVerts deltaMesh
local vertPosPoint = getNodeByName "vertPosPoint"
if vertPosPoint == undefined do
(
vertPosPoint = point name:"vertPosPoint"
)
-- append vertSpaceArray (jointToUse.name)
append vertSpaceArray (jointToUse.name)
for vertNo = 1 to meshVertCount do
(
local vert = polyop.getVert deltaMesh vertNo --node:space
-- vertNode = point name:("frame"+(frame as string)+"_vert"+(vertNo as string)+"_Point") pos:vert size:0.05
vertPosPoint.position = vert
local vertPosA = vertPosPoint.position
append vertSpaceArray vertPosA
)
return vertSpaceArray
)
fn rsta_deltaMesh_PrepareTimeLine deltaMesh deltaSkinName =
(
--first build an array of all the joints in the deltaMesh skin modifier
local skinnedBones = #()
for s = 1 to deltaMesh.modifiers.count do
(
skinMod = deltaMesh.modifiers[s]
if classof skinMod == Skin do
(
select deltaMesh
max modify mode
modPanel.setCurrentObject deltaMesh.modifiers[s]
local totalSkinModBones = skinOps.getNumberBones skinMod
for b = 1 to totalSkinModBones do
(
thebonename = skinOps.getBoneName skinMod b 1
realBone = getnodebyname theBoneName
append skinnedBones realBone
)
--now we need to ensure the bones are all key less. Then once we are we will rom them
animationRange = interval 0f (60000 as time) --set timeline to somethign stupidly big as a temp measure
sliderTime = 0f
removeAllKeys skinnedBones
--now we need to save a bPos file so we can restore this pose at the end.
local boneFileName = ("c:/"+deltaSkinName+".bon")
local skinFileName = ("c:/"+deltaSkinName+".env")
RSTA_outputSkinBoneData deltaMesh boneFileName
skinOps.saveEnvelope skinMod skinFileName
--now we need to create a rom for all of the objects in skinnedBones
local bindPoses = #()
local totalKeys = 0
local maxtime = 0f
local rotAmount = 50
with redraw off ( --try to turn redraw off to speed shit up
for thisBone in skinnedBones do
(
local thisTran = in coordsys parent thisBone.transform
append bindPoses thisTran
)
for b = 1 to skinnedBones.count do
(
slidertime = 0f
thisBone = skinnedBones[b]
with animate on (in coordsys parent thisBone.transform = bindPoses[b])
--now ensure there is a key every frame we're gonna need
for f = 1 to (skinnedBones.count) do
(
slidertime = (f as time)
with animate on (in coordsys parent thisBone.transform = bindPoses[b])
-- totalKeys = totalKeys + 1
-- if slidertime > maxtime do
-- (
-- maxtime = slidertime
-- )
)
slidertime = 0f --need to set this back to 0
)
maxtime = (skinnedBones.count as time)
format ("total of "+(skinnedBones.count as string)+" bones\n")
format ("All bones keyed."+"\n")
animationRange = interval 0f (maxtime as time)
-- local keyPoseArray = #() --for each index in here we have the joint that is moving at that point
for b = 1 to skinnedBones.count do
(
local thisBone = skinnedBones[b]
sliderTime = sliderTime + 1f
if toLower(thisBone.name) != "dummy01" then
(
if toLower(thisBone.name) != "mover" then
(
with animate on (thisBone.Rotation.Z_rotation = thisBone.Rotation.Z_rotation + rotAmount)
)
)
-- append keyPoseArray thisBone.name
)
sliderTime = 0f
)
)
)
format ("Timeline prepared...\n")
return skinnedBones
)
fn rsta_fakeSsdSkin deltaMesh deltaSkinName noOfInfluences =
(
local start = timeStamp()
local skinnedBones = rsta_deltaMesh_PrepareTimeLine deltaMesh deltaSkinName
--now we have prepared all the frames we need to build the vert arrays
--first we need to build data for each bone in the bind pose
-- local allVertRestArray = #()
local vertPositionsArray = #()
-- local skinDataArray = #()
with redraw off (
-- frame = 0
--
-- local jointToUse = skinnedBones[1]
-- local vertRestArray = rsta_calculateVertPositions deltaMesh frame jointToUse
-- append allVertRestArray vertRestArray
--now we have the rest positions, we now calculate the positions for the new poses
local lastFrame = (animationRange.end as string)
local lastFrameCount = lastFrame.count
lastFrame = ((substring lastFrame 1 (lastFrameCOunt - 1)) as integer)
for frame = 0 to lastFrame do
(
local jointToUse = undefined
if frame == 0 then
(
restPoseNode = point name:"restPose"
jointToUse = restPoseNode
)
else
(
jointToUse = skinnedBones[frame]
)
thisFrameArray = rsta_calculateVertPositions deltaMesh frame jointToUse
append vertPositionsArray thisFrameArray
restPoseNode = getNodeByName "restPose"
if restPoseNode != undefined do
(
delete restPoseNode
)
)
local vertPosPoint = getNodeByName "vertPosPoint"
if vertPosPoint != undefined do
(
delete vertPosPoint
)
slidertime = 0f
format "---------------------------------------------------------\n"
format "vertPositionsArray:\n"
for v = 1 to vertPositionsArray.count do
(
format (((v - 1) as string)+" "+(vertPositionsArray[v] as string)+"\n")
)
format "---------------------------------------------------------\n"
local skinDataArray = #()
local restPoseArray = vertPositionsArray[1]
for index = 2 to vertPositionsArray.count do
(
local vertNo = (index - 1)
local poseArray = vertPositionsArray[index]
local jointToUse = undefined
if frame == 0 then
(
restPoseNode = point name:"restPose"
jointToUse = restPoseNode
)
else
(
jointToUse = skinnedBones[index]
)
local diffArray = rsta_calculateVertDifferences restPoseArray poseArray jointToUse
local vertDiff = diffArray[vertNo + 1]
local dataToAppend = #(vertNo,jointToUse)
if vertDiff != 0 do
(
-- format ("Pose "+(pose as string)+" "+(skinnedBones[pose].name as string)+", vert "+(vertNo as string)+", rest:"+(restVertArray[vertNo] as string)+" pose:"+(poseVertArray[vertNo] as string)+" diff:"+(diffArray[vertNo] as string)+"\n")
append dataToAppend vertDiff
append skinDataArray dataToAppend
)
)
format "\n---------------------------------------------------------\n"
format "skinDataArray:\n"
for v = 1 to skinDataArray.count do
(
format (((v - 1) as string)+" "+(skinDataArray[v] as string)+"\n")
)
format "---------------------------------------------------------\n"
)
)
fn old_rsta_fakeSsdSkin deltaMesh deltaSkinName noOfInfluences =
(
local start = timeStamp()
local skinnedBones = rsta_deltaMesh_PrepareTimeLine deltaMesh deltaSkinName
--now we have prepared all the frames we need to build the vert arrays
--first we need to build data for each bone in the bind pose
local allVertRestArray = #()
local vertPositionsArray = #()
local skinDataArray = #()
with redraw off (
-- for thisBone in skinnedBones do
-- (
frame = 0
local jointToUse = skinnedBones[1]
local vertRestArray = rsta_calculateVertPositions deltaMesh frame jointToUse
append allVertRestArray vertRestArray
-- )
--now we have the rest positions, we now calculate the positions for the new poses
local lastFrame = (animationRange.end as string)
local lastFrameCount = lastFrame.count
lastFrame = ((substring lastFrame 1 (lastFrameCOunt - 1)) as integer)
for frame = 1 to lastFrame do
(
local jointToUse = skinnedBones[frame]
thisFrameArray = rsta_calculateVertPositions deltaMesh frame jointToUse
append vertPositionsArray thisFrameArray
)
slidertime = 0f
--now we have the data we now need to calculate the differences
local meshVertCount = polyop.getNumVerts deltaMesh
createDialog progBar width:300 height:30
format ((vertPositionsArray.count as string)+" total poses\n")
format "---------------------------------------------------------\n"
format "allvertRestArray:\n"
for v = 1 to allVertRestArray.count do
(
format ((v as string)+" rest: "+(allVertRestArray[1] as string)+"\n")
format ((v as string)+" pose: "+(vertPositionsArray[v] as string)+"\n")
)
format "---------------------------------------------------------\n"
break()
-- break()
-- for vertNo = 1 to meshVertCount do
-- (
for pose = 1 to vertPositionsArray.count do
-- for pose = 13 to 17 do
(
--should probably do something here based off noOfInfluences
/*
--big issue i have is figuring out this movement based off the chain of the hierarchy
we essentially need to find the childmost bone and see if that vert has moved relative to its parent
if it hasnt moved relative to its parent then we can ignore any other motions
***SURELY IF I JUST GET DISTANCES RELATIVE TO PARENT?????
**MAYBE GO UP THE HIERARCHY FROM THIS JOINT IF IT HAS MOVED UNTIL WE FIND ONE WHERE IT HASNT.
*/
-- for pose = 1 to vertPositionsArray.count do
-- (
for vertNo = 1 to meshVertCount do
(
--format ("testing pose "+(pose as string)+"\n")
-- local restVertArray = allVertRestArray[pose]
local restVertArray = allVertRestArray[1]
local relNodeRest = allVertRestArray[pose][1]
local poseVertArray = vertPositionsArray[pose]
local poseNodeRest = vertPositionsArray[pose][1]
local jointToUse = skinnedBones[pose]
if relNodeRest == poseNodeRest then
(
local diffArray = rsta_calculateVertDifferences restVertArray poseVertArray jointToUse
-- if diffArray != 0 then
local vertDiff = diffArray[vertNo + 1]
if vertDiff > 0 then
(
local parentNode = jointToUse.parent
if parentNode != undefined do
(
-- if parentNode == undefined do --this will essentially make a node at zero for none parented objects
-- (
-- parentNode = getNodeByName "ParentNode_Dummy"
--
-- if parentNode == undefined do
-- (
-- parentNode = point name:"ParentNode_Dummy" pos:[0,0,0]
-- )
-- )
local parentIndex = findItem skinnedBones parentNode
local parentRestVertArray = allVertRestArray[parentIndex]
local parentPoseVertArray = vertPositionsArray[parentIndex]
local parentDiffArray = rsta_calculateVertDifferences parentRestVertArray parentPoseVertArray parentNode
-- format ("parentDiffArray:"+(parentDiffArray as string)+"\n")
if parentDiffArray[vertNo+ 1] == 0 do
(
format ("diffArray: "+(diffArray as string)+"\n")
--format (parentNode.name+" parentDiffArray["+(vertNo as string)+"]:"+(parentDiffArray[vertNo] as string)+"\n")
local dataToAppend = #(vertNo,pose)
if vertDiff != 0 do
(
format ("Pose "+(pose as string)+" "+(skinnedBones[pose].name as string)+", vert "+(vertNo as string)+", rest:"+(restVertArray[vertNo] as string)+" pose:"+(poseVertArray[vertNo] as string)+" diff:"+(diffArray[vertNo] as string)+"\n")
append dataToAppend vertDiff
append skinDataArray dataToAppend
)
)
-- else
-- (
-- format ("SKIPPING AS "+parentNode.name+" parentDiffArray["+(vertNo as string)+"]:"+(parentDiffArray[vertNo] as string)+"\n")
-- )
)
)
)
else
(
format (relNodeRest+" != "+poseNodeRest+"\n")
)
progBar.prog.value = (100.*vertNo/meshVertCount)
)
-- progBar.prog.value = (100.*vertNo/meshVertCount)
)
format ("skinDataArray.count:"+(skinDataArray.count as string)+"\n")
destroyDialog progbar
-- local totalSkinData = #()
-- for vertNo = 1 to meshvertCount do
-- (
-- local meshSkinData = #()
-- for data = 1 to skinDataArray.count do
-- (
-- if skinDataArray[data][1] == vertNo do
-- (
-- append meshSkinData skinDataArray[data]
-- )
-- )
-- append totalSkinData meshSkinData
-- )
--
-- createDialog progBar width:300 height:30
--
-- local wcStart = timestamp()
-- for i = 1 to totalSkinData.count do
-- (
-- --convert the distances moved into weights
--
-- thisData = totalSkinData[i]
--
-- newTotal = 0
-- for dat = 1 to thisData.count do
-- (
-- newTotal = newTotal + thisData[dat][3]
-- )
--
-- for dat = 1 to thisData.count do
-- (
-- local jointWeight = thisData[dat][3] / newTotal
--
-- if jointWeight * 10 < 0.001 then
-- (
-- jointWeight = 0
-- )
-- --format ("Replacing [3] in "+(thisData[dat] as string)+" with "+(jointWeight as string)+"\n")
--
-- thisData[dat][3] = jointWeight
--
-- )
--
-- iVal = i
-- progBar.prog.value = (100.*i/totalSkinData.count)
-- )
--
-- local wcEnd = timestamp()
-- format ("Processing weightConversion took "+(((wcEnd - wcStart) / 1000.0) as string)+"seconds\n")
-- destroyDialog progbar
--
-- --so now we need to duplicate the bindMesh and then load the skinning via the bon and env file we saved earlier
-- --then loop through the totalSkinData array and set the weights.
--
-- format ("Applying skinning\n")
-- maxOps.cloneNodes deltaMesh cloneType:#copy actualNodeList:&c newNodes:&nnl
-- deltaSkin = nnl[1]
-- deltaSkin.name = deltaSkinName
-- slidertime = 0f
-- modCOunt = deltaSkin.modifiers.count
--
-- for m = modCOunt to 1 by -1 do
-- (
-- deletemodifier deltaSkin m
-- )
--
-- --now we reload the skinning
--
-- local bonFile = ("c:/"+deltaSkinName+".bon")
-- local envFile = ("c:/"+deltaSkinName+".env")
--
-- RSTA_inputDeltaSkinData deltaSkin envFile bonFile noOfInfluences
--
-- --now we need to use the data in totalSkinData array to weight the verts
--
-- format ("Attempting rsta_ApplyDeltaSkinning on "+deltaSkin.name+"...\n")
-- rsta_ApplyDeltaSkinning deltaSkin totalSkinData
)
local vertPosPoint = getNodeByName "vertPosPoint"
if vertPosPoint != undefined do
(
delete vertPosPoint
)
local end = timeStamp()
format ("Processing rsta_fakeSsdSkin took "+(((end - start) / 1000.0) as string)+"seconds\n")
messagebox "Done!" beep:true
)
deltaMesh = $bindMesh_bindAnim --this is the mesh with the delta mush on as we want to track how it is deforming
noOfInfluences = 4
rsta_fakeSsdSkin deltaMesh (deltaMesh.name+"_DeltaSkinMesh") noOfInfluences
-- space = $SKEL_L_Calf
-- deltaMesh = $BindMesh_Anim
-- frame = 0
-- rsta_calculateVertPositions space deltaMesh frame