[Closed] Align biped to max bone rig?
Does anyone know of any scripts that will align a character studio biped to a rig made with Max bones?
what the hell is that? usually people align a custom bones to the biped.
is it anything about FBX to BIPED?
do you need to align THE config only OR whole animation? do you have any designated naming convention?
I鈥檝 made a script like you want for my company,
but it鈥檚 highly customize, the bone rig have to satisfy many rules for the script work.
I don鈥檛 know the goal your want to reach behind this. but if you rigging your bone freely without some limit like biped, it is useless to align biped to bone rig.
It鈥檚 mostly that I find fitting max bones to a character mesh much easier than doing the same with biped. So I want to set up a rig that fits inside my character properly, and then convert it over to a biped to load motion capture data onto.
So it鈥檚 only the configuration, not animation. And since I鈥檒l be making the rig specifically for the purpose of loading a biped onto, I figure it shouldn鈥檛 be a problem to set it up for a 1 to 1 conversion.
interesting鈥?i do exactly opposite. i give to my artists the skeleton creation in the Biped and convert it to my custom rig after.
If anyone is interested, I鈥檝e come up with something that is even better (at least for me, since I usually create my rigs off of editable splines.)
Simply set up a series of lines describing the spine, head/neck, and left/right arms/legs, each with the appropriate number of vertices, and name them accordingly (note: fingers and toes are not currently supported).
Once that basic stick figure has been set up, create a biped in the scene.
At this point, simply run the script (if your biped is named something other than Bip01, change the baseName variable in the script first). You鈥檙e done!
I have not done any significant debugging on this yet, and am by no means a Maxscript master. If anyone finds any problems, or just sees away improve my code, please let me know!
-- Definitions
------------------------------------------------------------------------------
leftLeg = $leftLeg
rightLeg = $rightLeg
spine = $spine
head = $head
leftArm = $leftArm
rightArm = $rightArm
pointLT = getKnotPoint leftLeg 1 1
pointRT = getKnotPoint rightLeg 1 1
targetPointLT = getKnotPoint leftLeg 1 2
targetPointLC = getKnotPoint leftLeg 1 3
targetPointLF = getKnotPoint leftLeg 1 4
targetPointRT = getKnotPoint rightLeg 1 2
targetPointRC = getKnotPoint rightLeg 1 3
targetPointRF = getKnotPoint rightLeg 1 4
spineArray = for i = 1 to numKnots spine collect (getKnotPoint spine 1 i)
headArray = for i = 1 to numKnots head collect (getKnotPoint head 1 i)
pointLS = getKnotPoint leftArm 1 1
targetPointLS = getKnotPoint leftArm 1 2
targetPointLUa = getKnotPoint leftArm 1 3
targetPointLFa = getKnotPoint leftArm 1 4
targetPointLH = getKnotPoint leftArm 1 5
pointRS = getKnotPoint rightArm 1 1
targetPointRS = getKnotPoint rightArm 1 2
targetPointRUa = getKnotPoint rightArm 1 3
targetPointRFa = getKnotPoint rightArm 1 4
targetPointRH = getKnotPoint rightArm 1 5
baseName = "Bip01"
bip = execute ("$'" + basename)
pelvis = execute ("$'" + basename + " Pelvis'")
leftThigh = execute ("$'" + basename + " L Thigh'")
leftCalf = execute ("$'" + basename + " L Calf'")
leftFoot = execute ("$'" + basename + " L Foot'")
rightThigh = execute ("$'" + basename + " R Thigh'")
rightCalf = execute ("$'" + basename + " R Calf'")
rightFoot = execute ("$'" + basename + " R Foot'")
spinePartArray = #()
for i = 1 to (numKnots spine - 1) do
(
id = ""
if i > 1 do id = (i - 1) as string
spinePart = execute ("$'" + basename + " Spine" + id + "'")
append spinePartArray spinePart
)
headPartArray = #()
for i = 1 to (numKnots head - 1) do
(
id = ""
if i < (numKnots head - 1) then partName = " Neck" else partName = " Head"
if i > 1 and i < (numKnots head - 1) do id = (i - 1) as string
headPart = execute ("$'" + basename + partName + id + "'")
append headPartArray headPart
)
leftShoulder = execute ("$'" + basename + " L Clavicle'")
leftUpperarm = execute ("$'" + basename + " L Upperarm'")
leftForearm = execute ("$'" + basename + " L Forearm'")
leftHand = execute ("$'" + basename + " L Hand'")
rightShoulder = execute ("$'" + basename + " R Clavicle'")
rightUpperarm = execute ("$'" + basename + " R Upperarm'")
rightForearm = execute ("$'" + basename + " R Forearm'")
rightHand = execute ("$'" + basename + " R Hand'")
------------------------------------------------------------------------------
----------------------------------------------------------
-- Function to find the angle between two lines
--
-- Special thanks to prettyPixel
----------------------------------------------------------
fn fourPointAngle pA pB pC pD =
(
local vAB = pB - pA
local vCD = pD - pC
local angle = acos (dot (normalize vAB) (normalize vCD))
if angle < 90.0 then angle else (180.0 - angle)
)
----------------------------------------------------------
-------------------------------------------------------------------------------------------------
-- Functions to control transformations of biped parts
-------------------------------------------------------------------------------------------------
fn scaleToLength part p1 p2 =
(
scalePart = biped.getTransform part #scale
lengthPart = distance p1 p2
biped.setTransform part #scale [lengthPart, scalePart.y, scalePart.z] false
)
fn rotateFromPoints part p1 p2 offset =
(
theVector = normalize (p1 - p2)
theMatrix = matrixFromNormal theVector
preRotate theMatrix offset
biped.setTransform part #rotation theMatrix false
)
fn hipsAlign =
(
hipsPos = (pointLT + pointRT) / 2
biped.setTransform bip #pos hipsPos false
scaleP = biped.getTransform pelvis #scale
hipsWidth = distance pointLT pointRT
biped.setTransform pelvis #scale [scaleP.x, scaleP.y, hipsWidth] false
rotateFromPoints bip pointLT pointRT (eulerAngles -90 180 0)
)
fn proximalAlign part p2 p3 =
(
p1 = biped.getTransform part #pos
scaleToLength part p1 p2
outVector = normalize (p3 - p1)
partVector = normalize (p2 - p1)
rightVector = normalize (cross outVector partVector)
upVector = normalize (cross rightVector partVector)
theMatrix = matrix3 partVector upVector rightVector p1
biped.setTransform part #rotation theMatrix false
)
fn distalAlign part p1 p2 =
(
scaleToLength part p1 p2
p3 = biped.getTransform part.children[1] #pos
partAngle = fourPointAngle p1 p3 p1 p2
rotate part (angleAxis -partAngle [0,0,1])
)
fn footAlign foot p1 p2 =
(
scaleFoot = biped.getTransform foot #scale
lengthX = p1.z - p2.z
lengthY = p1.y - p2.y
biped.setTransform foot #scale [lengthX, lengthY, scaleFoot.Z] false
biped.setTransform foot #rotation (eulerAngles 180 90 0) false
heel = [p1.x, p1.y, p2.z]
ball = [p1.x, p2.y, p2.z]
footAngle = fourPointAngle heel ball heel p2
if foot == rightFoot do footAngle = (-footAngle)
rotate foot (angleAxis footAngle [0,0,1])
)
fn spineAlign =
(
biped.setTransform spinePartArray[1] #pos spineArray[1] false
for i = 1 to (numKnots spine - 1) do
(
scaleToLength spinePartArray[i] spineArray[i] spineArray[i + 1]
rotateFromPoints spinePartArray[i] spineArray[i] spineArray[i + 1] (eulerAngles 180 90 0)
)
)
fn headAlign =
(
biped.setTransform headPartArray[1] #pos headArray[1] false
for i = 1 to (numKnots head - 1) do
(
scaleToLength headPartArray[i] headArray[i] headArray[i + 1]
rotateFromPoints headPartArray[i] headArray[i] headArray[i + 1] (eulerAngles 180 90 0)
)
)
fn shoulderAlign part p1 p2 =
(
biped.setTransform part #pos p1 false
scaleToLength part p1 p2
-- Clavicle Z-axis
baseVector = (biped.getTransform spinePartArray[spinePartArray.count] #rotation as matrix3)[1]
goalVector = normalize (p1 - p2)
rightVector = normalize (cross baseVector goalVector)
crossVector = normalize (cross rightVector baseVector)
theMatrix = matrix3 crossVector rightVector baseVector p1
preRotate theMatrix (eulerAngles 0 0 180)
biped.setTransform part #rotation theMatrix false
-- Clavice Y-axis
p3 = biped.getTransform part.children[1] #pos
partAngle = fourPointAngle p1 p3 p1 p2
rotate part (angleAxis -partAngle [0,1,0])
)
fn handAlign part p1 p2 =
(
scaleToLength part p1 p2
handAngle = -90
if part == rightHand do handAngle = -handAngle
rotateFromPoints part p1 p2 (eulerAngles handAngle 90 0)
)
-------------------------------------------------------------------------------------------------
-- Execute transformations
------------------------------------------------------------------------------------------------------------
if (numKnots spine) < 7
then
(
bip.controller.spineLinks = (numKnots spine - 1)
if numKnots head < 8
then
(
bip.controller.neckLinks = (numKnots head - 2)
hipsAlign()
proximalAlign leftThigh targetPointLT targetPointLC
distalAlign leftCalf targetPointLT targetPointLC
footAlign leftFoot targetPointLC targetPointLF
proximalAlign rightThigh targetPointRT targetPointRC
distalAlign rightCalf targetPointRT targetPointRC
footAlign rightFoot targetPointRC targetPointRF
spineAlign()
headAlign()
shoulderAlign leftShoulder pointLS targetPointLS
proximalAlign leftUpperarm targetPointLUa targetPointLFa
distalAlign leftForearm targetPointLUa targetPointLFa
handAlign leftHand targetPointLFa targetPointLH
shoulderAlign rightShoulder pointRS targetPointRS
proximalAlign rightUpperarm targetPointRUa targetPointRFa
distalAlign rightForearm targetPointRUa targetPointRFa
handAlign rightHand targetPointRFa targetPointRH
)
else (messageBox ("Please manually set the number of neck links to " + (numKnots head - 2) as string))
)
else (messageBox ("Please manually set the number of spine links to " + (numKnots spine - 1) as string))
------------------------------------------------------------------------------------------------------------
Well, no big surprise, it wasn鈥檛 hard to break. Getting the shoulders to line up properly was the biggest pain when I threw this together. Figures it鈥檚 the first thing to not work when I tried to apply it.
Okay, just鈥?wow.
I spent about 4 hours trying to nail down just what was going on with those clavicles. Sometimes they did what I wanted, sometimes they weren鈥檛 even close. I finally hit on a rather bizarre discovery: apparently, using biped.setTransform on the clavicles will ONLY have the desired results if the uppermost spine segment is perfectly vertical.
Knowing that, I made the following changes to my script, and it seems to be working fine now:
-- Definitions
------------------------------------------------------------------------------
leftLeg = $leftLeg
rightLeg = $rightLeg
spine = $spine
head = $head
leftArm = $leftArm
rightArm = $rightArm
pointLT = getKnotPoint leftLeg 1 1
pointRT = getKnotPoint rightLeg 1 1
targetPointLT = getKnotPoint leftLeg 1 2
targetPointLC = getKnotPoint leftLeg 1 3
targetPointLF = getKnotPoint leftLeg 1 4
targetPointRT = getKnotPoint rightLeg 1 2
targetPointRC = getKnotPoint rightLeg 1 3
targetPointRF = getKnotPoint rightLeg 1 4
spineArray = for i = 1 to numKnots spine collect (getKnotPoint spine 1 i)
headArray = for i = 1 to numKnots head collect (getKnotPoint head 1 i)
pointLS = getKnotPoint leftArm 1 1
targetPointLS = getKnotPoint leftArm 1 2
targetPointLUa = getKnotPoint leftArm 1 3
targetPointLFa = getKnotPoint leftArm 1 4
targetPointLH = getKnotPoint leftArm 1 5
pointRS = getKnotPoint rightArm 1 1
targetPointRS = getKnotPoint rightArm 1 2
targetPointRUa = getKnotPoint rightArm 1 3
targetPointRFa = getKnotPoint rightArm 1 4
targetPointRH = getKnotPoint rightArm 1 5
baseName = "Bip01"
bip = execute ("$'" + basename)
pelvis = execute ("$'" + basename + " Pelvis'")
leftThigh = execute ("$'" + basename + " L Thigh'")
leftCalf = execute ("$'" + basename + " L Calf'")
leftFoot = execute ("$'" + basename + " L Foot'")
rightThigh = execute ("$'" + basename + " R Thigh'")
rightCalf = execute ("$'" + basename + " R Calf'")
rightFoot = execute ("$'" + basename + " R Foot'")
spinePartArray = #()
for i = 1 to (numKnots spine - 1) do
(
id = ""
if i > 1 do id = (i - 1) as string
spinePart = execute ("$'" + basename + " Spine" + id + "'")
append spinePartArray spinePart
)
headPartArray = #()
for i = 1 to (numKnots head - 1) do
(
id = ""
if i < (numKnots head - 1) then partName = " Neck" else partName = " Head"
if i > 1 and i < (numKnots head - 1) do id = (i - 1) as string
headPart = execute ("$'" + basename + partName + id + "'")
append headPartArray headPart
)
leftShoulder = execute ("$'" + basename + " L Clavicle'")
leftUpperarm = execute ("$'" + basename + " L Upperarm'")
leftForearm = execute ("$'" + basename + " L Forearm'")
leftHand = execute ("$'" + basename + " L Hand'")
rightShoulder = execute ("$'" + basename + " R Clavicle'")
rightUpperarm = execute ("$'" + basename + " R Upperarm'")
rightForearm = execute ("$'" + basename + " R Forearm'")
rightHand = execute ("$'" + basename + " R Hand'")
------------------------------------------------------------------------------
----------------------------------------------------------
-- Functions to find the angle between two lines
----------------------------------------------------------
fn fourPointAngle pA pB pC pD =
(
local vAB = pB - pA
local vCD = pD - pC
local angle = acos (dot (normalize vAB) (normalize vCD))
if angle < 90.0 then angle else (180.0 - angle)
)
----------------------------------------------------------
fn twoVectorAngle vAB vCD =
(
local angle = acos (dot (normalize vAB) (normalize vCD))
if angle < 90.0 then angle else (180.0 - angle)
)
----------------------------------------------------------
/*
--------------------------------------------------------------------------------------------
-- Function to align an axis to a plane using another axis
--------------------------------------------------------------------------------------------
-- Special thanks to Denis Trofimove
fn alignAxisToPlane node axis:#x pole: normal:[0,0,1] =
(
tm = node.transform
vec = case axis of
(
#x: tm[1]
#y: tm[2]
#z: tm[3]
)
vec = normalize vec
normal = normalize normal
if abs (dot vec normal) > 0.0 do
(
rot = if iskindof pole Point3 and abs (dot vec pole) < 1.0 then
(
pole = normalize pole
normalize (cross pole normal)
) else vec
front = normalize (cross rot normal)
side = normalize (cross normal front)
if (dot vec side) < 0.0 do side = -side
rtm = angleaxis (acos (dot vec side)) (normalize (cross side vec))
node.transform = tm = translate (rotate (scalematrix tm.scale) (tm.rotation*rtm)) tm.pos
)
tm
)
--------------------------------------------------------------------------------------------
*/
fn rotateToAlign obj rotatedAxis rotationAxis planeNormal =
(
format "rotateToAlign...
"
format "rotatedAxis: %
" rotatedAxis
format "rotationAxis: %
" rotationAxis
if rotatedAxis != rotationAxis then
(
if rotationAxis != planeNormal then
(
format "rotationAxis = %
" rotationAxis
format "planeNormal = %
" planeNormal
proj = cross (normalize rotationAxis) (normalize planeNormal)
rot = acos (dot rotatedAxis (normalize proj))
) else rot = 0.0
if rot>90.0 then abs (rot-=180)
rotationAxis = normalize(cross rotatedAxis proj)
rQuat = quat (rotationAxis.x * (sin(rot / 2))) (rotationAxis.y * (sin(rot / 2))) (rotationAxis.z * (sin(rot / 2))) (cos (rot / 2))
rotate obj rQuat
)
)
-------------------------------------------------------------------------------------------------
-- Functions to control transformations of biped parts
-------------------------------------------------------------------------------------------------
fn scaleToLength part p1 p2 =
(
scalePart = biped.getTransform part #scale
lengthPart = distance p1 p2
biped.setTransform part #scale [lengthPart, scalePart.y, scalePart.z] false
)
fn rotateFromPoints part p1 p2 offset =
(
theVector = normalize (p1 - p2)
theMatrix = matrixFromNormal theVector
preRotate theMatrix offset
biped.setTransform part #rotation theMatrix false
)
fn hipsAlign =
(
hipsPos = (pointLT + pointRT) / 2
biped.setTransform bip #pos hipsPos false
scaleP = biped.getTransform pelvis #scale
hipsWidth = distance pointLT pointRT
biped.setTransform pelvis #scale [scaleP.x, scaleP.y, hipsWidth] false
rotateFromPoints bip pointLT pointRT (eulerAngles -90 180 0)
)
fn proximalAlign part p2 p3 =
(
p1 = biped.getTransform part #pos
scaleToLength part p1 p2
outVector = normalize (p3 - p1)
partVector = normalize (p2 - p1)
rightVector = normalize (cross outVector partVector)
upVector = normalize (cross rightVector partVector)
theMatrix = matrix3 partVector upVector rightVector p1
biped.setTransform part #rotation theMatrix false
)
fn distalAlign part p1 p2 =
(
scaleToLength part p1 p2
p3 = biped.getTransform part.children[1] #pos
partAngle = fourPointAngle p1 p3 p1 p2
rotate part (angleAxis -partAngle [0,0,1])
)
fn footAlign foot p1 p2 =
(
scaleFoot = biped.getTransform foot #scale
lengthX = p1.z - p2.z
lengthY = p1.y - p2.y
biped.setTransform foot #scale [lengthX, lengthY, scaleFoot.Z] false
biped.setTransform foot #rotation (eulerAngles 180 90 0) false
heel = [p1.x, p1.y, p2.z]
ball = [p1.x, p2.y, p2.z]
footAngle = fourPointAngle heel ball heel p2
if foot == rightFoot do footAngle = (-footAngle)
rotate foot (angleAxis footAngle [0,0,1])
)
fn spineAlign =
(
biped.setTransform spinePartArray[1] #pos spineArray[1] false
for i = 1 to (numKnots spine - 1) do
(
scaleToLength spinePartArray[i] spineArray[i] spineArray[i + 1]
rotateFromPoints spinePartArray[i] spineArray[i] spineArray[i + 1] (eulerAngles 180 90 0)
)
)
fn headAlign =
(
biped.setTransform headPartArray[1] #pos headArray[1] false
for i = 1 to (numKnots head - 1) do
(
scaleToLength headPartArray[i] headArray[i] headArray[i + 1]
rotateFromPoints headPartArray[i] headArray[i] headArray[i + 1] (eulerAngles 180 90 0)
)
)
fn shoulderAlign part tgt =
(
topSpine = spinePartArray[spinePartArray.count]
tgt.parent = topSpine
spineRot = biped.getTransform topSpine #rotation
biped.setTransform topSpine #rotation (quat -0.707107 0 -0.707107 0) false
p1 = getKnotPoint tgt 1 1
p2 = getKnotPoint tgt 1 2
biped.setTransform part #pos p1 false
scaleToLength part p1 p2
shoulderAngle = 0
if part == rightShoulder do shoulderAngle = 180
rotateFromPoints part p1 p2 (eulerAngles shoulderAngle 90 90)
biped.setTransform topSpine #rotation spineRot false
)
fn handAlign part p1 p2 =
(
scaleToLength part p1 p2
handAngle = -90
if part == rightHand do handAngle = -handAngle
rotateFromPoints part p1 p2 (eulerAngles handAngle 90 0)
)
-------------------------------------------------------------------------------------------------
-- Execute transformations
------------------------------------------------------------------------------------------------------------
if (numKnots spine) < 7
then
(
bip.controller.spineLinks = (numKnots spine - 1)
if numKnots head < 8
then
(
bip.controller.neckLinks = (numKnots head - 2)
hipsAlign()
proximalAlign leftThigh targetPointLT targetPointLC
distalAlign leftCalf targetPointLT targetPointLC
footAlign leftFoot targetPointLC targetPointLF
proximalAlign rightThigh targetPointRT targetPointRC
distalAlign rightCalf targetPointRT targetPointRC
footAlign rightFoot targetPointRC targetPointRF
spineAlign()
headAlign()
shoulderAlign leftShoulder leftArm
proximalAlign leftUpperarm targetPointLUa targetPointLFa
distalAlign leftForearm targetPointLUa targetPointLFa
handAlign leftHand targetPointLFa targetPointLH
shoulderAlign rightShoulder rightArm
proximalAlign rightUpperarm targetPointRUa targetPointRFa
distalAlign rightForearm targetPointRUa targetPointRFa
handAlign rightHand targetPointRFa targetPointRH
)
else (messageBox ("Please manually set the number of neck links to " + (numKnots head - 2) as string))
)
else (messageBox ("Please manually set the number of spine links to " + (numKnots spine - 1) as string))
------------------------------------------------------------------------------------------------------------
The clavicles just don鈥檛 work in biped. I found the same issue when I tried to write a tool for a client. It will work when figure mode is off but not when it is on.
i remember this problem too.
i鈥檝e checked my old code i see that i did all structure change in the Figure Mode ON, aligned(transformed) biped bones in the Mode OFF, saved as a Bip file, went back to the Mode ON and applied the bip file.
Looks like i had a big reason doing it this way but i don鈥檛 remember why鈥?/p>
Thanks for the tip on getNodeByName! Also, I should have mentioned that this script is for using with figure mode turned on. I had a lot of problems getting it to work, and ended up spending about 4 hours just trying to pinpoint the source of the problem. But as I said, as long as the uppermost spine segment is completely vertical, the clavicles seem to behave properly (at least they have for me so far.)