1. The reason for making the conversion tool
Hello everyone, I am Zhao. I often get some character models from various sources. After I get these models, I will find that they have skins, bones, and even motions.
However, many of these resources are intercepted from the game. After being imported into 3DsMax, the bones of the character are bone type, not biped type. Anyone who is familiar with 3DsMax should know that the bone type needs to reconnect the IK by itself. If the bone is biped, it will be more convenient to use. So I have been looking for a tool that can convert bone bones to biped bones. I found some tools on the Internet, which can also be used, but I always feel that it is not particularly convenient. So I decided to make one myself.
The full code for this tool is provided at the end. But I want to explain first that I developed this tool in the 3DsMax2018 version, and the support for Maxscript is different in different versions. Since I am free and open source, if you encounter API problems or bugs, please solve them yourself.
By the way, if you have any tools you want to develop, you can also tell me. If it is simple, I can finish it for free and provide open source as an article. If it is complicated, I can also consider whether to charge for production according to my own time.
2. Tool instructions
1. What you need
Here I take a game model of Onmyoji as an example. This is an fbx file of a character model with skin information, imported into 3DsMax.
Take a look at the list of scene objects, and you will find that the bones of this model were originally made with biped, and then some custom bone bones were added.
This kind of skeleton is made of biped, it is relatively easy to restore it to biped, because its structure and naming itself conform to the rules of biped.
However, the bones of many character resource models are not made of biped, because there are many softwares for making 3D resources, not necessarily 3Dsmax, but maya, etc. So I also want to be compatible with other bone situations.
2. Tool introduction interface
After running the script, you will see an interface consisting of 5 collapsible windows.
The first one is the About window. Its content first displays the author's information, and then there are 4
interfaces behind the simple steps of the operation, which correspond to the 4 major steps of the next operation. Next, I will explain one by one
1. Specify the bones of the biped architecture
This tool window is the process of specifying the bones that are necessary for biped creation. You can see that there is a BoneList list above. The first column lists all the bone parts supported by the biped skeleton, and the second column uses asterisks to mark which parts are necessary. Because as the basic part of biped, without these bones, it cannot be generated.
This specified step can be divided into automatic and manual operations
(1) If the original bone is made by biped, then you can select the root node of the bone, and then click the SelectAndFit button, it will automatically traverse all the original bones, and according to The name of the bone, to match the part of the biped
(2) If the original bone name is not in accordance with the biped rules, you can also specify it manually. The specific operation is to select the root node of the bone and click the Select button. Next, first in the Select the bone object to be specified in the scene, and then click the corresponding bone part in the list. If you want to cancel the assignment of a certain bone, you can double-click the bone part in the list.
For the second case of manual specification, because it is not easy to specify once, I also provide the function of saving and reading. After specifying, you can click the Save button. At this time, a window to save the file will open, allowing the user to select the file to be saved. The file uses the csv format. When you want to continue editing next time, first use the Select button to select the root node of the bone, and then click the Load button. At this time, a selection window for reading the file will open. Select the previously saved csv file, and you can upload the last result read came in.
2. Specify a custom bone
Since the bones of the character are not necessarily all biped parts, there can also be many custom bone parts, such as the skirt of the clothes, the bones of the weapon, etc., so after specifying the biped bones, you can also specify custom bone parts skeleton. Of course, if not, you can also leave it unspecified.
This operation must be done after the biped bone is specified or read in the first step, because it is also necessary to determine the type of the parent node of the custom bone.
The operation is also divided into two situations: automatic and manual
(1) If you want to use the custom function, after specifying the biped bone, select the root node of the original bone, and then click the Select And Check button. At this time, the tool will traverse under the root node All the nodes in , if they are not biped bones that have been specified before, are considered as custom bones.
(2) You can also manually specify some bones, and then click the Select And Add button to add them to the list. This function has deduplication, so if the bone has been added before, it will not be added repeatedly.
(3) Click the Clean button to clear all the specified custom bones, or double-click the bone name in the list to delete a single bone.
3. Create a new bone
After specifying the bones and custom bones of the biped part, you can generate a new biped bone
In the Bone Controller panel, after entering the name of the biped to be generated, you can select One Key Create to create a biped and a custom bone with one click, and then automatically align their positions. If you don’t want to use one key, you can also manually generate step by step
. Create Biped Only button to generate biped alone and Create Bones Only button to generate custom bone bones, and then use the ResizeBones button to manually align the bone position.
If it has been generated before, you can also specify the generated biped bone by selecting the new biped root node and clicking the SelectBiped button when continuing to operate.
This is the state of the model after the biped and custom bones have been generated. It can be seen that the newly generated bones are just aligned with the original model.
4. Skinning operation
After the skeleton is generated, the skinning operation can be performed.
Since a model may be composed of multiple mesh parts, here you can single-select or multi-select the skinning meshes to be copied, and then click the Add button. Add it to the list. You can also select the grid that has been added, and then click the Remove button to remove it.
Finally click the ReSkin button, the tool will copy the selected skin meshes, read their skin information, and transfer them to the newly generated bones.
This is the result after skinning. It can be seen that the newly generated mesh model can accurately follow the movement of the newly generated bones.
3. The principle of the tool
This version of the tool, I deliberately divided the steps according to the principle of thinking. From the tool, we can see that the whole process is divided into the following steps: 1. Raw bone data collection 2.
Generate
a new Biped
3. Align the bones
4. Obtain skinning information
5. Re-skinning
Now let's talk about the implementation of these steps in detail:
1. Raw skeleton data collection
Before collecting data, we must at least know what data needs to be collected.
Let’s take a look at the statement of creating a Biped in MaxScript:
biped.createNew <height_float> <angle_float> <wpos_point3> . . .
There are 3 data that are required:
1. Bone height
2. Rotation angle
3. World coordinates
followed by ellipsis, These are some optional parameters. In fact, they are all
bone parameters in Figure Mode in 3DsMax :
How do we know these parameters? We can only guess these parameters from the original bone bone. Therefore, the user must first specify the root bone of the original bone, and then read these bones through traversal.
1. Get a certain number of joints
From the specified Biped parts, the number of each bone part can be judged, such as Spine bones. If you judge how many Spine parts have specified bones, then the number of Spines can be obtained, and the same is true for other fingers and toes.
2.Triangle Pelvis和Triangle Neck
These two options will lead to changes in the tree structure of the bones.
If Triangle Pelvis is checked, L Thigh and R Thigh will be in the next layer of Spine
If Triangle Pelvis is unchecked, L Thigh and R Thigh will be on the same layer of Spine, and both are on the next layer of Pelvis
If Triangle Neck is checked, L Clavicle and R Clavicle will be on the same floor as Neck
If Triangle Neck is unchecked, L Clavicle and R Clavicle will be on the next layer of Neck
After knowing this relationship, when we collect bone information, we must pay special attention to the parent-child relationship of these bones to see which one they belong to.
3. How to get the height
In fact, there is no way to obtain the height, because the height here is literally the height from the top of the human skeleton to the sole of the foot. But our original bones have no thickness, so we can only calculate the coordinate position of the highest bone, not the top.
But the problem is not big, because the bone alignment will be used to modify the bone position below, so I got the distance from the Head to the Foot of the biped bone, as the height, which is equivalent to giving the bone a rough default value.
4. About rotation angle and coordinates
Because the bones will be aligned again below, the position and rotation are not important, just give a default value first.
5. Storage of bones
Since the tool has been divided into a list of biped parts and custom bones, I used two Struct structures to store the data structures of biped and custom bones.
2. Generate a new Biped
Through the above data collection, we have obtained the parameters necessary to create Biped.
Biped can be created by biped.createNew method.
local bipedHeight = maxHeight - minHeight
newBipedObj = biped.createNew bipedHeight -90 [0,0,0] \
arms:needArm \
neckLinks:neckNum \
spineLinks:spineNum \
legLinks:legNum \
tailLinks:tailNum \
ponyTail1Links:ponyTail1Num \
ponyTail2Links:ponyTail2Num \
fingers:fingerNum \
fingerLinks:fingerLinkNum \
toes:toeNum \
toeLinks:toeLinkNum \
trianglePelvis:needTrianglePelvis \
triangleNeck:needTriangleNeck \
prop1Exists:needProps1 \
prop2Exists:needProps2 \
prop3Exists:needProps3
newBipedObj.controller.rootName = bipedName
There are 2 points worth noting:
1. If you want to change the name of the entire Biped together, such as changing from Bip001 to Bip002, it is not to traverse all the bones to change the name attribute object by object, but to get the controller of the Biped, and then modify the rootName, so that the whole The names of all biped nodes will change accordingly.
2. This step creates only the Biped part. In fact, many character models will add some bone-type bones as details on the basis of Biped, and these bone bones have not been generated in this step. Since the positions of these bones follow the normal biped bones, we will generate them after the biped bones are generated.
3. Align the bones
This step seems to be very simple, isn't it that each bone finds the bone with the same name as the original bone, and then copies the displacement, rotation and scaling information?
In fact, this is not the case, because:
1. In Biped, some bones can be moved directly, and some bones are moved by parent-child connection and IK. So if you directly set the position coordinates of the bones, many bones will not take effect. There are not many bones that can directly set the position coordinates, only the root bone, the neck, the left and right shoulders, the first Spine, the first joints of the fingers and toes.
2. The imported bone bone has a zoom of 1, but the biped bone zoom is not 1, which cannot be set according to the bone.
From this point of view, apart from the rotation information, there seems to be no information that can be directly set.
But the problem is not insoluble. Actually the above 2 questions are the same question. If we want to manually adapt the position of the bone, the normal way is to enter Figure Mode first, and then zoom in and out of the parent bone to an appropriate size to achieve the purpose of adjusting the position of the child bone. If you use scripts to operate, it is actually the same, you only need to calculate the scaling of the bones.
The calculation method is to calculate the distance between the coordinates of the parent bone and the coordinates of the child bone in the past, and this distance is the scaling value of the parent bone.
However, not all bones are calculated and scaled in this way. Here are several situations:
1. The root bone does not need to be scaled.
2. Pelvis of the pelvis, no matter what its parent-child structure is, its scaling is the distance from Pelvis to one of the thighs Thigh Multiply by 2
3. The last bone of the sternal spine does not need to be scaled, because its child bones can directly set the coordinates, and do not need to rely on the parent's scale to determine the position. The same is true for other children who can directly set the coordinates of the bones.
There is one more thing to pay attention to here. Biped objects cannot directly obtain information such as pos. They must first obtain transform, and then obtain pos, rotation, and scale.
4. Obtain skin information
For a skinned model, you need to get its skinned bone list first.
There is a point to note here. There are 2 lists of bones in the Skin, one is sorted according to the order of the UI display list, and the other is the actual bone Id during skin calculation. We should pay attention to the fact that what needs to be obtained is the actual bone Id, not the id that the UI shows sorted by.
So we need to get the number in the skin bone list through the skinOps.GetNumberBones method first, and then get the bone name of a certain bone id through the skinOps.GetBoneName method, and then save it.
The next step is to obtain information vertex by vertex.
There are 2 pieces of information that need to be obtained in a vertex skinning information:
1. How many bones are affected by a vertex
. 2. What is the weight of each bone that a vertex receives.
Here I also use the Struct structure to record the skin bone list and vertex skin weight information of a skinned mesh.
5. Re-skinning
Since we have the skinning information from the previous step, copy the original skinning mesh, add the Skin modifier, and then assign the skinning information to the new skinning mesh.
Fourth, the complete code:
(
--ui
local HelpWin
local BoneListWin
local CustomBoneListWin
local BoneCtrlWin
local SkinCtrlWin
--function
local GetMatch
local AddToBoneDict
local GetBoneInfoByName
local InitBoneList
local FitBoneToBiped
local GetFitName
local CreateBipedFun
local GetBipedHeight
local GetCommonBoneNum
local GetNeckNum
local GetSpineNum
local GetLegNum
local GetTailNum
local GetPonytail1Num
local GetPonytail2Num
local GetFingerNum
local GetFingerLinkNum
local GetToeNum
local GetProp
local CheckNeedArm
local CheckNeedTrianglePelvis
local CheckNeedTriangleNeck
local GetBipedName
local AddToCustomBoneDict
local GetCustomBoneInfoByName
local CheckCustomBone
local CheckOneCustomBone
local CleanCustomBone
local UpdateCustomBoneList
local CheckBoneIsBiped
local CheckNewBipedObj
local FitBoneToOrig
local CreateCustomBone
local ResizeNewBipedFun
local ResizeBoneFun
local RePositionBoneFun
local ResizeOneBone
local SaveBoneListFun
local LoadBoneListFun
local GetSaveBoneListPathFun
local GetLoadBoneListPathFun
local LoadBoneListFitOneBone
local GetSubBoneByName
local AddCustomBoneToList
local AddOneCustomBoneToList
local CheckSelectionIsBipedRoot
local CheckSelectSingleObj
local AddToSkinMeshList
local AddOneObjToSkinMeshList
local RemoveSkinMeshByName
local UpdateSkinMeshList
local SkinFun
local SkinOneMesh
local GetNewBoneByName
local InitNewBipedBoneList
local AddToNewBipedBoneList
local GetNewBipedBoneByName
--var
local mustHaveBoneList = #("root","Pelvis","Spine","L Thigh","L Calf","L Foot",\
"L Toe0","R Thigh","R Calf","R Foot","R Toe0","Neck","L Clavicle","L UpperArm",\
"L Forearm","L Hand","L Finger0","R Clavicle","R UpperArm","R Forearm","R Hand",\
"R Finger0","Head")
local maxBoneList = #("root","Prop1","Prop2","Prop3","Pelvis","Spine","Spine1","Spine2",\
"Spine3","Spine4","Spine5","Spine6","Spine7","Spine8","Spine9","Neck","Neck1","Neck2",\
"Neck3","Neck4","Neck5","Neck6","Neck7","Neck8","Neck9","Neck10","Neck11","Neck12","Neck13",\
"Neck14","Neck15","Neck16","Neck17","Neck18","Neck19","Neck20","Neck21","Neck22","Neck23",\
"Neck24","Head","Ponytail1","Ponytail11","Ponytail12","Ponytail13","Ponytail14","Ponytail15",\
"Ponytail16","Ponytail17","Ponytail18","Ponytail19","Ponytail110","Ponytail111","Ponytail112",\
"Ponytail113","Ponytail114","Ponytail115","Ponytail116","Ponytail117","Ponytail118","Ponytail119",\
"Ponytail120","Ponytail121","Ponytail122","Ponytail123","Ponytail124","Ponytail2","Ponytail21",\
"Ponytail22","Ponytail23","Ponytail24","Ponytail25","Ponytail26","Ponytail27","Ponytail28",\
"Ponytail29","Ponytail210","Ponytail211","Ponytail212","Ponytail213","Ponytail214","Ponytail215",\
"Ponytail216","Ponytail217","Ponytail218","Ponytail219","Ponytail220","Ponytail221","Ponytail222",\
"Ponytail223","Ponytail224","L Clavicle","L UpperArm","L Forearm","L Hand","L Finger0","L Finger01",\
"L Finger02","L Finger03","L Finger1","L Finger11","L Finger12","L Finger13","L Finger2","L Finger21",\
"L Finger22","L Finger23","L Finger3","L Finger31","L Finger32","L Finger33","L Finger4","L Finger41",\
"L Finger42","L Finger43","R Clavicle","R UpperArm","R Forearm","R Hand","R Finger0","R Finger01",\
"R Finger02","R Finger03","R Finger1","R Finger11","R Finger12","R Finger13","R Finger2","R Finger21",\
"R Finger22","R Finger23","R Finger3","R Finger31","R Finger32","R Finger33","R Finger4","R Finger41",\
"R Finger42","R Finger43","L Thigh","L Calf","L HorseLink","L Foot","L Toe0","L Toe01","L Toe02",\
"L Toe1","L Toe11","L Toe12","L Toe2","L Toe21","L Toe22","L Toe3","L Toe31","L Toe32","L Toe4",\
"L Toe41","L Toe42","R Thigh","R Calf","R HorseLink","R Foot","R Toe0","R Toe01","R Toe02","R Toe1",\
"R Toe11","R Toe12","R Toe2","R Toe21","R Toe22","R Toe3","R Toe31","R Toe32","R Toe4","R Toe41",\
"R Toe42","Tail","Tail1","Tail2","Tail3","Tail4","Tail5","Tail6","Tail7","Tail8","Tail9","Tail10",\
"Tail11","Tail12","Tail13","Tail14","Tail15","Tail16","Tail17","Tail18","Tail19","Tail20","Tail21",\
"Tail22","Tail23","Tail24")
local boneInfoDict
local selectedBoneRootObj
local bipedName
local newBipedObj
local customBoneInfoDict
local customBoneNameList
local skinMeshList
local skinInfoList
local newBipedObjNameList
local newBipedObjDict
--struct
struct VertexSkinInfo
(
public
index,
boneIdList,
weightList,
fn AddWeightInfo id val =
(
if this.weightList == undefined then
(
this.weightList = #()
)
if this.boneIdList == undefined then
(
this.boneIdList = #()
)
append this.boneIdList id
append this.weightList val
)
)
struct MeshSkinInfo
(
skinObj,
boneNameList,
vertexInfoList,
fn AddVertexInfo info =
(
if vertexInfoList == undefined then
(
vertexInfoList = #()
)
append vertexInfoList info
),
fn SetData skinMeshObj =
(
if skinMeshObj == undefined then
return 0
this.skinObj = skinMeshObj
select skinMeshObj
local oldModSkin = skinMeshObj.modifiers[Skin]
if oldModSkin == undefined then
(
print "No Skin on the object"
return 0
)
max modify mode
modPanel.setCurrentObject oldModSkin
local boneNum = skinOps.GetNumberBones oldModSkin
this.boneNameList = #()
for i in 1 to boneNum do
(
local boneName = skinOps.GetBoneName oldModSkin i 1
append this.boneNameList boneName
)
local vertexNum = GetNumVerts skinMeshObj.mesh
this.vertexInfoList = #()
for i in 1 to vertexNum do
(
local oneVertInfo = VertexSkinInfo()
oneVertInfo.index = i
local skinBoneNum = skinOps.GetVertexWeightCount oldModSkin i
for j in 1 to skinBoneNum do
(
local tempBoneId = skinOps.GetVertexWeightBoneID oldModSkin i j
local tempWeight = skinOps.GetVertexWeight oldModSkin i j
oneVertInfo.AddWeightInfo tempBoneId tempWeight
)
append this.vertexInfoList oneVertInfo
)
)
)
struct CustomBoneInfoObj
(
public
name,
pos,
rotation,
scale,
selectBone,
newBone,
parentName,
parentIsBiped,
fn SetData obj =
(
this.selectBone = obj
this.name = obj.name
this.pos = obj.transform.pos
this.rotation = obj.transform.rotation
this.scale = obj.transform.scale
if obj.parent != undefined then
(
local bipedBoneName = CheckBoneIsBiped obj.parent
if bipedBoneName != undefined then
(
this.parentName = bipedBoneName
this.parentIsBiped = true
)
else
(
this.parentName = obj.parent.name
this.parentIsBiped = false
)
)
else
(
this.parentName = undefined
this.parentIsBiped = false
)
),
fn SetNewBone val =
(
this.newBone = val
)
)
struct BoneInfoObj
(
public
name,
isMust,
selectBone,
newBone,
pos,
rotation,
scale,
row,
fn GetShowName =
(
return this.name
),
fn GetMust =
(
if this.isMust == true then
return "*"
else
return ""
),
fn SetName val =
(
this.name = val
local index = findItem mustHaveBoneList val
if index >0 then
(
this.isMust = true
)
else
(
this.isMust = false
)
),
fn SetSelectBone val =
(
this.selectBone = val
if this.selectBone != undefined then
(
this.pos = val.transform.pos
this.rotation = val.transform.rotation
this.scale = val.transform.scale
)
else
(
this.pos = undefined
this.rotation = undefined
this.scale = undefined
)
this.UpdateRow()
),
fn SetNewBone val =
(
this.newBone = val
),
fn SetRow val =
(
this.row = val
),
fn UpdateRow =
(
if this.row != undefined then
(
local content = "";
if this.selectBone != undefined then
(
content = this.selectBone.name
)
this.row.subItems.item[2].text = content
)
)
)
--tool function
fn GetMatch str1 str2 =
(
local regexStr = "*"+str2+"*"
return matchPattern str1 pattern:regexStr
)
fn GetMatchEnd str1 str2 =
(
local regexStr = "*"+str2
return matchPattern str1 pattern:regexStr
)
fn AddToBoneDict info =
(
if boneInfoDict == undefined then
(
boneInfoDict = #()
)
local index = findItem maxBoneList info.name
if index> 0 then
(
boneInfoDict[index] = info
)
)
fn GetBoneInfoByName val =
(
if boneInfoDict == undefined then
(
return undefined
)
local index = findItem maxBoneList val
if index > 0 then
return boneInfoDict[index]
else
return undefined
)
fn AddToCustomBoneDict info =
(
if customBoneInfoDict == undefined then
(
customBoneInfoDict = #()
)
if customBoneNameList == undefined then
(
customBoneNameList = #()
)
local index = findItem customBoneNameList info.name
if index >0 then
(
customBoneInfoDict[index] = info
)
else
(
append customBoneNameList info.name
append customBoneInfoDict info
)
)
fn GetCustomBoneInfoByName val =
(
if customBoneNameList == undefined or customBoneInfoDict == undefined then
(
return undefined
)
local index = findItem customBoneNameList val
if index > 0 then
(
return customBoneInfoDict[index]
)
else
(
return undefined
)
)
fn RemoveCustomBoneInfoByName val =
(
if customBoneNameList == undefined or customBoneInfoDict == undefined then
(
return 0
)
local index = findItem customBoneNameList val
if index < 0 then
(
return 0
)
deleteItem customBoneNameList index
deleteItem customBoneInfoDict index
UpdateCustomBoneList()
)
fn CheckBoneIsBiped obj =
(
local curName = undefined
for i in 1 to boneInfoDict.count do
(
local info = boneInfoDict[i]
if info.selectBone != undefined and info.selectBone == obj then
(
curName = info.name
break
)
)
return curName
)
--ui function
fn InitBoneList =
(
boneInfoDict = #()
for i in 1 to maxBoneList.count do
(
local info = BoneInfoObj()
info.SetName maxBoneList[i]
AddToBoneDict info
)
)
fn ShowMsg msg =
(
MessageBox msg title:"Tips"
)
fn GetFitBoneInfo val =
(
local index = 0
local newName = val
if newName != "root" then
newName = replace val 1 (bipedName.count+1) ""
for i in 1 to maxBoneList.count do
(
if newName == maxBoneList[i] then
(
index = i
break
)
)
if index >0 then
(
return boneInfoDict[index]
)
else
(
return undefined
)
)
fn FitBoneToBiped obj =
(
local objName = obj.name
if objName == bipedName then
(
objName = "root"
)
local info = GetFitBoneInfo objName
if info != undefined then
info.SetSelectBone obj
local childrenList = obj.children
if childrenList != undefined and childrenList.count >0 then
(
for i in 1 to childrenList.count do
(
FitBoneToBiped childrenList[i]
)
)
)
fn FitBoneToOrig obj =
(
local objName = obj.name
if objName == bipedName then
(
objName = "root"
)
local boneType = classof obj
if boneType!= Dummy and (GetMatch objName "Footstep") == false then
(
if boneType == Biped_Object then
(
local info = GetFitBoneInfo objName
if info != undefined then
info.SetNewBone obj
)
else
(
local info = GetCustomBoneInfoByName objName
if info != undefined then
info.SetNewBone obj
)
)
local childrenList = obj.children
if childrenList != undefined and childrenList.count >0 then
(
for i in 1 to childrenList.count do
(
FitBoneToOrig childrenList[i]
)
)
)
fn CheckMustBone =
(
for item in boneInfoDict do
(
if item.isMust == true and item.selectBone == undefined then
(
return item.name
)
)
return undefined
)
fn GetBipedHeight =
(
local headInfo = GetBoneInfoByName("Head")
local footInfo = GetBoneInfoByName("L Foot")
return (distance headInfo.pos footInfo.pos)
)
fn GetCommonBoneNum name1 name2 =
(
local indexStart = findItem maxBoneList name1
local indexEnd = findItem maxBoneList name2
local num = 0;
for i in indexStart to indexEnd do
(
local curName = maxBoneList[i]
local info = GetBoneInfoByName(curName)
if info != undefined and info.selectBone != undefined then
(
num = num +1
)
)
return num
)
fn GetNeckNum =
(
return GetCommonBoneNum "Neck" "Neck24"
)
fn GetSpineNum =
(
return GetCommonBoneNum "Spine" "Spine9"
)
fn GetLegNum =
(
local num = 3
local info = GetBoneInfoByName "L HorseLink"
if info != undefined and info.selectBone!=undefined then
(
num = 4
)
return num
)
fn GetTailNum =
(
return GetCommonBoneNum "Tail" "Tail24"
)
fn GetPonytail1Num =
(
return GetCommonBoneNum "Ponytail1" "Ponytail124"
)
fn GetPonytail2Num =
(
return GetCommonBoneNum "Ponytail2" "Ponytail224"
)
fn GetFingerNum =
(
local info = GetBoneInfoByName "L Finger4"
if info != undefined and info.selectBone != undefined then
(
return 5
)
info = GetBoneInfoByName "L Finger3"
if info != undefined and info.selectBone != undefined then
(
return 4
)
info = GetBoneInfoByName "L Finger2"
if info != undefined and info.selectBone != undefined then
(
return 3
)
info = GetBoneInfoByName "L Finger1"
if info != undefined and info.selectBone != undefined then
(
return 2
)
info = GetBoneInfoByName "L Finger0"
if info != undefined and info.selectBone != undefined then
(
return 1
)
return 0
)
fn GetFingerLinkNum =
(
return GetCommonBoneNum "L Finger0" "L Finger03"
)
fn GetToeNum =
(
local info = GetBoneInfoByName "L Toe4"
if info != undefined and info.selectBone != undefined then
(
return 5
)
info = GetBoneInfoByName "L Toe3"
if info != undefined and info.selectBone != undefined then
(
return 4
)
info = GetBoneInfoByName "L Toe2"
if info != undefined and info.selectBone != undefined then
(
return 3
)
info = GetBoneInfoByName "L Toe1"
if info != undefined and info.selectBone != undefined then
(
return 2
)
info = GetBoneInfoByName "L Toe0"
if info != undefined and info.selectBone != undefined then
(
return 1
)
return 0
)
fn GetToeLinkNum =
(
return GetCommonBoneNum "L Toe0" "L Toe02"
)
fn GetProp val =
(
if val == 1 then
(
info = GetBoneInfoByName "Prop1"
if info != undefined and info.selectBone != undefined then
(
return true
)
else
(
return false
)
)
else if val == 2 then
(
info = GetBoneInfoByName "Prop2"
if info != undefined and info.selectBone != undefined then
(
return true
)
else
(
return false
)
)
else if val == 3 then
(
info = GetBoneInfoByName "Prop3"
if info != undefined and info.selectBone != undefined then
(
return true
)
else
(
return false
)
)
else
(
return false
)
)
fn CheckNeedArm =
(
info = GetBoneInfoByName "L UpperArm"
if info != undefined and info.selectBone != undefined then
(
return true
)
else
(
return false
)
)
fn CheckNeedTrianglePelvis =
(
local result = false;
local thighInfo = GetBoneInfoByName "L Thigh"
local spineInfo = GetBoneInfoByName "Spine"
if thighInfo!= undefined and thighInfo.selectBone != undefined then
(
if spineInfo!= undefined and spineInfo.selectBone != undefined then
(
if thighInfo.selectBone.parent == spineInfo.selectBone then
(
result = true
)
)
)
return result
)
fn CheckNeedTriangleNeck =
(
local result = true;
local clavicleInfo = GetBoneInfoByName "L Clavicle"
local neckInfo = GetBoneInfoByName "Neck"
if clavicleInfo!= undefined and clavicleInfo.selectBone != undefined then
(
if neckInfo!= undefined and neckInfo.selectBone != undefined then
(
if clavicleInfo.selectBone.parent == neckInfo.selectBone then
(
result = false
)
)
)
return result
)
fn CreateBipedFun =
(
local missingName = CheckMustBone()
if missingName != undefined then
(
ShowMsg("MustNeed Bone Missing:"+missingName)
return 0
)
local bipedHeight = GetBipedHeight()
local numNum = GetNeckNum()
local neckNum = GetNeckNum()
local spineNum = GetSpineNum()
local legNum = GetLegNum()
local tailNum = GetTailNum()
local ponytail1Num = GetPonytail1Num()
local ponytail2Num = GetPonytail2Num()
local fingerNum = GetFingerNum()
local fingerLinkNum = GetFingerLinkNum()
local toeNum = GetToeNum()
local toeLinkNum = GetToeLinkNum()
local needProp1 = GetProp 1
local needProp2 = GetProp 2
local needProp3 = GetProp 3
local needArm = CheckNeedArm()
local needTrianglePelvis = CheckNeedTrianglePelvis()
local needTriangleNeck = CheckNeedTriangleNeck()
newBipedObj = biped.createNew bipedHeight -90 [0,0,0] \
arms:needArm \
neckLinks:neckNum \
spineLinks:spineNum \
legLinks:legNum \
tailLinks:tailNum \
ponyTail1Links:ponytail1Num \
ponyTail2Links:ponytail2Num \
fingers:fingerNum \
fingerLinks:fingerLinkNum \
toes:toeNum \
toeLinks:toeLinkNum \
trianglePelvis:needTrianglePelvis \
triangleNeck:needTriangleNeck \
prop1Exists:needProp1 \
prop2Exists:needProp2 \
prop3Exists:needProp3
newBipedObj.controller.rootName = GetBipedName()
FitBoneToOrig newBipedObj
)
fn SetBipedName val =
(
bipedName = val
BoneCtrlWin.bipedNameTxt.text = val
)
fn GetBipedName =
(
return BoneCtrlWin.bipedNameTxt.text
)
fn CheckCustomBone =
(
if selectedBoneRootObj == undefined then
(
ShowMsg("Please select boneRootFirst!")
return 0
)
customBoneInfoDict = #()
customBoneNameList = #()
CheckOneCustomBone selectedBoneRootObj
UpdateCustomBoneList()
)
fn CheckOneCustomBone obj =
(
if (classof obj)!= Dummy and (GetMatch obj.name "Footstep") == false and (GetMatchEnd obj.name "Nub") == false then
(
local bipedBoneName = CheckBoneIsBiped obj
if bipedBoneName == undefined then
(
local info = CustomBoneInfoObj()
info.SetData obj
AddToCustomBoneDict info
)
)
local childrenList = obj.children
if childrenList != undefined and childrenList.count >0 then
(
for i in 1 to childrenList.count do
(
CheckOneCustomBone childrenList[i]
)
)
)
fn CleanCustomBone =
(
customBoneInfoDict = #()
customBoneNameList = #()
UpdateCustomBoneList()
)
fn UpdateCustomBoneList =
(
CustomBoneListWin.boneDataList.Clear()
CustomBoneListWin.boneDataList.Fullrowselect = true
CustomBoneListWin.boneDataList.GridLines = true
CustomBoneListWin.boneDataList.View = CustomBoneListWin.boneDataList.View.Details
if customBoneInfoDict == undefined or customBoneInfoDict.count <=0 then
(
return 0
)
CustomBoneListWin.boneDataList.Columns.Add "BoneName" 100
CustomBoneListWin.boneDataList.Columns.Add "parentType" 100
CustomBoneListWin.boneDataList.Columns.Add "parentName" 200
for i = 1 to customBoneInfoDict.count do
(
local info = customBoneInfoDict[i]
row = dotNetObject "System.Windows.Forms.ListViewItem"
row.Text = info.name
local parentType = ""
local parentName = ""
if info.parentName != undefined then
(
parentName = info.parentName
if info.parentIsBiped == true then
(
parentType = "biped"
)
else
(
parentType = "bone"
)
)
row.SubItems.Add(parentType)
row.SubItems.Add(parentName)
CustomBoneListWin.boneDataList.Items.Add(row)
)
)
fn CheckNewBipedObj =
(
if newBipedObj == undefined then
(
ShowMsg "Please create biped or select biped first"
return 0
)
FitBoneToOrig newBipedObj
)
fn CreateCustomBone =
(
if customBoneInfoDict == undefined and customBoneInfoDict.count == 0 then
(
return 0
)
for i in 1 to customBoneInfoDict.count do
(
local info = customBoneInfoDict[i]
if info.selectBone != undefined then
(
local newBone = copy info.selectBone
newBone.name = info.selectBone.name
info.SetNewBone newBone
if info.parentName != undefined then
(
if info.parentIsBiped == true then
(
local parentInfo = GetBoneInfoByName info.parentName
if parentInfo != undefined and parentInfo.newBone != undefined then
(
newBone.parent = parentInfo.newBone
)
)
else
(
local parentInfo = GetCustomBoneInfoByName info.parentName
if parentInfo != undefined and parentInfo.newBone != undefined then
(
newBone.parent = parentInfo.newBone
)
)
)
)
)
)
fn ResizeNewBipedFun =
(
if newBipedObj == undefined then
(
ShowMsg "Please create biped or select biped first"
return 0
)
newBipedObj.controller.figureMode = true
ResizeBoneFun newBipedObj
RePositionBoneFun()
newBipedObj.controller.figureMode = false
)
fn ResizeBoneFun obj =
(
local objName = obj.name
if objName == bipedName then
(
objName = "root"
)
local boneType = classof obj
if boneType!= Dummy and (GetMatch objName "Footstep") == false then
(
if boneType == Biped_Object then
(
local info = GetFitBoneInfo objName
ResizeOneBone info
)
)
local childrenList = obj.children
if childrenList != undefined and childrenList.count >0 then
(
for i in 1 to childrenList.count do
(
ResizeBoneFun childrenList[i]
)
)
)
fn ResizeOneBone info =
(
if info.selectBone == undefined or info.newBone == undefined then
return 0
local childrenList =info.selectBone.children
if childrenList == undefined or childrenList.count ==0 then
(
return 0
)
if info.name == "root" then
return 0
if info.name == "L Foot" or info.name == "R Foot" then
return 0
if info.name == "Pelvis" then
(
local nextInfo = GetBoneInfoByName "L Thigh"
if nextInfo != undefined then
(
local tempScale = distance info.pos nextInfo.pos
tempScale = tempScale*2
biped.setTransform info.newBone #scale [tempScale,tempScale,tempScale] true
)
)
else
(
if (GetMatch info.name "Spine") == true then
(
if (GetMatch childrenList[1].name "Spine") == false then
(
return 0
)
)
local maxVal = 0
for i in 1 to childrenList.count do
(
local tempVal = distance info.pos childrenList[i].transform.pos
if tempVal >maxVal then
maxVal = tempVal
)
if maxVal > 0 then
(
biped.setTransform info.newBone #scale [maxVal,maxVal,maxVal] true
)
)
)
fn RePositionBoneFun =
(
if boneInfoDict != undefined and boneInfoDict.count >0 then
(
for i in 1 to boneInfoDict.count do
(
local info = boneInfoDict[i]
if info.selectBone != undefined and info.newBone != undefined then
(
biped.setTransform info.newBone #pos info.pos true
biped.setTransform info.newBone #rotation info.rotation true
biped.setTransform info.newBone #pos info.pos true
biped.setTransform info.newBone #rotation info.rotation true
)
)
)
if customBoneInfoDict != undefined and customBoneInfoDict.count >0 then
(
for i in 1 to customBoneInfoDict.count do
(
local info = customBoneInfoDict[i]
if info.selectBone != undefined and info.newBone != undefined then
(
info.newBone.pos = info.selectBone.pos
info.newBone.rotation = info.selectBone.rotation
info.newBone.scale = info.selectBone.scale
)
)
)
)
fn GetSaveBoneListPathFun =
(
local savePath = getSaveFileName types:"csv(*.csv)|*csv"
if savePath == undefined then
(
return undefined
)
if (matchPattern savePath pattern:"*.csv") == false then
(
savePath+=".csv"
)
return savePath
)
fn SaveBoneListFun =
(
if boneInfoDict == undefined or boneInfoDict.count == 0 then
(
ShowMsg("No data can save!")
return 0
)
local savePath = GetSaveBoneListPathFun()
if savePath == undefined then
(
return 0
)
local content = "";
for i in 1 to boneInfoDict.count do
(
local info = boneInfoDict[i]
if info.selectBone != undefined then
(
content+=info.name+","+info.selectBone.name
content += "\n"
)
)
if content == "" then
(
ShowMsg("No bone can save,Please assign or autofit bone first!")
return 0
)
local f = createFile savePath
format content to:f
close f
ShowMsg ("save file to :"+savePath)
)
fn GetLoadBoneListPathFun =
(
local loadPath = getOpenFileName types:"csv(*.csv)|*csv"
if loadPath == undefined then
(
return undefined
)
return loadPath
)
fn LoadBoneListFun =
(
if selectedBoneRootObj == undefined then
(
ShowMsg "Please select boneRoot"
return 0
)
local loadPath = GetLoadBoneListPathFun()
if loadPath == undefined then
(
return 0
)
local f = openFile loadPath
local lineList = #()
while not eof f do
(
local lineStr = readLine f
append lineList lineStr
)
close f
for i in 1 to lineList.count do
(
LoadBoneListFitOneBone lineList[i]
)
)
fn LoadBoneListFitOneBone val =
(
if selectedBoneRootObj == undefined then
return 0
local strArr = filterString val ","
if strArr == undefined or strArr.count < 2 then
(
return 0
)
local key = strArr[1]
local boneName = strArr[2]
local info = GetBoneInfoByName key
if info == undefined then
(
return 0
)
local targetBoneObj = GetSubBoneByName selectedBoneRootObj boneName
if targetBoneObj != undefined then
(
info.SetSelectBone targetBoneObj
)
)
fn GetSubBoneByName obj val =
(
if obj.name == val then
return obj
local resultObj = undefined
local childrenList = obj.children
if childrenList != undefined and childrenList.count > 0 then
(
for i in 1 to childrenList.count do
(
local subResult = GetSubBoneByName childrenList[i] val
if subResult != undefined then
(
resultObj = subResult
break
)
)
)
return resultObj
)
fn AddCustomBoneToList =
(
if $ == undefined then
return 0
local tempList = #()
local tempType = classof $
if tempType == ObjectSet then
(
if $.count > 0 then
(
for i in 1 to $.count do
(
append tempList $[i]
)
)
)
else
(
append tempList $
)
if tempList.count == 0 then
return 0
for i in 1 to tempList.count do
(
AddOneCustomBoneToList tempList[i]
)
UpdateCustomBoneList()
)
fn AddOneCustomBoneToList obj =
(
local objType = classOf obj
if objType == Dummy or objType == Biped_Object then
return 0
if customBoneNameList != undefined then
(
local index = findItem customBoneNameList obj.name
if index >0 then
return 0
)
local info = CustomBoneInfoObj()
info.SetData obj
AddToCustomBoneDict(info)
)
fn CheckSelectionIsBipedRoot obj =
(
if obj == undefined then
return false
local objType = classof obj
if objType != Biped_Object then
return false
objType = classof obj.controller
if objType != Vertical_Horizontal_Turn then
return false
return true
)
fn CheckSelectSingleObj obj =
(
if obj == undefined then
return false
local objType = classof obj
if objType == ObjectSet or objType == Dummy then
return false
return true
)
fn AddToSkinMeshList obj =
(
if obj == undefined then
return 0
if skinMeshList == undefined then
skinMeshList = #()
local objType = classof obj
local addList = #()
if objType == ObjectSet then
(
for i in 1 to obj.count do
(
append addList obj[i]
)
)
else
(
append addList obj
)
local realAddList = #()
for i in 1 to addList.count do
(
local subObj = addList[i]
if subObj.modifiers[Skin] != undefined then
(
append realAddList subObj
)
)
if realAddList.count == 0 then
(
ShowMsg "No Skin on selected objs!"
return 0
)
for i in 1 to realAddList.count do
(
AddOneObjToSkinMeshList realAddList[i]
)
UpdateSkinMeshList()
)
fn AddOneObjToSkinMeshList obj =
(
local isExist = false
if skinMeshList.count > 0 then
(
for i in 1 to skinMeshList.count do
(
if skinMeshList[i] == obj then
(
isExist = true
break
)
)
)
if isExist == true then
return 0
append skinMeshList obj
)
fn RemoveSkinMeshByName val =
(
if skinMeshList == undefined or skinMeshList.count == 0 then
return 0
local index = 0
for i in 1 to skinMeshList.count do
(
if skinMeshList[i].name == val then
(
index = i
break
)
)
if index == 0 then
return 0
deleteItem skinMeshList index
UpdateSkinMeshList()
)
fn UpdateSkinMeshList =
(
SkinCtrlWin.skinDataList.Items.clear()
if skinMeshList == undefined or skinMeshList.count ==0 then
return 0
for i in 1 to skinMeshList.count do
(
SkinCtrlWin.skinDataList.Items.Add(skinMeshList[i].name)
)
)
fn InitNewBipedBoneList =
(
newBipedObjNameList = #()
newBipedObjDict = #()
if boneInfoDict == undefined or boneInfoDict.count == 0 then
return 0
for i in 1 to boneInfoDict.count do
(
local info = boneInfoDict[i]
if info.newBone != undefined then
AddToNewBipedBoneList info.selectBone.name info.newBone
)
)
fn AddToNewBipedBoneList val obj =
(
if newBipedObjNameList == undefined then
newBipedObjNameList = #()
if newBipedObjDict == undefined then
newBipedObjDict = #()
append newBipedObjNameList val
append newBipedObjDict obj
)
fn GetNewBipedBoneByName val =
(
if newBipedObjNameList == undefined or newBipedObjDict == undefined then
return undefined
local index = findItem newBipedObjNameList val
if index == 0 then
return undefined
return newBipedObjDict[index]
)
fn SkinFun =
(
if skinMeshList == undefined or skinMeshList.count == 0 then
(
ShowMsg "Please add skinMesh first!"
return 0
)
InitNewBipedBoneList()
skinInfoList = #()
for i in 1 to skinMeshList.count do
(
local info = MeshSkinInfo()
info.SetData skinMeshList[i]
append skinInfoList info
)
for i in 1 to skinInfoList.count do
(
SkinOneMesh skinInfoList[i]
)
)
fn SkinOneMesh info =
(
local newSkinMeshObj = copy info.skinObj
deleteModifier newSkinMeshObj 1
select newSkinMeshObj
ModPanel.addModToSelection(Skin()) ui:on
local modSkin = newSkinMeshObj.modifiers[Skin]
for i in 1 to info.boneNameList.count do
(
local boneNode = GetNewBoneByName info.boneNameList[i]
if boneNode != undefined then
(
skinOps.addbone modSkin boneNode -1
)
)
vertexNum = GetNumVerts newSkinMeshObj.mesh
for i in 1 to vertexNum do
(
--print i
skinOps.SetVertexWeights modSkin i info.vertexInfoList[i].boneIdList info.vertexInfoList[i].weightList
)
)
fn GetNewBoneByName val =
(
local info = GetCustomBoneInfoByName val
if info != undefined then
return info.newBone
local bipedBoneObj = GetNewBipedBoneByName val
if bipedBoneObj != undefined then
return bipedBoneObj
return undefined
)
--ui
--HelpWin
rollout HelpWin "About" width:400 height:212
(
label 'lbl1' "BoneToBipedTool" pos:[23,10] width:89 height:21 align:#left
label 'lbl37' "author:Li Weizhao" pos:[23,32] width:157 height:21 align:#left
HyperLink 'theHyperlink' "https://blog.csdn.net/liweizhao" pos:[54,57] width:309 height:21 address:"https://blog.csdn.net/liweizhao" align:#left
--label 'lbl38' "blog:https://blog.csdn.net/liweizhao" pos:[23,54] width:352 height:21 align:#left
label 'lbl39' "Ver 1.0.0" pos:[139,10] width:65 height:16 align:#left
label 'lbl40' "Step:" pos:[8,82] width:157 height:21 align:#left
label 'lbl41' "1.assign the original biped part bones" pos:[22,108] width:220 height:21 align:#left
label 'lbl42' "2.assign the original non-biped custom bones" pos:[22,130] width:220 height:21 align:#left
label 'lbl43' "3.Create biped and custom bones" pos:[22,151] width:220 height:21 align:#left
label 'lbl44' "4.select skinMeshes and reskin" pos:[22,172] width:220 height:21 align:#left
label 'lbl62' "Blog:" pos:[22,56] width:30 height:15 align:#left
)
--boneListWin
rollout BoneListWin "1.Assign BoneList" width:400 height:351
(
label 'lbl1' "BoneList" pos:[11,11] width:157 height:20 align:#left
dotNetControl 'boneDataList' "System.Windows.Forms.ListView" pos:[9,30] width:380 height:200 align:#left
label 'lbl4' "AutoFit:" pos:[39,284] width:77 height:14 align:#left
label 'lbl5' "original boneRoot:" pos:[37,248] width:97 height:15 align:#left
label 'selectRootTxt' "UnSelected" pos:[145,249] width:86 height:19 align:#left
button 'selectAndFitBtn' "SelectAndFit" pos:[149,276] width:159 height:24 align:#left
button 'saveBtn' "Save" pos:[151,308] width:72 height:24 align:#left
button 'loadBtn' "Load" pos:[239,308] width:72 height:24 align:#left
label 'lbl9' "Save And Load:" pos:[38,311] width:115 height:14 align:#left
button 'selectBtn' "Select" pos:[239,244] width:72 height:24 align:#left
on BoneListWin open do
(
boneDataList.Fullrowselect = true
boneDataList.GridLines = true
boneDataList.View = boneDataList.View.Details
boneDataList.Columns.Add "BoneName" 100
boneDataList.Columns.Add "MustNeed" 60
boneDataList.Columns.Add "SetBone" 200
InitBoneList()
for i = 1 to boneInfoDict.count do
(
row = dotNetObject "System.Windows.Forms.ListViewItem"
boneInfoDict[i].SetRow row
row.Text = boneInfoDict[i].GetShowName()
row.SubItems.Add(boneInfoDict[i].GetMust())
row.SubItems.Add("")
boneDataList.Items.Add(row)
)
)
on boneDataList mouseDown arg do
(
hit=(boneDataList.HitTest (dotNetObject "System.Drawing.Point" arg.x arg.y))
local clickName = hit.item.subItems.item[0].text
local info = GetBoneInfoByName clickName
if info != undefined then
(
if arg.Clicks == 2 do
(
info.SetSelectBone undefined
)
if arg.Clicks == 1 do
(
info.SetSelectBone $
)
)
)
on selectAndFitBtn pressed do
(
if $ == undefined then
(
selectRootTxt.text = "UnSelected"
selectedBoneRootObj = undefined
)
else
(
if (CheckSelectSingleObj $) == false then
(
selectRootTxt.text = "UnSelected"
selectedBoneRootObj = undefined
ShowMsg "Please select the biped root only!"
return 0
)
selectedBoneRootObj = $
selectRootTxt.text = selectedBoneRootObj.name
SetBipedName selectedBoneRootObj.name
FitBoneToBiped selectedBoneRootObj
)
)
on saveBtn pressed do
(
SaveBoneListFun()
)
on loadBtn pressed do
(
LoadBoneListFun()
)
on selectBtn pressed do
(
if $ == undefined then
(
selectRootTxt.text = "UnSelected"
selectedBoneRootObj = undefined
)
else
(
if (CheckSelectSingleObj $) == false then
(
selectRootTxt.text = "UnSelected"
selectedBoneRootObj = undefined
ShowMsg "Please select the biped root only!"
return 0
)
selectedBoneRootObj = $
selectRootTxt.text = selectedBoneRootObj.name
SetBipedName selectedBoneRootObj.name
)
)
)
--customBoneListWin
rollout CustomBoneListWin "2.Assign CustomBoneList" width:400 height:324
(
label 'lbl1' "BoneList(not biped bones)" pos:[11,11] width:157 height:20 align:#left
dotNetControl 'boneDataList' "System.Windows.Forms.ListView" pos:[9,30] width:380 height:200 align:#left
label 'lbl5' "boneRoot:" pos:[16,244] width:50 height:15 align:#left
label 'selectRootTxt' "UnSelected" pos:[81,245] width:86 height:19 align:#left
button 'selectBtn' "Select And Check" pos:[209,239] width:146 height:24 align:#left
button 'cleanBtn' "Clean" pos:[209,279] width:147 height:24 align:#left
button 'addBtn' "Select And Add" pos:[29,278] width:146 height:24 align:#left
on boneDataList mouseDown arg do
(
if arg.Clicks == 2 do
(
hit=(boneDataList.HitTest (dotNetObject "System.Drawing.Point" arg.x arg.y))
local clickName = hit.item.subItems.item[0].text
RemoveCustomBoneInfoByName clickName
)
)
on selectBtn pressed do
(
if (CheckSelectSingleObj $) == false then
(
selectRootTxt.text = "UnSelected"
selectedBoneRootObj = undefined
ShowMsg "Please select the biped root only!"
return 0
)
selectedBoneRootObj = $
selectRootTxt.text = selectedBoneRootObj.name
CheckCustomBone()
)
on cleanBtn pressed do
(
CleanCustomBone()
)
on addBtn pressed do
(
AddCustomBoneToList()
)
)
rollout BoneCtrlWin "3.Bone Controller" width:400 height:249
(
button 'createBipedBtn' "Create Biped Only" pos:[18,118] width:170 height:36 align:#left
button 'selectBipedBtn' "SelectBiped" pos:[18,174] width:170 height:36 align:#left
button 'resizeBtn' "ResizeBones" pos:[214,174] width:170 height:36 align:#left
label 'lbl1' "Biped Name:" pos:[26,32] width:67 height:17 align:#left
edittext 'bipedNameTxt' "" pos:[113,27] width:186 height:27 align:#left
button 'createBoneBtn' "Create Bones Only" pos:[214,117] width:170 height:36 align:#left
button 'onekeyBtn' "One Key Create" pos:[18,72] width:370 height:36 align:#left
on createBipedBtn pressed do
(
CreateBipedFun()
)
on selectBipedBtn pressed do
(
if (CheckSelectionIsBipedRoot $) == false then
(
selectedBoneRootObj = undefined
ShowMsg "Please select the biped root only!"
return 0
)
newBipedObj = $
CheckNewBipedObj()
)
on resizeBtn pressed do
(
ResizeNewBipedFun()
)
on createBoneBtn pressed do
(
CreateCustomBone()
)
on onekeyBtn pressed do
(
CreateBipedFun()
CreateCustomBone()
ResizeNewBipedFun()
ResizeNewBipedFun()
)
)
rollout SkinCtrlWin "4.Skin Controller" width:400 height:320
(
dotNetControl 'skinDataList' "System.Windows.Forms.ListBox" pos:[9,30] width:380 height:164 align:#left
label 'lbl32' "Skin Mesh List" pos:[13,8] width:92 height:18 align:#left
button 'addBtn' "Add" pos:[15,213] width:170 height:31 align:#left
button 'removeBtn' "Remove" pos:[204,213] width:170 height:31 align:#left
button 'skinBtn' "ReSkin" pos:[16,272] width:358 height:31 align:#left
on addBtn pressed do
(
AddToSkinMeshList $
)
on removeBtn pressed do
(
if skinDataList.SelectedItem == undefined then
(
ShowMsg "Please select the obj to remove in the ListBox!"
return 0
)
RemoveSkinMeshByName (skinDataList.SelectedItem as string)
)
on skinBtn pressed do
(
SkinFun()
)
)
local theFloater = newRolloutFloater "Test" 400 600
addRollout HelpWin theFloater rolledup:false
addRollout BoneListWin theFloater rolledup:true
addRollout CustomBoneListWin theFloater rolledup:true
addRollout BoneCtrlWin theFloater rolledup:true
addRollout SkinCtrlWin theFloater rolledup:true
)