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