-- Bip2root -- Dani Rosen - Oct 14, 2005 -- Copies horizontal position of the biped onto the root object and links the -- biped to the root. Instead of deleting the biped keys, the script also creates -- a new layer with keys for the biped that put it back to its origin. This allows -- for continued work on the biped if it gets unlinked from the root. -- -- v1.1 - Jan 6, 2006 - Made the whole operation undoable. Before only one key at a time -- could be undone. -- v1.2 - Jan 9, 2006 - fixed long-digit zero floats problem with bip positions -- v1.3 - Jan 10, 2006 - added ability to key only first and last frames. -- - creation of a new root is now relative to the bip size -- v1.4 - Jan 12, 2006 - replaced custom fields with spinner. -- v1.41 - Jan 18, 2006 - added mouse wait cursor -- v1.5 - added root fixing button for cases when the alignment fails -- v1.51 - Apr 24, 2006 - made sure the root had a linear controller. -- v1.6 - Apr 24, 2006 - added a first + last keyframes function with non-matched first frame -- v1.7 - May 12, 2006 - added Static-Root function - for preventing biped snapping on vignettes. -- v1.8 - May 18, 2006 - fixed some bugs - mostly - misalignments. -- v2.0 - May 22, 2006 - fixed a bug with creating a missing root, added a height functions. -- v2.1 - Jun 1, 2006 - small bug fixes: making rootZinit global, preventing Note keys from being -- - deleted, first-last keyframing step count fix. -- v2.2 - Jun 9, 2006 - added a missing Bip check -- v2.3 - Aug 21, 2006 - tests for Object-Space IK Objects -- v2.4 - Sep 11, 2006 - added option to freeze root's X/Y axis -- -- known issues: -- * - will always create the posAdjust layer on the bottom-most layer macroScript Bip2root category:"DaniTools" internalcategory:"DaniTools" tooltip:"Bip2root" buttontext:"Bip2root" Icon:#("SubObjectIcons",38) ( global posInit global bipObj = $Bip01 global rootObj = $'!root' global thisTime = currenttime global rootXinit, rootYinit, rootZinit rollout bip2root "Bip2root v2.4" ( button bAbout "About" tooltip:"About" height:15 width:35 pos:[190,5] radioButtons pickobj "Source and Target objects" pos:[18,15] width:230 height:30 labels:#("Default Objects", "Pick Objects") columns:2 pickbutton bipBtn "Bip01" pos:[28,55] width:80 height:25 enabled:false pickbutton rootBtn "!root" pos:[120,55] width:80 height:25 enabled:false radioButtons rootHeight "Root height:" pos:[8,90] labels:#("Current", "Footsteps", "Z=0") columns:3 default:3 button bRHeight "?" height:15 width:15 pos:[200,105] radioButtons rootKeys "Root Keyframing:" pos:[8,130] width:230 height:40 labels:#("Key Every", "Use Biped Keys", "First and Last Frames", "First and Last, First Non-Matched", "Static Root") columns:1 default:1 spinner stepCount "" range:[1,100,1] type:#integer fieldwidth:30 pos:[75,146] label lbl1 "Frames" pos:[120,147] width:40 height:16 button bfirst "?" height:15 width:15 pos:[200,190] button bstatic "?" height:15 width:15 pos:[200,208] label lbFreeze "(optional) - Freeze Root:" pos:[28,225] enabled:true checkbox chkX "X" checked:false pos:[146,224] enabled:true checkbox chkY "Y" checked:false pos:[176,224] enabled:true button doit "Do it!" pos:[28,252] width:176 height:32 progressBar progBar "ProgressBar" pos:[10,292] width:210 height:7 label lbl2 "Read \"About\" before using this \xbb" pos:[8,307] enabled:false button rootFix "Fix Root" tooltip:"Attempt to fix root position in case things messed up" height:17 pos:[170,305] enabled:false on bAbout pressed do ( rollout rolAbout "About" ( label ab1 "Bip2root v2.4" label ab2 "Dani Rosen \xa9 2005" progressBar horizLine "ProgressBar" width:200 height:3 enabled:true value:100 color:(color 10 10 0) align:#center label ab3 "Used for aligning root object to bip's position." align:#center label ab4 "For best results key every 1 frame, Z=0." align:#center label ab5 "If root is not aligned to the bip after execution" align:#center label ab6 "- undo and try again. If that fails too, click on" label ab7 "the \"fix root\" button which will attempt to fix" label ab8 "the misalignment. Another option is to delete" label ab9 "the root; the tool will recreate it." ) createdialog rolAbout width:223 height:180 ) on bRHeight pressed do ( rollout rolRHeight "Root Height" ( label hlab1 "Leave this on \"Z=0\" for most cases, where the root stays" align:#left label hlab2 "on the ground level. If the root is not on the ground level" align:#left label hlab3 "then use the \"Current\" option to use the existing root's" align:#left label hlab4 "height. If there is no root object in the scene, and the" align:#left label hlab5 "character is not at ground level - then use the \"Footsteps\"" align:#left label hlab6 "option to base the height off the Footsteps bone." align:#left height:20 label hlab7 "Note: The Footsteps bone is not an accurate means of" align:#left label hlab8 "measuring the height of the character from the ground." align:#left label hlab9 "It's usually under the center of mass (COM) and only" align:#left label hlab10 "'roughly' at the height of the lowest foot - but not exact." align:#left ) createdialog rolRHeight width:295 height:200 ) on bfirst pressed do ( rollout rolFirst "First and Last, First non-matched" ( label lab1 "Use this option when you want to start the root motion" align:#left label lab2 "From where it is on the first frame, not necessarily" align:#left label lab3 "where the biped is; then match the last frame only" align:#left label lab4 "with the biped." align:#left label lab5 "This is useful for outros of parametric mini-games," align:#left label lab6 "where the root is located where the intro started," align:#left label lab7 "and stayed there during the parametric animation." align:#left ) createdialog rolFirst width:280 height:140 ) on bstatic pressed do ( rollout rolFirst "Static Root" ( label lb1 "This option is best for vignettes, where the root stays" align:#left label lb2 "static and must only match the biped on the last frame." align:#left height:20 label lb3 "Sometimes, re-linking the biped to the root causes the" align:#left label lb4 "biped to snap to a different position in the scene." align:#left label lb5 "Choosing this option is best for such scenarios." align:#left height:20 label lb6 "Note: if you have multiple roots and bipeds, be sure" align:#left label lb7 "to name them with unique names." align:#left ) createdialog rolFirst width:280 height:150 ) on pickobj changed state do ( bipBtn.enabled = (pickobj.state == 2) rootBtn.enabled = (pickobj.state == 2) if pickobj.state == 1 do ( bipObj = Bip01 rootObj = '!root' bipBtn.text = "Bip01" rootBtn.text = "!root" ) ) on bipBtn picked obj do ( bipBtn.text=obj.name bipObj=obj ) on rootBtn picked obj do ( rootBtn.text=obj.name rootObj=obj ) on rootKeys changed state do ( if rootKeys.state == 4 or rootKeys.state == 5 then ( lbFreeze.enabled = false chkX.enabled = false chkY.enabled = false ) else ( lbFreeze.enabled = true chkX.enabled = true chkY.enabled = true ) ) -- ######## DO IT on doit pressed do ( if (isvalidnode bipObj) == false do ( messagebox ("Bip was not found! - \"" + (bipObj as string) + "\"") title:"Error! Missing Bip" return 0 ) -- Object-Space IK test: OSIK = false select (biped.getNode bipObj #larm) if bipObj.controller.osObject != undefined then OSIK = true select (biped.getNode bipObj #rarm) if bipObj.controller.osObject != undefined then OSIK = true max select none If OSIK == true then ( case (yesNoCancelBox ("One of the arms is linked to an Object-Space Object (in the IK secion).\n" + \ "This can cause unpredictable results if the OS Object is not deleted.\n" + \ "Would you like to continue anyway?") title:"Object-Space IK Object detected!") of ( #yes: format "" #no: return 0 #cancel: return 0 ) ) undo "Bip2root" on ( thisTime = currenttime -- create root if it's not there if rootObj == undefined do ( if (isvalidnode $'!root') == false do ( BipDim = bipObj.max - bipObj.min -- basing root size off of biped size: rootObj = box length:(BipDim[1] * 2) width:(BipDim[1] * 2) height:((BipDim[1] * 2)/1.5) name:"!root" boxmode:on ) ) -- make the root linear rootObj.pos.controller = linear_position() slidertime = animationrange.start -- set var root height FSbone = biped.getNode bipObj #footprints if rootHeight.state == 1 then global rootZinit = rootObj.pos.z if rootHeight.state == 2 then global rootZinit = FSbone.transform[4][3] if rootHeight.state == 3 then global rootZinit = 0 -- set rootXYinit rootXinit = rootObj.pos.x rootYinit = rootObj.pos.y -- test duplicate names global bipArray = #() global rootArray = #() for t in objects do ( if t.name == bipObj.name then append bipArray t.name if t.name == rootObj.name then append rootArray t.name ) if bipArray.count > 1 or rootArray.count > 1 then ( messagebox ("There are duplicate names in the scene!\nPlease rename your Root and Biped to have unique names.") \ title:"Error!" return 0 ) setWaitCursor() max select none --script causes problems if Bip is selected if bipObj == undefined do ( messagebox ("There is no Biped in the scene!") title:"Error!" return 0 ) at time animationrange.start.frame posInit = Biped.getTransform bipObj #pos -- correct long zero floats if (findstring (posInit[1] as string) "e") != undefined do ( posInit = #(0, posInit[2], posInit[3]) ) if (findstring (posInit[2] as string) "e") != undefined do ( posInit = #(posInit[1], 0, posInit[3]) ) if (findstring (posInit[3] as string) "e") != undefined do ( posInit = #(posInit[1], posInit[2], 0) ) -- check if Biped is linked if bipObj.parent != undefined then ( if rootKeys.state != 5 then ( BipDimNew = bipObj.max - bipObj.min -- basing root size off of biped size: rootObjTemp1 = box length:(BipDimNew[1] * 2) width:(BipDimNew[1] * 2) height:((BipDimNew[1] * 2)/1.5) name:"!root_TEMP1" boxmode:on rootObjTemp2 = box length:(BipDimNew[1] * 2) width:(BipDimNew[1] * 2) height:((BipDimNew[1] * 2)/1.5) name:"!root_TEMP2" boxmode:on with animate off ( rootObjTemp1.pos = [posInit[1],posInit[2],rootZinit] rootObjTemp2.pos = rootObjTemp1.pos rootObjTemp1.parent = bipObj d = dummy () bipObj.parent = d bipObj.parent = undefined delete d if rootObjTemp1.pos != rootObjTemp2.pos then ( rootObjTemp1.parent = undefined bipObj.parent = rootObjTemp1 rootObjTemp1.transform = rootObjTemp2.transform bipObj.parent = undefined ) delete rootObjTemp1 delete rootObjTemp2 ) ) ) rootInitpos = rootObj.pos deletekeys rootObj.controller #allkeys bipHkeys = bipObj.transform.controller.horizontal.controller.keys if (biped.numLayers bipObj.controller) > 0 then ( for L in 1 to (biped.numLayers bipObj.controller) do ( if (biped.getLayerName bipObj.controller 1) == "posAdjust" then ( biped.deleteLayer bipObj.controller 1 ) ) ) if rootKeys.state != 5 then ( biped.createLayer bipObj.controller 1 "posAdjust" biped.setcurrentlayer bipObj.controller 0 ) -- ### USE BIPED KEYS if rootKeys.state == 2 then ( global icount = 0 for i in bipHkeys do ( icount += 1 at time i.time.frame ( bipos = Biped.getTransform bipObj #pos -- correct long zero floats if (findstring (bipos[1] as string) "e") != undefined do ( bipos = #(0, bipos[2], bipos[3]) ) if (findstring (bipos[2] as string) "e") != undefined do ( bipos = #(bipos[1], 0, bipos[3]) ) with animate on ( rootPosX = bipos[1] rootPosY = bipos[2] bipPosX = posInit[1] bipPosY = posInit[2] if chkX.checked then ( rootPosX = rootXinit bipPosX = posInit[1] + (bipos[1] - rootXinit) ) if chkY.checked then ( rootPosY = rootYinit bipPosY = posInit[2] + (bipos[2] - rootYinit) ) rootObj.pos = [rootPosX,rootPosY,rootZinit] biped.setcurrentlayer bipObj.controller 1 Biped.setTransform bipObj #pos [bipPosX,bipPosY,bipos[3]] on biped.setcurrentlayer bipObj.controller 0 ) ) progBar.value = 100.0*icount/bipHkeys.count ) ) -- end rootKeys 2 else ( -- ### KEY EVERY N FRAME if rootKeys.state == 1 then ( for i in animationrange.start.frame to animationrange.end.frame by stepCount.value do ( at time i ( bipos = Biped.getTransform bipObj #pos -- correct long zero floats if (findstring (bipos[1] as string) "e") != undefined do ( bipos = #(0, bipos[2], bipos[3]) ) if (findstring (bipos[2] as string) "e") != undefined do ( bipos = #(bipos[1], 0, bipos[3]) ) with animate on ( rootPosX = bipos[1] rootPosY = bipos[2] bipPosX = posInit[1] bipPosY = posInit[2] if chkX.checked then ( rootPosX = rootXinit bipPosX = posInit[1] + (bipos[1] - rootXinit) ) if chkY.checked then ( rootPosY = rootYinit bipPosY = posInit[2] + (bipos[2] - rootYinit) ) rootObj.pos = [rootPosX,rootPosY,rootZinit] biped.setcurrentlayer bipObj.controller 1 Biped.setTransform bipObj #pos [bipPosX,bipPosY,bipos[3]] on biped.setcurrentlayer bipObj.controller 0 ) ) progBar.value = 100.0*i/(animationrange.end.frame - animationrange.start.frame) ) ) -- end rootKey 1 else ( -- ### FIRST AND LAST FRAMES if rootKeys.state == 3 then ( for i in animationrange.start.frame to animationrange.end.frame by (animationrange.end.frame - animationrange.start.frame) do ( at time i ( bipos = Biped.getTransform bipObj #pos -- correct long zero floats if (findstring (bipos[1] as string) "e") != undefined do ( bipos = #(0, bipos[2], bipos[3]) ) if (findstring (bipos[2] as string) "e") != undefined do ( bipos = #(bipos[1], 0, bipos[3]) ) with animate on ( rootPosX = bipos[1] rootPosY = bipos[2] bipPosX = posInit[1] bipPosY = posInit[2] if chkX.checked then ( rootPosX = rootXinit bipPosX = posInit[1] + (bipos[1] - rootXinit) ) if chkY.checked then ( rootPosY = rootYinit bipPosY = posInit[2] + (bipos[2] - rootYinit) ) rootObj.pos = [rootPosX,rootPosY,rootZinit] biped.setcurrentlayer bipObj.controller 1 Biped.setTransform bipObj #pos [bipPosX,bipPosY,bipos[3]] on biped.setcurrentlayer bipObj.controller 0 ) ) progBar.value = 100.0*i/(animationrange.end.frame - animationrange.start.frame) ) ) -- end rootKey 3 else ( -- ### FIRST NON-MATCHED if rootKeys.state == 4 then ( at time animationrange.start.frame ( bipos = Biped.getTransform bipObj #pos -- correct long zero floats if (findstring (bipos[1] as string) "e") != undefined do ( bipos = #(0, bipos[2], bipos[3]) ) if (findstring (bipos[2] as string) "e") != undefined do ( bipos = #(bipos[1], 0, bipos[3]) ) with animate on ( addNewKey rootObj.pos.controller animationrange.start.frame rootObj.pos = rootInitpos biped.setcurrentlayer bipObj.controller 1 Biped.setTransform bipObj #pos [posInit[1],posInit[2],bipos[3]] on biped.setcurrentlayer bipObj.controller 0 ) ) progBar.value = 0 at time animationrange.end.frame ( bipos = Biped.getTransform bipObj #pos -- correct long zero floats if (findstring (bipos[1] as string) "e") != undefined do ( bipos = #(0, bipos[2], bipos[3]) ) if (findstring (bipos[2] as string) "e") != undefined do ( bipos = #(bipos[1], 0, bipos[3]) ) with animate on ( rootObj.pos = [bipos[1],bipos[2],rootZinit] biped.setcurrentlayer bipObj.controller 1 Biped.setTransform bipObj #pos [rootInitpos[1],rootInitpos[2],bipos[3]] on biped.setcurrentlayer bipObj.controller 0 ) ) progBar.value = 100 ) -- end rootKey 4 else ( -- ### STATIC ROOT if rootKeys.state == 5 then ( BipDimNew = bipObj.max - bipObj.min -- basing root size off of biped size: rootObjTemp1 = box length:(BipDimNew[1] * 2) width:(BipDimNew[1] * 2) height:((BipDimNew[1] * 2)/1.5) name:"!root_TEMP1" boxmode:on rootObjTemp2 = box length:(BipDimNew[1] * 2) width:(BipDimNew[1] * 2) height:((BipDimNew[1] * 2)/1.5) name:"!root_TEMP2" boxmode:on progBar.value = 0 with animate off ( rootObjTemp1.transform = rootObj.transform rootObjTemp2.transform = rootObj.transform rootObjTemp1.parent = bipObj bipObj.parent = rootObj rootObjTemp1.parent = undefined rootObj.transform = rootObjTemp1.transform bipObj.parent = rootObj rootObj.transform = rootObjTemp2.transform redrawViews() delete rootObjTemp1 delete rootObjTemp2 ) progBar.value = 100 ) -- end rootKey 5 ) -- end not rootKey 4 ) -- end not rootKey 3 ) -- end not rootKey 1 ) -- end not rootKey 2 if rootKeys.state != 5 then --final linking, was just 'bipObj.parent=rootObj', but sometimes the bip would fly out, hence the long way: ( biped.setcurrentlayer bipObj.controller 1 BipDimNew = bipObj.max - bipObj.min -- basing root size off of biped size: rootObjTemp1 = box length:(BipDimNew[1] * 2) width:(BipDimNew[1] * 2) height:((BipDimNew[1] * 2)/1.5) name:"!root_TEMP1" boxmode:on rootObjTemp2 = box length:(BipDimNew[1] * 2) width:(BipDimNew[1] * 2) height:((BipDimNew[1] * 2)/1.5) name:"!root_TEMP2" boxmode:on with animate off ( rootObjTemp1.transform = rootObj.transform rootObjTemp2.transform = rootObj.transform rootObjTemp1.parent = bipObj bipObj.parent = rootObj if rootObjTemp1.pos != rootObjTemp2.pos then ( rootObjTemp1.parent = undefined rootObj.transform = rootObjTemp1.transform bipObj.parent = rootObj rootObj.transform = rootObjTemp2.transform ) delete rootObjTemp1 delete rootObjTemp2 ) ) progBar.value = 100.0 lbl2.enabled = true rootFix.enabled = true slidertime = thisTime setArrowCursor() ) -- end undo ) -- end DoIt on rootFix pressed do ( contFix = 1 if rootKeys.state == 4 then ( contFix = 0 if queryBox ("This function doesn't work well with non-matched first frame" \ + "\nContinue?") title:"Confirm non-matched first frame root fix" then contfix = 1 ) if contFix == 1 do ( with animate off ( bipos = Biped.getTransform bipObj #pos -- correct long zero floats if (findstring (bipos[1] as string) "e") != undefined do ( bipos = #(0, bipos[2], bipos[3]) ) if (findstring (bipos[2] as string) "e") != undefined do ( bipos = #(bipos[1], 0, bipos[3]) ) bipObj.parent = undefined --redrawViews() --not needed anymore rootObj.pos = [bipos[1],bipos[2],rootZinit] bipObj.parent = rootObj rootObj.pos = [0,0,0] ) ) ) ) -- end rollout createdialog bip2root 230 327 )