Notifications
Clear all

[Closed] Auto-Skin-Weight Approach

 eek

Yep its pretty neat – I’d like to see regions assigned to multiple joints e.g. Upper leg, lower leg, knee faces assigned to both. Displaying the border verts would be neat and allowing there assignment too would be cool for joints used just for spreading deformation and not weighting a whole region.

Must look into this myself sometime.

Oh I see what you mean. Cool ideas. I think some of them might be easy to implement, others might need some time especially cause I have to figure out how to make it all “flowing”. The worst thing would be if the user would be slayn by thousands of menus.
So for today I added a little curve control to let the the user change the falloff type of their transitions took me a while to fight against the curve-control UI element but in the end it was okay.
I’m currently thinking about the possibility of storing a “transition-edge distance” for every bone individually.

Just in case some of you downloaded it on Sunday, tested it with CAT and got pretty upset about the poor functionality… please donwload it again and try it once more. I’ve fixed the “CAT-bones-are found-in-weird-order”-bug.

-k.

Thanks for the nice present. Having mirror function is absolutely fantastic

edit: Would it be too much to ask for some next version to have a check box for mirror stuff to work on topology symmetry? What I mean is that often there are character’s who’s topology is symmetrical, but for some reason a mirror vertex or poly is in different distance from the mirror plane.

Ahm… interesting question. Honestly, I have currently no idea how to implement such a topology method. Any suggestions?
What I could easily implement is a threshold value which would give you the opportunity to select a point if it’s a bit displaced from its actual mirrored position. Another idea might be adding kind of offset like they have done on the skin-mirror tab to move the mirror plane manually which would also be pretty easy.

-k.

I don;t skin anything most of the time, but I think this script is still quite awesome.

As for doing the offset, that seems like the fastest/easiest fix to do, and if it doesn’t work out, you can always do the harder approach if need be.

All those would help.

No idea, I’m only occasional scripter
But here is what I meant to exclude any confusion – mudbox symmetry, scroll down to the “Set a topological axis “/bull image

Allright, so here we go with the latest version. Though the UI might look similar to the previous version I did some coding work to fix the improper “find-region-by-bones” algorithm. Not sure about your tests but mine have been quite satisfying so far. You may give it a try.

ko’gen

for a game a build a quick weight methods, the game need maximum 2 bone for each vertices. About your tool: if a skeleton exist can assign the best weight and apply a correct smoothing value into join ? Can i use your script with another script ?

/*
	This script found all geometry with a Skin modifier and apply a best weight for each vertex.
	In this version compute the best proximity with rigid weight (1.0), in next version i will 
	make also a no-rigid weight
*/

Struct BONESKINSTRUCT
(
	iskin = 0,
	mark = #{},	--vertex list	assigned
	smth = #{},	--vertex list	that need a smooth value
	pos = [0,0,0],	--start of bone vector
	end = #() -- all children pos
)

Struct FIND_VERTEX_WEIGHTS
(
	nodes = #(),
	smoothJoint = FALSE , -- is a beta
	fn getDistanceFromBone tbone P &smth=
	(
		local A = tbone.pos
		local AP = A-P
		local endCount = tbone.end.count
		if endCount > 0 then
		(
			local dist
			for i=1 to endCount do
			(
				local into , bestDist
				local B = tbone.end[i]
				local AB = A-B
				local BP = B-P
				local outA = dot AB AP < 0
				local outB = dot AB BP > 0
				local distPB = length(BP)
				local distPA = length(AP)
				local distPAB = length(cross (AB) (AP))/length(AB)
				
				bestDist = if outA and not outB then ( into = false ; distPB)  -- out A -> get distance from point A
				else if outB and not outA then (into = false ;  distPB*1.01 )-- out B -> get distance from point B with a little penalty to assign
				else ( into = (distPAB/distPB) > 0.5 or (distPAB/distPA) > 0.5 ; distPAB )-- in A and B -> get distance from line AB -- if is exactly near B prependicular vector == 1 
					 
				if i==1 or bestDist < dist do (dist = bestDist ; smth = not into)
			)
			dist
		)
		else ( smth = false ; length AP)
	),
	fn setBestWeight =
	(
		clearlistener()
		--progressStart "Finding Skeleton Weight"
		
		progress1 = 100.0 / nodes.count
		for h=1 to nodes.count do
		(
			progressOne = progress1*(h-1)
			--progressUpdate progressOne
			local obj = maxops.getnodebyhandle nodes[h]
			format "
# Finding best weight for obj:\"%\" #
" obj.name
			st = timeStamp()
			local nVerts = obj.numverts
			
			--------------------------------------------------
			/*			  Get Bone informations				*/
			--------------------------------------------------
			local skinMod = obj.modifiers[#Skin]
			if skinMod==undefined then continue
			SetCommandPanelTaskMode mode:#modify
			ModPanel.SetCurrentObject obj.skin
			if ModPanel.GetCurrentObject() != obj.skin do (print " SHIT SKIN MODIFIER DON'T WOK *" ; return undefined)
			
			--max modify mode
			--modPanel.setCurrentObject skinMod
			local nBone = skinOps.GetNumberBones skinMod
			local BoneSkin = #()
			local BoneSkinHandle = #()
			local BoneSequence = #()
			BoneSkin.count = BoneSkinHandle.count = nBone
			for b=1 to nBone do
			(
				local bnode = getnodebyname (skinOps.GetBoneName skinMod b 1)
				BoneSkin[b] = BONESKINSTRUCT iskin:b pos:(bnode.pos) end:(for child in bnode.children collect child.pos)
				BoneSkinHandle[b] = bnode.handle
			)			
			format "> inizialize skin bone in % ms
" (timeStamp()-st)
			st = timeStamp()
			
			--------------------------------------------------
			/*		Find nearest bone for each vertex		*/
			--------------------------------------------------
			progress2 = progress1/nVerts 
			
			local RigidVertex = #{}
			for v=1 to nVerts do
			(
				--progressUpdate ((v-1)*progress2+progressOne)
				--format "> Find nearest for v %
" v
				local vertex = getVert obj v
				local nearest , mindist , needSmooth
				for b=1 to nBone do
				(
					local smth = False
					local dist = getDistanceFromBone BoneSkin[b] vertex &smth
					if b==1 or dist <= mindist do (mindist = dist ; nearest = b ;  needSmooth = smth)
					RigidVertex[v] = needSmooth
				)
				BoneSkin[nearest].mark[v] = TRUE
			)
			for b=1 to nBone do for v in BoneSkin[b].mark do skinOps.ReplaceVertexWeights skinMod v #(b) #(1.0)
			
			format "> get first proximity in % ms
" (timeStamp()-st)
			st = timeStamp()
			
			if smoothJoint do
			(
				--------------------------------------------------------------------------
				/*  Find all valid joints es: join 0-1* , join 1-2 , joint 1-3 , joint 2-4
							(2)--(4)
							/
					(0)---(1)---(3)
					* : ha due figli, prendo una bisettrice come media tra i due */
				--------------------------------------------------------------------------
				
				local joints = #()
				for b=1 to nBone do
				(
					first = maxops.getnodebyhandle BoneSkinHandle[b]
					for second in first.children where (c = finditem BoneSkinHandle second.handle)>0 do append joints #(b,c)
				)
				for n=1 to joints.count do
				(
					local b1 = joints[n][1]
					local b2 = joints[n][2]
					local bone1 = maxops.getnodebyhandle BoneSkinHandle[b1]
					local bone2 = maxops.getnodebyhandle BoneSkinHandle[b2]
					format "Joint \"%\" <-> \"%\"
" bone1.name bone2.name
					
					face1 = meshop.getFacesUsingVert  obj BoneSkin[b1].mark
					face2 = meshop.getFacesUsingVert  obj BoneSkin[b2].mark
					smoothVerts = meshop.getVertsUsingFace obj (face1*face2)
					
					local smth = false
					if smoothVerts.numberset>0 then for v in smoothVerts do
					(
						local vertex = getVert obj v
						local dist1 = getDistanceFromBone BoneSkin[b1] vertex &smth
						local dist2 = getDistanceFromBone BoneSkin[b2] vertex &smth
						local W = normalize [dist1,dist2]
						skinOps.ReplaceVertexWeights skinMod v #(b1,b2) #(W.y,W.x)
					)
					
				)
				--setVertSelection $Line004  selectV
				format "> optimize joints in % ms
" (timeStamp()-st)
			)
		)
		--progressUpdate 100.0
		progressEnd()
	)
)

/* utilize */
--algo = FIND_VERTEX_WEIGHTS nodes:(for obj in geometry where obj.modifiers[#skin]!=undefined collect obj.handle) smoothJoint:TRUE
--algo.setBestWeight()
OK
Page 7 / 10