PDA

View Full Version : Align biped to max bone rig?


Malkalypse
03-02-2012, 10:06 PM
Does anyone know of any scripts that will align a character studio biped to a rig made with Max bones?

denisT
03-03-2012, 02:33 AM
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?

NoFlame
03-03-2012, 03:01 AM
I'v made a script like you want for my company,
but it's highly customize, the bone rig have to satisfy many rules for the script work.
I don't 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.

Malkalypse
03-03-2012, 03:47 AM
It's 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's only the configuration, not animation. And since I'll be making the rig specifically for the purpose of loading a biped onto, I figure it shouldn't be a problem to set it up for a 1 to 1 conversion.

denisT
03-03-2012, 04:01 AM
It's mostly that I find fitting max bones to a character mesh much easier than doing the same with biped.
interesting... i do exactly opposite. i give to my artists the skeleton creation in the Biped and convert it to my custom rig after.

Malkalypse
03-05-2012, 10:00 PM
If anyone is interested, I've 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).
http://www.versatileartist.com/temp/stick_figure1.jpg

Once that basic stick figure has been set up, create a biped in the scene.
http://www.versatileartist.com/temp/stick_figure2.jpg

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're done!
http://www.versatileartist.com/temp/stick_figure3.jpg

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))
------------------------------------------------------------------------------------------------------------

Malkalypse
03-06-2012, 10:21 PM
Well, no big surprise, it wasn't hard to break. Getting the shoulders to line up properly was the biggest pain when I threw this together. Figures it's the first thing to not work when I tried to apply it.

Malkalypse
03-08-2012, 01:39 AM
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't 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...\n"
format "rotatedAxis: %\n" rotatedAxis
format "rotationAxis: %\n" rotationAxis

if rotatedAxis != rotationAxis then
(

if rotationAxis != planeNormal then
(
format "rotationAxis = %\n" rotationAxis
format "planeNormal = %\n" 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))
------------------------------------------------------------------------------------------------------------

PEN
03-08-2012, 01:15 PM
The clavicles just don't 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.

PEN
03-08-2012, 01:20 PM
Use getNodeByName instead of execute in you code.

Malkalypse
03-08-2012, 04:44 PM
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.)

denisT
03-08-2012, 05:10 PM
The clavicles just don't 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've 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't remember why...

CGTalk Moderation
03-08-2012, 05:10 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.