Notifications
Clear all

[Closed] Delete Geometry from Skin Modifier Bone List

I’m trying to find a way to have maxscript go through the bone list in a Skin modifier and remove any geometry from the list, leaving only bones in the list. There isn’t any weighting on the culprit geometry in the bone list, but they are causing problems further down the pipeline.

I’m looking through the Skin modifier page in the maxscript documentation, and I’ve found the following commands, which could prove useful.

[color=MediumTurquoise]skinOps.multiRemove <Skin>
Brings up a list box where the user can delete multiple bones instead of one at a time.

skinOps.addbone <Skin> <Bone_node> <Update_integer>
Adds a bone to the current system.

skinOps.GetBoneName <Skin> <bone_integer> <nameflag_index>
Returns the name of the indexed bone as a string.where nameflag_index can be 0 or 1.

skinOps.GetNumberBones <Skin>
Returns the number of bones in the system.

skinOps.GetSelectedBone <Skin>
Returns the index of the current selected bone in the Bone list.[/color]

My original thought was to prune items out of the bone list by class, leaving only boneGeometry class items in the list. I’m not sure how to go about this though.

Another approach might be to save out the weights, delete everything from the bone list, load only bones back into the list by class, then import the weights back into the modifier

A third option might be to save the weights, delete the Skin modifer, apply a new Skin modifier, load only bones back into the list by class, then import the weights back in.

10 Replies

Hi Dustin,

My original thought was to prune items out of the bone list by class, leaving only boneGeometry class items in the list. I’m not sure how to go about this though.

I would do it this way too. this should get you started:

mapped fn RemoveNonBonesFromSkin obj =
(
if isvalidnode obj then
	(	
	ind = modPanel.getModifierIndex obj obj.Skin

		if ind != undefined then
		(
		--set the modify panel active, skinops needs this
		max modify mode
		modPanel.setCurrentObject obj.modifiers[ind] 
		-- get the bone count	
		numBones = skinOps.getNumberBones obj.skin
		-- get the bonenames
		Bonenames = for b = 1 to numBones collect skinOps.getBoneName obj.skin b 1
		-- iterate the array in reverse as when you remove a bone the .count property will change	
		for i = BoneNames.count to 1 by -1 do
			(
			local skinbone = getnodebyname BoneNames[i]
			-- if it's not a bone, remove it
			if classof skinbone != BoneGeometry then 
				skinOps.removebone Obj.skin i 	
			)--end loop
		)--end if ind
	)--end isvalidnode
)
RemoveNonBonesFromSkin (selection as array)

here is my version… i’m using check dependency to find exact bones that used in the Skin:


  fn removeNotBones sk = 
  (
  	nodes = for n in (refs.dependson sk) where isvalidnode n and not iskindof n BoneGeometry collect n
  	names = for k=1 to (skinops.getnumberbones sk) collect (skinops.getbonename sk k 0)
  
  	for node in nodes where (k = finditem names node.name) != 0 do
  	(
  		skinops.removebone sk k
  		deleteitem names k
  	)
  )
  --where [b]sk [/b]is currently opened skin modifier
  

Thanks so much guys, I really appreciate the help.

using refs.dependson is a nice way of doing it. Skinops doesn’t allow you to get the bone as a node, only a string. I am never sure how efficient getnodebyname is but i guess it’s not a huge issue if it only takes a second longer to calculate in this context.

2 Replies
(@denist)
Joined: 11 months ago

Posts: 0

the problem of using of getnodebyname is multiply nodes with the same name. usually i’m using same names in rig(skeleton) for all characters. the only difference is main Root. It has character’s name.
that means the node that you got with getnodebyname might be not the same node that used in the skin.

(@lonerobot)
Joined: 11 months ago

Posts: 0

Yes, that’s certainly true. You can make simple tools to check assets for duplicate names to avoid this as much as possible, but it’s certainly not a concrete way of avoiding it. The other option I have used is to specify all:true in getnodebyname and check that returned array count is 1. But there’s no real way knowing without using the refs structure if is it actually the bone you are looking for on a character.

Just so I’m certain I understand…


--Removes bones for the currently selected Skin modifier which are in variable k
skinOps.removeBone sk k
--Deletes items in the names variable which are also in the f variable so they're no longer part of that array
deleteItem names f

Correct?

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

deleteItem names f

why is f? in my code it’s k. you have to delete the same index from skin list and from names. the idea is to keep same indexation in both lists after removing a bone from the skin.

I just changed it to f because you defined k as a variable in the names array, then used the same variable again a few lines later. There’s nothing wrong with that, I just used a different letter to make it more understandable for me since I’m learning.

however you like but in case of
skinOps.removeBone sk k
deleteItem names f
f and k have to be the same