Files
gtav-src/tools_ng/wildwest/script/3dsMax/Characters/Rigging/runeBind/runeBind.ms
T
2025-09-29 00:52:08 +02:00

304 lines
8.7 KiB
Plaintext
Executable File

/**
script to try and mimic Rune Spaans TrollHunter rigging/binding tool
will epxlode a mesh into its constituent tris, then rigid bind these to
closest bone
**/
--Matt Rennie
--April 2014
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
clearListener()
filein "rockstar/export/settings.ms" -- This is fast
-- Figure out the project
theProjectRoot = RsConfigGetProjRootDir()
theProject = RSConfigGetProjectName()
theWildWest = RsConfigGetWildWestDir()
theProjectConfig = RsConfigGetProjBinConfigDir()
toolsRoot = RsConfigGetToolsRootDir()
-- filein (RsConfigGetWildWestDir() + "script\\max\\Rockstar_North\\character\\Includes\\FN_Rigging.ms")
filein (theWildWest + "script/3dsMax/_config_files/Wildwest_header.ms")
filein (theWildWest + "script/3dsMax/_common_functions/FN_RSTA_Rigging.ms")
filein (theWildWest + "script/3dsMax/_common_functions/FN_RSTA_UI.ms")
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
fn RSTA_runeBindMesh rootObj obj =
(
--first of we need to build the hierarchy
rootHierarchyArray = #()
rootHierarchyArray = RSTA_getAllChildren rootObj arr:rootHierarchyArray#()
--now we clone obj then explode it into tris
if classof obj == Editable_Poly then
(
disableSceneRedraw()
max create mode
local nnl = undefined
maxOps.cloneNodes obj cloneType:#copy newNodes:&nnl
select nnl
nnl[1].name = (obj.name+"_RuneBind")
local runeBindObj = nnl[1]
local totalFaces = polyop.getNumFaces runeBindObj
nnl = undefined
maxOps.cloneNodes obj cloneType:#copy newNodes:&nnl
select nnl
nnl[1].name = (obj.name+"_RuneBind2")
local runeBindObj2 = nnl[1]
local totalFaces2 = polyop.getNumFaces runeBindObj2
initProgBar()
for poly = totalFaces to 1 by -1 do
(
polyop.detachFaces runeBindObj poly delete:true asNode:false
progBar.prog.value = (100.*poly/totalFaces)
)
format ("Faces detatched.\n")
--ok we'll loop through again now and find the closest bone
local faceToBoneArray = #()
if totalFaces != totalFaces2 do
(
format "FaceCount mismatch\n"
break()
)
local centrePoint = point pos:[0,0,0] name:"centrePoint"
format ("Building detatched face data...\n")
for poly = totalFaces2 to 1 by -1 do
(
local startTime = timestamp()
local dist = 100000.0 --set to a ludicroudsly high number
local closestJoint = undefined
local thisName = undefined
format ("Building detached face data for face "+(poly as string)+"\n")
-- runeBindObj.EditablePoly.SetSelection #Face #{poly}
local newNode = undefined
local thisName = (runeBindObj2.name+"_"+(poly as string))
polyop.detachFaces runeBindObj2 poly delete:false asNode:true name:thisName node:#(newNode)
local thisFace = getNodeByName thisName
CenterPivot thisFace
--format (thisName+" generated.\n")
for joint in rootHierArchyArray do
(
--*** instead of jusing joint pivot we should use joint bbox centre
centrePoint.transform = joint.transform
local jointBBox = nodeGetBoundingBox joint joint.transform
local mp1 = ((jointBBox[1][1] + jointBBox[2][1]) / 2)
local mp2 = ((jointBBox[1][2] + jointBBox[2][2]) / 2)
local mp3 = ((jointBBox[1][3] + jointBBox[2][3]) / 2)
in coordsys joint centrePoint.position = [mp1,mp2,mp3]
local jointVsFaceDist = (distance centrePoint thisFace)
if jointVsFaceDist < dist do
(
dist = jointVsFaceDist
closestJoint = joint
)
)
-- format ("Setting face "+thisFace.name+" to use joint "+closestJoint.name+"\n")
delete thisFace
local thisData = #(
#(),
#()
)
append thisData[1] closestJoint
--now we will get the vert numbers of this poly
local faceVerts = polyop.getFaceVerts runeBindObj poly
for fv in faceverts do
(
append thisData[2] fv
)
--format ((thisData as string)+"\n")
append faceToBoneArray thisData
--format (thisName+" data parsed.\n")
local endTime = timestamp()
local timeTaken = ((endTime - startTime) / 1000.0)
if timeTaken > 0.21 do
(
gc()
)
format ("Processing this face took "+(timeTaken as string)+" seconds\n")
progBar.prog.value = (100.*poly/totalFaces)
)
format ("Face detach data created.\n")
-- enableSceneRedraw()
delete runeBindObj2
delete centrePoint
format ("Starting skinning...\n")
local Faces = polyop.getNumFaces runeBindObj
--format ("Skin mesh has "+(faces as string)+" total faces...\n")
--now we have got a mapping of faces to joints we can skin it all up
max modify mode
select runeBindObj
modPanel.addModToSelection (Skin ()) ui:on
-- addModifier runeBindObj (Skin())
local skinMod = runeBindObj.modifiers[#Skin]
skinMod.bone_Limit = 4
skinMod.showNoEnvelopes = on
for wbone = 1 to rootHierarchyArray.count do
(
--print wbone
try (skinOps.addBone skinMod rootHierarchyArray[wbone] 1) catch ()
)
local vertCount = polyop.getNumVerts runeBindObj
--format ("Skin mesh has "+(vertCount as string)+" total verts...\n")
--first off we'll blanket weight every vert to the base bone in the skin mod
for v = 1 to vertCount do
(
skinOps.SetVertexWeights skinMod v 1 1.0
)
for g = 1 to faceToBoneArray.count do
(
local fb = faceToBoneArray[g]
--format ("fb: "+fb as string+"\n")
local joint = fb[1][1]
--format ("Skinning "+(joint.name+"\n"))
local verts = fb[2]
local fbNo = findItem rootHierarchyArray joint
for vertNo in verts do
(
--format ("Attempting to skin joint "+joint.name+" to vert "+(vertNo as string)+"\n")
skinOps.SetVertexWeights skinMod vertNo fbNo 1.0
)
-- for fbNo = 1 to rootHierarchyArray.count do
-- (
-- thisJoint = skinOps.GetBoneName skinMod fbNo 1
--
-- if thisJOint == joint.name do
-- (
-- --ok now we have found this bone we need to set all the verst to be weighted 100% to it
--
-- for vertNo in verts do
-- (
-- --format ("Attempting to skin joint "+joint.name+" to vert "+(vertNo as string)+"\n")
-- skinOps.SetVertexWeights skinMod vertNo fbNo 1.0
-- )
-- )
-- )
progBar.prog.value = (100.*g/faceToBoneArray.count)
--format (joint.name+" skinned. \n")
)
format ("Skinning rough mesh.\n Beginning skinwrap to "+obj.name+"\n")
max create mode
destroyDialog progBar
--now we'll skinwrap the original to this runeBind
select obj
addModifier obj (Skin_Wrap ())
local wrapMod = obj.modifiers[#Skin_Wrap]
format ("Beginning skinWrap - this can take a while!\n")
wrapMod.meshList = #(runeBindObj)
wrapMod.falloff = 1
wrapMod.engine = 0 --face deformation
wrapMod.threshold = 0.001
wrapMod.weightAllVerts = on
wrapMod.ConvertToSkin true
if obj.modifiers[#Skin] != undefined do
(
format "Applying some default skin values\n"
--toggle always deform off and on
obj.modifiers[#Skin].always_deform = false
obj.modifiers[#Skin].always_deform = true
obj.modifiers[#Skin].cross_radius = 0.0834036
obj.modifiers[#Skin].mirrorEnabled = off
obj.modifiers[#Skin].bone_Limit = 4
obj.modifiers[#Skin].clearZeroLimit = 0.0
skinOps.RemoveZeroWeights obj.modifiers[#Skin]
obj.modifiers[#Skin].Filter_Vertices = on
obj.modifiers[#Skin].shadeweights = on
obj.modifiers[#Skin].showNoEnvelopes = on
)
-- delete runeBindObj
enableSceneRedraw()
format ("runeBinding complete.\n")
)
else
(
format ("Please operate on Editable_Poly objects.\n")
)
)
obj = $
rootObj = getNodeByName "Dummy01"
if selection.count == 1 then
(
RSTA_runeBindMesh rootObj obj
)
else
(
messagebox ("Please run with only one mesh selected.\n")
)