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.
New year, new version Autoweight 0.055 is available.
Click here to go the scriptspot-page to donwload the current version.
Click here to read about a couple of new features on scriptspot.
Click here to watch a new tutorial-video.
Happy new year ko’gen
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