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

1062 lines
33 KiB
Plaintext
Executable File

try (destroyDialog RSpedDmgMapperRoll) catch ()
callbacks.removeScripts id:#RSdmgHelperMat
--gc()
--resumeediting()
--popprompt()
rollout RSpedDmgMapperRoll "Ped Damage-Mapper [v1.18:Stiff Engine]" width:320 --height:188
(
dotNetControl RsBannerPanel "Panel" pos:[0,0] height:32 width:RSpedDmgMapperRoll.width
local bannerStruct = makeRsBanner dn_Panel:RsBannerPanel wiki:"PedDamageMapper" versionNum:1.18 versionName:"Stiff Engine" filename:(getThisScriptFilename())
-- UV-channel used for damage:
local damChan = 2
-- Data for setting up different damage-zones on body:
struct sectionStruct
(
num, Name, Enabled = True, Colour, VOffset = 0.0, CylRot = 0.0, CylHeight = 1.0, FlipSection = False, BoneNames = #(),
WorkingBoneNames = #(), Verts = #{}, GeomFaces = #{}, MapFaces = #{}, RootPos = [0,0,0], MapDir = [0,0,0]
)
local sectionsList =
#(
sectionStruct name:"Torso" enabled:True colour:red vOffset:0.8 cylRot:95 CylHeight:0.9 \
boneNames:#("SKEL_Spine0", "SKEL_Pelvis", "CTRLRIG_Tail_03_NUB", "SKEL_Spine*", "SKEL_?_Clavicle", "*_Suit_*", "SM_?_Pouches*", "SM_LifeSaver*", "SKEL_Tail*", "SPR_Gonads", "SM_CollarStraps*", "CTRLRIG_Spine*", "CTRLRIG_Spine1", "SKEL_Neck_1"),
sectionStruct name:"Head" enabled:True colour:green VOffset:2.55 CylRot:180 CylHeight:0.37 \
boneNames:#("SKEL_Neck_1", "CTRLRIG_Head", "RB_Neck_*", "FB_*", "FACIAL_*", "SPR_?_Ear", "SKEL_Head_NUB", "CTRLRIG_Head_NUB", "SKEL_Head"),
sectionStruct name:"LArm" enabled:True colour:yellow vOffset:5.31 cylRot:-85 CylHeight:0.9 flipSection:True \
boneNames:#("SKEL_L_UpperArm", "SKEL_L_Clavicle", "RB_L_*ArmRoll", "MH_L_Elbow", "SKEL_L_ForeArm", "SKEL_L_Finger*", "*_L_Hand", "SM_L_Cuff", "CTRLRIG_L_Clavicle_NUB", "SKEL_L_Finger00_NUB", "SKEL_L_Finger2_NUB"),
sectionStruct name:"RArm" enabled:True colour:blue vOffset:7.31 cylRot:85 CylHeight:0.9 flipSection:True \
boneNames:#("SKEL_R_UpperArm", "SKEL_R_Clavicle", "RB_R_*ArmRoll", "MH_R_Elbow", "SKEL_R_ForeArm", "SKEL_R_Finger*", "*_R_Hand", "SM_L_Cuff", "CTRLRIG_R_Clavicle_NUB", "SKEL_R_Finger00_NUB", "SKEL_R_Finger2_NUB"),
sectionStruct name:"LLeg" enabled:True colour:(red + blue) vOffset:9.45 cylRot:-75 flipSection:True \
boneNames:#("SKEL_L_Thigh", "SM_L_Flipper*", "*_L_Bum*", "MH_L_Knee", "*_L_Calf*", "*_L_Thigh*", "L_PantHem*", "RB_L_ThighRoll", "SKEL_R_Thigh_NUB", "SKEL_L_Calf", "SKEL_L_Toe0", "SKEL_L_Toe0_NUB", "SKEL_L_Foot"),
sectionStruct name:"RLeg" enabled:True colour:(green + blue) vOffset:11.45 cylRot:75 flipSection:True \
boneNames:#("SKEL_R_Thigh", "SM_R_Flipper*", "*_R_Bum*", "MH_R_Knee", "*_R_Calf*", "*_R_Thigh*", "R_PantHem*", "RB_R_ThighRoll", "SKEL_R_Thigh_NUB", "SKEL_R_Calf", "SKEL_R_Toe0", "SKEL_R_Toe0_NUB", "SKEL_R_Foot")
)
-- Faces assigned to these bones will be exluded from Damage Mapping:
local excludeBoneNames = #("*_Eye_*", "*Eyeball*")
-- Only down-facing faces for these bones will be excluded:
local underExcludeBoneNames = #("*Foot*", "*Toe*")
group "Show debug texture:"
(
checkbutton showHelperGridMatBtn "Helper-grid" width:140 checked:False offset:[0,-3] across:2
tooltip:"Show selected objects with material showing the mapping on UV-channel 2, with damage-segment zone outlined on the texture"
checkbutton showHelperAreaMatBtn "Limb-colours" width:140 checked:True offset:[0,-3]
tooltip:"Show selected objects with material showing the mapping on UV-channel 2, showing limb-mapping colours"
)
button btnDmgMapper "Apply Damage Mapping" width:200 height:30 offset:[1,1]
tooltip:"Apply damage-mapping modifiers to selected skinned objects, generating mapping-cylinders from bone objects"
checkButton btnMapAllLimbs "Allow modifiers for full body" width:200 height:16 offset:[1,-4]
tooltip:"By default, \"Apply\" doesn't add modifiers for parts that don't appear to be used by a mesh.\n\nOverriding this behaviour will slow down the Apply process."
button btnAddExclusion "Add Damage-Exclude Modifiers" width:200 offset:[1,0]
tooltip:"Add modifiers to exclude selected faces from damage-mapping"
button btnCollapseToSkin "Collapse to Skin" width:200 offset:[0,0]
tooltip:"Collapse selected objects' modifiers below their Skin modifiers"
progressBar progressCtrl
-- Generate handy helper-texture materials, for showing how the damage-map has been set up:
fn genDmgGridHelperMat =
(
-- Adds a handy helper-texture material to material-editor slot 7, set up to show how the damage-map has been set up --
local texMap = bitmaptexture filename:( ::RsConfigGetWildwestDir() + "script/3dsmax/characters/materials/damage_helperA.bmp" )
texMap.coords.mapChannel = 2
texMap.coords.U_Offset = texMap.coords.V_Offset = -0.5
texMap.coords.U_Tiling = texMap.coords.V_Tiling = 0.5
local dmgmat = standardmaterial name:"DamageHelperGridMat" diffusemap:texMap showInViewport:true
dmgmat
)
fn genDmgAreaHelperMat =
(
local colourCount = sectionsList.count
local texMap = bitmaptexture filename:( ::RsConfigGetWildwestDir() + "script/3dsmax/characters/materials/damage_helperB.bmp" )
texMap.coords.mapChannel = 2
texMap.coords.U_Offset = (1.0)
texMap.coords.U_Tiling = (0.5)
texMap.coords.V_Offset = (colourCount)
texMap.coords.V_Tiling = (0.5 / colourCount)
local dmgmat = standardmaterial name:"DamageHelperAreaMat" diffusemap:texMap showInViewport:true
dmgmat
)
local dmgGridHelperMat = genDmgGridHelperMat()
local dmgAreaHelperMat = genDmgAreaHelperMat()
local matObjs = #()
local origMats = #()
fn changeObjMatting newObjs =
(
-- Set to Object subobject-level, as Face mode will mess up materials on apply:
if (subobjectLevel != 0) do
(
subobjectLevel = 0
)
local newMatObjs = #()
local newOrigMats = #()
local reusedObjs = #{}
reusedObjs.count = matObjs.count
-- Build new holding-lists for object-materials:
local findNum
for obj in newObjs do
(
append newMatObjs obj
findNum = findItem matObjs obj
if (findNum == 0) then
(
append newOrigMats obj.material
)
else
(
append newOrigMats origMats[findNum]
reusedObjs[findNum] = true
)
)
-- Restore materials for objects that aren't in newObjs:
for n = -reusedObjs do
(
matObjs[n].material = origMats[n]
)
matObjs = newMatObjs
origMats = newOrigMats
-- Set objects to use helper-material:
matObjs.material = if showHelperAreaMatBtn.checked then dmgAreaHelperMat else dmgGridHelperMat
)
fn setSelHelperMats =
(
changeObjMatting (getCurrentSelection())
)
fn startShowHelperMats =
(
setSelHelperMats()
-- Update whenever the selection changes:
callbacks.addScript #selectionSetChanged ("RSpedDmgMapperRoll.setSelHelperMats()") id:#RSdmgHelperMat
-- Clear temp materials before saving:
callbacks.addScript #filePreSaveProcess ("RSpedDmgMapperRoll.changeObjMatting #()") id:#RSdmgHelperMat
callbacks.addScript #filePostSaveProcess ("RSpedDmgMapperRoll.setSelHelperMats()") id:#RSdmgHelperMat
)
fn clearHelperMats deactivate:True =
(
callbacks.removeScripts id:#RSdmgHelperMat
changeObjMatting #()
if deactivate do
(
showHelperGridMatBtn.checked = false
showHelperAreaMatBtn.checked = false
)
)
on showHelperGridMatBtn changed activated do
(
if showHelperAreaMatBtn.checked do
(
showHelperAreaMatBtn.checked = False
clearHelperMats()
showHelperGridMatBtn.checked = activated
)
if activated then
(
startShowHelperMats()
)
else
(
clearHelperMats()
)
)
on showHelperAreaMatBtn changed activated do
(
if showHelperGridMatBtn.checked do
(
showHelperGridMatBtn.checked = False
clearHelperMats()
showHelperAreaMatBtn.checked = activated
)
if activated then
(
startShowHelperMats()
)
else
(
clearHelperMats()
)
)
on RSpedDmgMapperRoll open do
(
-- Initialise tech-art banner:
bannerStruct.setup()
if (showHelperGridMatBtn.checked or showHelperAreaMatBtn.checked) do startShowHelperMats()
)
on RSpedDmgMapperRoll close do
(
clearHelperMats()
)
-- Get index for object's Skin modifier, if it has one:
fn getSkinIdx obj =
(
local retVal = 0
for n = 1 to obj.modifiers.count while (retVal == 0) do
(
if (isKindOf obj.modifiers[n] Skin) do
(
retVal = n
)
)
return retVal
)
-- Sets modifier-stack to show under a given modifier:
fn showUnderMod obj thisMod =
(
if (getCommandPanelTaskMode() != #modify) do (setCommandPanelTaskMode #modify)
-- Get modifier below thisMod (or the object-node, if none)
local thisModIdx = modPanel.getModifierIndex obj thisMod
local underModIdx = (thisModIdx + 1)
local underMod = if (underModIdx > obj.modifiers.count) then obj else obj.modifiers[underModIdx]
if (modPanel.getCurrentObject() != underMod) do
(
modPanel.setCurrentObject underMod
)
modPanel.setCurrentObject underMod
if (subobjectlevel != 0) do (subobjectlevel = 0)
return underMod
)
-- Gets Dmg "Edit Normals" modifier and selection-clearer modifier (or adds it below Skin and all current Dmg modifiers, if it doesn't already exist)
-- These modifiers stops normals and selection from being messed up by other modifiers
-- Returns the modifier/baseObject from below selection-clearer.
fn showUnderSkin obj =
(
local keepNormsName = "Dmg.KeepNormals"
local safeModName = "Dmg.Sel.Clear"
local skinIdx = (getSkinIdx obj)
local skinMod = if (skinIdx == 0) then undefined else obj.modifiers[skinIdx]
local normMod = undefined
local safeMod = undefined
local lastDmgMod = undefined
-- Find existing safety-modifiers:
for modIdx = (skinIdx + 1) to obj.modifiers.count while (normMod == undefined) or (safeMod == undefined) do
(
local thisMod = obj.modifiers[modIdx]
case of
(
((normMod == undefined) and (matchPattern thisMod.name pattern:keepNormsName)):
(
normMod = thisMod
)
((safeMod == undefined) and (matchPattern thisMod.name pattern:safeModName)):
(
safeMod = thisMod
)
(matchPattern thisMod.name pattern:"Dmg.*"):
(
lastDmgMod = thisMod
)
)
)
if (getCommandPanelTaskMode() != #modify) do (setCommandPanelTaskMode #modify)
-- Deal with various modifier-combinations:
case of
(
-- If we have no "Dmg.KeepNormals", add it and a selection-clearer (a new one, if one already exists...)
(normMod == undefined):
(
case of
(
-- Add under the last Dmg modifier, if found:
(lastDmgMod != undefined):(showUnderMod obj lastDmgMod)
-- Otherwise, add under Skin, if found: (no reason why that should be though?)
(skinMod != undefined):(showUnderMod obj skinMod)
-- No modifiers?
(obj.modifiers.count == 0):(modPanel.setCurrentObject obj)
-- Go to top of any other modifiers:
Default:(modPanel.setCurrentObject obj.modifiers[1])
)
-- Add "Edit Normals" modifier first, to ensure that normals are retained:
local normMod = (Edit_Normals name:(keepNormsName) Display_Length:0.01)
modPanel.addModToSelection normMod
-- Add selection-clearer modifier below the Edit Normals
showUnderMod obj normMod
local safeMod = (Poly_Select name:(safeModName))
modPanel.addModToSelection safeMod
)
-- If we have "Dmg.KeepNormals", but not "Dmg.Sel.Clear", add selection-modifier below normals-modifier
(safeMod == undefined):
(
showUnderMod obj normMod
safeMod = (Poly_Select name:(safeModName))
modPanel.addModToSelection safeMod
)
)
-- Set stack to below selection-clearer modifier:
showUnderMod obj safeMod
return #(normMod, safeMod)
)
fn findNamedMods obj namePattern:"Dmg.*" =
(
local findMods = #()
for thisMod in obj.modifiers do
(
-- Remove whitespace from name...
local trimmedName = trimleft thisMod.name
if (matchPattern trimmedName pattern:namePattern) do
(
append findMods thisMod
)
)
return findMods
)
fn deleteTheseMods obj delMods keepMods:#() =
(
local objMods = obj.modifiers
delMods = for thisMod in delMods where (findItem objMods thisMod != 0) and (findItem keepMods thisMod == 0) collect thisMod
if (delMods.count != 0) do
(
pushPrompt ("Removing old modifiers from: " + obj.name)
suspendEditing()
for thisMod in delMods do
(
deleteModifier obj thisMod
)
resumeEditing()
popPrompt()
delMods.count = 0
)
)
-- Find User-Excluded faces, mapped to [0,0,0]:
fn getUserExcludedFaces obj testPolyMod: deleteMods:#() =
(
local userExcludeFaces = #{}
-- Was a test-modifier supplied?
local addTestMod = (testPolyMod == unsupplied)
if addTestMod do
(
testPolyMod = Edit_Poly name:"Dmg.Poly.Testing..."
modPanel.addModToSelection testPolyMod
)
pushPrompt "Finding excluded faces..."
local faceCount = (testPolyMod.GetNumFaces())
userExcludeFaces.count = faceCount
if (testPolyMod.GetMapChannelActive damChan) do
(
local vertsExcluded = #()
vertsExcluded.count = testPolyMod.GetNumMapVertices damChan
for faceNum = 1 to faceCount do
(
-- Only need to bother checking face's first vert...
local vertNum = (testPolyMod.GetMapFaceVert damChan faceNum 1)
local faceExcluded = vertsExcluded[vertNum]
-- Face is considered user-excluded if this vert is at [0,0]
if (faceExcluded == undefined) do
(
local vertUv = (testPolyMod.GetMapVertex damChan vertNum)
vertUv.Z = 0
faceExcluded = (distance vertUv [0,0,0] < 0.001)
vertsExcluded[vertNum] = faceExcluded
)
userExcludeFaces[faceNum] = faceExcluded
)
)
popPrompt()
if addTestMod do
(
append deleteMods testPolyMod
)
return userExcludeFaces
)
fn addUserExcludes obj userExcludeFaces deleteMods:#() =
(
pushPrompt ("Adding User Excludes: " + obj.name)
showUnderSkin obj
local polyMod = Edit_Poly name:"Dmg.Setting...UserNone"
local selectMod = Poly_Select name:"Dmg.Sel.UserNone"
-- Add new poly-select modifier:
modPanel.addModToSelection polyMod
polyMod.setSelection #face userExcludeFaces
subobjectlevel = 4
modPanel.addModToSelection selectMod
subobjectlevel = 4
append deleteMods polyMod
-- Add uv-mapper, which maps faces to [0,0,0]:
local uvMapper = UVWMap name:(" Dmg.Map.UserNone") maptype:1 length:0.1 width:0.1 height:0.1 utile:0 vtile:0 mapChannel:damChan
modPanel.addModToSelection uvMapper
uvMapper.gizmo.scale = [0,0,0]
popPrompt()
return selectMod
)
fn genDmgMapping obj applyAll:False =
(
local skinIdx = getSkinIdx obj
if (skinIdx == 0) do return false
local skinMod = obj.modifiers[skinIdx]
if (getCommandPanelTaskMode() != #modify) do (setCommandPanelTaskMode #modify)
local keepMods = showUnderSkin obj
-- These modifiers will be deleted at end of process:
local deleteMods = #()
-- Add modifier used to probe object's faces at this point in stack, and to convert selections from vert to face:
local testPolyMod = Edit_Poly name:"Dmg.Poly.Testing..."
modPanel.addModToSelection testPolyMod
append deleteMods testPolyMod
-- Find faces mapped to [0,0,0]
local userExcludeFaces = getUserExcludedFaces obj testPolyMod:testPolyMod deleteMods:deleteMods
-- Remove existing "Dmg" modifiers (apart from temp test-modifier)
deleteTheseMods obj (findNamedMods obj) keepMods:(#(testPolyMod) + keepMods)
-- Get working bone-names list, and tweak it for alternative skeletons:
for sectionData in sectionsList do (sectionData.WorkingBoneNames = deepCopy sectionData.boneNames)
sectionsList.enabled = True
-- If scene contains clavicle-nubs, it's probably a shark - don't include clavicles as part of torso:
if (($SKEL_Clavicle_NUB*).count != 0) do
(
sectionsList[1].WorkingBoneNames = for boneName in sectionsList[1].WorkingBoneNames where (not matchPattern boneName pattern:"*Clavicle*") collect boneName
)
-- Mapping-cylinders will be placed at the position of the first bones on the bone-lists, and pointed at the last bone on that list:
local secNum = 0
for sectionData in sectionsList where sectionData.Enabled do
(
sectionData.Num = (secNum += 1)
sectionData.Verts = #{}
sectionData.GeomFaces = #{}
sectionData.MapFaces = #{}
local boneNames = sectionData.WorkingBoneNames
local boneObjs = for boneName in boneNames collect
(
local obj = getNodeByName boneName
if (isValidNode obj) then obj else dontCollect
)
local rootPos, mapDir
if (boneObjs.count > 1) then
(
local rootPos = boneObjs[1].pos
local endPos = boneObjs[boneObjs.count].pos
-- Mapping-direction is from first bone to last:
local mapDir = endPos - rootPos
)
else
(
sectionData.Enabled = False
)
sectionData.rootPos = rootPos
sectionData.mapDir = mapDir
)
-- Set view to Skin modifier:
if (getCommandPanelTaskMode() != #modify) do (setCommandPanelTaskMode #modify)
modPanel.setCurrentObject skinMod
skinOps.closeWeightTool skinMod
local useBones = #{}
local boneSectionNums = #()
local excludeBones = #{}
local underExcludeBones = #{}
-- Match skin-modifier's bone-names against the body-section bone-name lists:
(
local skinBoneCount = skinOps.getNumberBones skinMod
local allMentionedBones = #{}
local boneNum, boneSectionNum
for boneNum = 1 to skinBoneCount do
(
boneSectionNum = undefined
skinBoneName = skinOps.getBoneName skinMod boneNum 1
-- Is this on the exclude-bones list?
for boneName in excludeBoneNames while (boneSectionNum == undefined) do
(
if (matchPattern skinBoneName pattern:boneName) do
(
excludeBones[boneNum] = True
allMentionedBones[boneNum] = True
boneSectionNum = False
)
)
-- Is this on the underside-exclude bones list?
if (boneSectionNum != False) do
(
for boneName in underExcludeBoneNames while (not underExcludeBones[boneNum]) do
(
if (matchPattern skinBoneName pattern:boneName) do
(
underExcludeBones[boneNum] = True
allMentionedBones[boneNum] = True
)
)
)
-- Is this on any of the main section-bones lists?
for sectionNum = 1 to sectionsList.count while (boneSectionNum == undefined) do
(
for boneName in sectionsList[sectionNum].WorkingBoneNames while (boneSectionNum == undefined) do
(
if (matchPattern skinBoneName pattern:boneName) do
(
boneSectionNum = sectionNum
)
)
)
if (isKindOf boneSectionNum integer) do
(
useBones[boneNum] = True
allMentionedBones[boneNum] = True
)
append boneSectionNums boneSectionNum
)
)
local excludeVerts = #{}
local underExcludeVerts = #{}
-- Verts used by bones for multiple sections:
local overlapVerts = #{}
-- Find body-section with highest bone-weight for each vertex
for skinVertNum = 1 to (skinOps.getNumberVertices skinMod) do
(
local vertHighWeight = 0.0
local vertHighSectionNum = 0
local vertBoneCount = (skinOps.getVertexWeightCount skinMod skinVertNum)
local vertExcludes = #{}
local vertUnderExcludes = #{}
for vertBoneNum = 1 to vertBoneCount do
(
local getBoneID = skinOps.GetVertexWeightBoneID skinMod skinVertNum vertBoneNum
local getBoneWeight = skinOps.GetVertexWeight skinMod skinVertNum vertBoneNum
local hasWeight = (getBoneWeight != 0)
if hasWeight and useBones[getBoneID] do
(
-- Is this vert used by more than one body-segment?
if (vertHighWeight > 0) and (vertHighSectionNum != 0) and (vertHighSectionNum != boneSectionNums[getBoneID]) do
(
overlapVerts[skinVertNum] = true
)
if (getBoneWeight > vertHighWeight) do
(
vertHighWeight = getBoneWeight
vertHighSectionNum = boneSectionNums[getBoneID]
)
)
if excludeBones[getBoneID] or (not hasWeight) do
(
vertExcludes[vertBoneNum] = True
)
if underExcludeBones[getBoneID] or (not hasWeight) do
(
vertUnderExcludes[vertBoneNum] = True
)
)
-- Only flag this vert for exclusion if it it only used by excludey or non-weighted bones:
if (vertExcludes.numberSet == vertBoneCount) do
(
excludeVerts[skinVertNum] = True
)
if (vertUnderExcludes.numberSet == vertBoneCount) do
(
underExcludeVerts[skinVertNum] = True
)
if (vertHighSectionNum != 0) do sectionsList[vertHighSectionNum].Verts[skinVertNum] = true
)
fn getFaces polyMod verts =
(
polyMod.setSelection #vertex #{}
subobjectlevel = 1
polyMod.Select #vertex verts
polyMod.convertSelection #Vertex #Face
subobjectlevel = 4
polyMod.GetSelection #Face
)
-- Convert overlap-verts to faces:
modPanel.setCurrentObject testPolyMod
testPolyMod.ButtonOp #UnhideAllFace
testPolyMod.ButtonOp #UnhideAllVertex
local overlapFaces = getFaces testPolyMod overlapVerts
-- Find faces used by verts:
for sectionData in sectionsList where sectionData.Enabled and (applyAll or (sectionData.Verts.count != 0)) do
(
sectionData.GeomFaces = getFaces testPolyMod sectionData.Verts
)
local excludeFaces = getFaces testPolyMod excludeVerts
local underExcludeFaces = getFaces testPolyMod underExcludeVerts
-- Work out which face-elements in UV-channel 1 belong to which body-section, based on non-overlapping verts:
(
local testUvMap = Unwrap_UVW name:("Dmg.UV.Testing...")
testUvMap.setApplyToWholeObject true
addModifier obj testUvMap -- Add modifier to top of stack:
testUvMap.setTVSubObjectMode 3
append deleteMods testUvMap
for sectionData in sectionsList where sectionData.Enabled and (applyAll or (sectionData.geomFaces.numberSet != 0)) do
(
-- Select the segment's uncontested faces:
testUvMap.selectFaces (sectionData.geomFaces - overlapFaces)
-- Expand selection to get full mapping-element:
local lastSelCount
local curSelCount = 0
while (lastSelCount != curSelCount) do
(
lastSelCount = curSelCount
testUvMap.expandSelection()
curSelCount = (testUvMap.getSelectedFaces()).numberSet
)
-- Get faces that are on the same mapping-element as faces that are only on this body-segment, are aren't on multiple segments:
sectionData.mapFaces = testUvMap.getSelectedFaces()
)
)
-- Delete all modifiers that have been marked for removal so far:
deleteTheseMods obj deleteMods keepMods:keepMods
-- Make list of UV-faces that are connected to multiple body-segments, and shouldn't be used to decide assignments:
local UVOverlaps = #{}
for sectionData in sectionsList do
(
local secMapFaces = sectionData.mapFaces
for otherSecNum = (sectionData.Num + 1) to sectionsList.count do
(
UVOverlaps += sectionsList[otherSecNum].mapFaces * secMapFaces
)
sectionData.mapFaces -= UVOverlaps
)
-- Assign remaining segment-UV faces to their assigned segment, and remove them from the others:
for sectionData in sectionsList do
(
sectionData.GeomFaces += sectionData.mapFaces
for otherSectionData in sectionsList where (otherSectionData != sectionData) do
(
otherSectionData.geomFaces -= sectionData.mapFaces
)
)
-- Add modifiers to bottom of current stack...
modPanel.setCurrentObject obj
for sectionData in sectionsList where sectionData.Enabled and (applyAll or (sectionData.GeomFaces.numberSet != 0)) do
(
local sectionName = sectionData.Name
local polyMod = Edit_Poly name:("Dmg.New." + sectionName)
local selectMod = Poly_Select name:("Dmg.Sel." + sectionName)
local uvMapper = UVWMap name:(" Dmg.Map." + sectionName) maptype:1 length:1 width:1 height:sectionData.CylHeight mapChannel:damChan
local flipVal = if sectionData.FlipSection then 1 else 0
local uvXformer = UVW_Xform name:(" Dmg.uvxfrm." + sectionName) map_channel:damChan u_offset:1 v_offset:sectionData.VOffset u_flip:flipVal v_flip:flipVal
-- Add temporary selection-setup modifier:
(
modPanel.addModToSelection polyMod
append deleteMods polyMod
)
-- Unhide faces. Clear subobject-selection, to ensure that uvMapper gizmo is centred on object pivot:
subobjectlevel = 4
polyMod.ButtonOp #UnhideAllVertex
polyMod.ButtonOp #UnhideAllFace
polyMod.setSelection #face #{}
-- Add uvmapper while selection is blank:
modPanel.addModToSelection uvMapper
modPanel.addModToSelection uvXformer
-- Set Edit Poly modifier's selection:
modPanel.setCurrentObject polyMod
polyMod.Select #Face sectionData.geomFaces
-- Convert Edit to Select:
modPanel.addModToSelection selectMod
subobjectlevel = 4
modPanel.setCurrentObject uvXformer
(
-- Add temp object to work out gizmo direction:
local tempDirObj = box name:(uniqueName "Temp_dmgMapDirDummy") \
width:0.1 height:0.1 length:0.1 --parent:obj
-- Point temp-box in the right direction:
tempDirObj.dir = sectionData.mapDir
local getRot = (tempDirObj.rotation) as eulerAngles
getRot.Z = 0
tempDirObj.rotation = getRot
-- Apply cylinder-rotation if required:
if sectionData.CylRot != 0 do
(
in coordSys local rotate tempDirObj (eulerangles 0 0 sectionData.CylRot)
)
tempDirObj.pos = in coordSys obj sectionData.rootPos
-- Pass object's transform to gizmo, delete temp object:
local newDirXform = tempDirObj.transform * (inverse obj.objectTransform)
delete tempDirObj
uvMapper.gizmo.transform = newDirXform
)
-- Clear per-section data-arrays:
sectionData.Verts = #{}
sectionData.GeomFaces = #{}
sectionData.MapFaces = #{}
sectionData.WorkingBoneNames = #()
)
-- Add modifiers to auto-exclude faces from damage:
(
-- Only set down-facing "underExcludeFaces" as excluded:
for faceNum in underExcludeFaces do
(
local faceNorm = (polyop.getFaceNormal obj faceNum)
if (faceNorm.Z < -0.5) do
(
excludeFaces[faceNum] = True
)
)
if (excludeFaces.numberSet != 0) do
(
local polyMod = Edit_Poly name:"Dmg.Setting...AutoNone"
local selectMod = Poly_Select name:"Dmg.Sel.AutoNone"
-- Add new poly-select modifier:
(
modPanel.addModToSelection polyMod
append deleteMods polyMod
)
polyMod.setSelection #face excludeFaces
subobjectlevel = 4
modPanel.addModToSelection selectMod
subobjectlevel = 4
-- Add uv-mapper, which maps faces to [0,0,0]:
local uvMapper = UVWMap name:(" Dmg.Map.AutoNone") maptype:1 length:0.1 width:0.1 height:0.1 utile:0 vtile:0 mapChannel:damChan
modPanel.addModToSelection uvMapper
uvMapper.gizmo.scale = [0,0,0]
-- Shift auto-excluded UVs up to [0,1,0] to keep them separate from manually-excluded ones:
local uvXformer = UVW_Xform name:(" Dmg.uvxfrm.AutoNone") map_channel:damChan v_offset:1
modPanel.addModToSelection uvXformer
-- Delete all modifiers that have been marked for removal so far:
deleteTheseMods obj deleteMods keepMods:keepMods
)
)
-- Add manual-exclude modifiers:
(
addUserExcludes obj userExcludeFaces deleteMods:deleteMods
)
-- Delete all modifiers that have been marked for removal:
deleteTheseMods obj deleteMods keepMods:keepMods
OK
)
on btnDmgMapper pressed do
(
local timeStart = timeStamp()
progressCtrl.value = 0
local selObjs = getCurrentSelection()
local useObjs = for obj in selObjs where (isEditPolyMesh obj) collect obj
if (useObjs.count != 0) do
(
clearHelperMats deactivate:False
undo "apply Damage Mapping" on with redraw off
(
local currentObj = (modPanel.getCurrentObject())
local panelMode = (getCommandPanelTaskMode())
local viewSave = (RSrefFuncs.viewportsToWire())
-- Reset radiosity models, to avoid getting the "The Radiosity Solution has been Invalidated" message:
if (isKindOf SceneRadiosity.Radiosity Radiosity) do
(
SceneRadiosity.Radiosity.Reset True False
)
-- Process objects:
for objNum = 1 to useObjs.count while (not keyboard.escPressed) do
(
local obj = useObjs[objNum]
local promptMsg = stringstream ""
format "Applying Damage Mapping to:% [%/%]" obj.name objNum useObjs.count to:promptMsg
pushPrompt (promptMsg as string)
genDmgMapping obj applyAll:btnMapAllLimbs.checked
popPrompt()
progressCtrl.value = 100 * (float objNum / useObjs.count)
)
if (getCommandPanelTaskMode() != panelMode) do (setCommandPanelTaskMode panelMode)
if (currentObj == undefined) then
(
select selObjs
)
else
(
modPanel.setCurrentObject currentObj
)
RSrefFuncs.restoreViewports viewSave
)
startShowHelperMats()
)
progressCtrl.value = 100
format "Time taken to apply Damage Mapping: %s\n" ((timeStamp() - timeStart) / 1000.0)
)
on btnAddExclusion pressed do
(
local timeStart = timeStamp()
local selObjs = getCurrentSelection()
local useObjs = for obj in selObjs where (isEditPolyMesh obj) collect obj
progressCtrl.value = 0
if (useObjs.count != 0) do
(
clearHelperMats deactivate:False
undo "add damage-exclusion" on
(
local selObjs = getCurrentSelection()
local currentObj = (modPanel.getCurrentObject())
local panelMode = (getCommandPanelTaskMode())
local viewSave = (RSrefFuncs.viewportsToWire())
-- Reset radiosity models, to avoid getting the "The Radiosity Solution has been Invalidated" message:
if (isKindOf SceneRadiosity.Radiosity Radiosity) do
(
SceneRadiosity.Radiosity.Reset True False
)
-- Set panel to Modify tab:
if (panelMode != #modify) do (setCommandPanelTaskMode #modify)
local selMods = #()
for objNum = 1 to useObjs.count while (not keyboard.escPressed) do
(
local obj = useObjs[objNum]
local promptMsg = stringstream ""
format "Applying Damage Exclusion to:% [%/%]" obj.name objNum useObjs.count to:promptMsg
pushPrompt (promptMsg as string)
-- Show modifier-stack below Skin and its safety-modifiers:
local keepMods = showUnderSkin obj
local deleteMods = #()
-- Find faces mapped to [0,0,0]
local userExcludeFaces = getUserExcludedFaces obj deleteMods:deleteMods
-- Delete existing User-exclude modifiers before re-adding:
join deleteMods (findNamedMods obj namePattern:"Dmg.*.UserNone")
-- Add new exclude-modifiers:
local selMod = addUserExcludes obj userExcludeFaces deleteMods:deleteMods
append selMods selMod
deleteTheseMods obj deleteMods keepMods:keepMods
popPrompt()
progressCtrl.value = 100 * (float objNum / useObjs.count)
)
case of
(
(selMods.count == 1):
(
modPanel.setCurrentObject selMods[1]
subobjectlevel = 4
showEndResult = True
)
(currentObj == undefined):
(
select selObjs
)
Default:
(
modPanel.setCurrentObject currentObj
)
)
RSrefFuncs.restoreViewports viewSave
)
startShowHelperMats()
)
progressCtrl.value = 100
format "Time taken to apply Damage Exclusion: %s\n" ((timeStamp() - timeStart) / 1000.0)
)
on btnCollapseToSkin pressed do
(
clearHelperMats deactivate:False
undo "collapse to Skin" on
(
local selObjs = getCurrentSelection()
local currentObj = modPanel.getCurrentObject()
for obj in selObjs do
(
local skinIdx = getSkinIdx obj
if (skinIdx != 0) do
(
modPanel.SetCurrentObject obj.modifiers[skinIdx]
maxOps.CollapseNodeTo obj (skinIdx + 1) True
)
)
if (currentObj == undefined) then
(
select selObjs
)
else
(
modPanel.setCurrentObject currentObj
)
)
startShowHelperMats()
)
)
createDialog RSpedDmgMapperRoll