MaxScript编写bone转换biped工具

一、制作转换工具的缘由

  大家好,我是阿赵。我经常从各种渠道得到了一些角色模型,这些模型得到之后,会发现是带有蒙皮和骨骼,甚至带有动作的。
  不过这些资源很多都是从游戏截取出来的,导入到3DsMax之后,角色的骨骼是bone类型的,不是biped类型的。熟悉3DsMax的人应该都知道,bone类型还要重新的去自己连IK,如果骨骼是biped的话,使用起来会比较方便一点。所以我一直想找一个工具能把bone骨骼转换到biped骨骼。在网上找了一些工具,也能用,不过总感觉不是特别的顺手。所以我决定自己做一个。
  这个工具的完整代码在最后提供了。不过我要先说明,我是在3DsMax2018版本开发的这个工具,在不同版本对Maxscript的支持不一样。由于我是免费开源的,所以如果遇到API问题或者bug,请各位自行解决了。
  顺便说一句,如果各位有什么工具想开发的,也可以说一下,如果简单的,我可以免费做完当文章写提供开源。如果是复杂的,我也可以根据自己的时间来考虑是否收费制作。

二、工具的使用说明

1、需要的东西

在这里插入图片描述

  我这里拿一个阴阳师的游戏模型作为例子。这是一个带有蒙皮信息的角色模型的fbx文件,导入到了3DsMax里面。
在这里插入图片描述

  注意看一下场景物体列表,会发现,这个模型的骨骼,原来就是用biped做的,然后还附加了一些自定义的bone骨骼。
  这种本身是biped做的骨骼,需要还原成biped的话,相对来说会比较容易一些,因为它的结构和命名本身就是符合biped的规则的。
  不过很多角色资源的模型,它的骨骼并不是biped做的,因为制作3D资源的软件很多,并不一定是3Dsmax,也可以是maya等。所以我也要兼容其他的骨骼情况。

2、工具介绍界面

在这里插入图片描述

  运行了脚本之后,会看到出现一个界面,它是由5个可折叠窗口组成的。
  第一个是About窗口,它的内容首先是显示了作者信息,然后还有操作的简单步骤
  后面的4个界面,是对应接下来操作的4个大步骤的。接下来再一一说明

1.指定biped架构的骨骼

在这里插入图片描述

  这个工具窗口,是把作为要生成biped时必要的部位的骨骼指定的过程。可以看到上面有一个BoneList的列表,第一列里面列出了biped骨骼所有支持的骨骼部位,第二列用星号标出了哪些部位是必须的。因为作为biped的基础部位,如果没有这些骨骼,就不能生成。

这个指定的步骤可以分为自动和手动2种操作
(1)如果原来的骨骼就是biped制作的,那么可以选择骨骼的根节点,然后点击SelectAndFit按钮,就会自动的遍历原来所有的骨骼,并根据骨骼的名称,去匹配biped的部位
(2)如果原来的骨骼命名并不是按照biped规则的,也可以手动的去指定,具体的操作是选择骨骼的根节点,点击Select按钮,接下来,先在场景里面选择需要指定的骨骼物体,然后单击列表里面对应的骨骼部位。如果想取消某个骨骼的指定,可以双击列表里面的骨骼部位。
在这里插入图片描述

  针对第二种手动指定的情况,因为指定一次并不容易,所以我还提供了保存和读取的功能。当指定完成之后,可以点击Save按钮,这时候会打开一个保存文件的窗口,让用户选择需要保存的文件,文件使用csv格式。当下次想继续编辑的时候,先用Select按钮选择了骨骼的根节点,然后点击Load按钮,这时候会打开一个读取文件的选择窗口,选择之前保存的csv文件,就可以把上一次的结果读取进来了。

2.指定自定义骨骼

  由于角色的骨骼不一定全部都是biped的部位,还可以有很多自定义的骨骼部位,比如衣服的裙摆、武器的骨骼等,所以在指定了biped骨骼之后,接下来还可以指定自定义的骨骼。当然如果没有,也可以不指定。
在这里插入图片描述

  这个操作必须是在第一步biped骨骼指定完成或者读取完成之后,才能做的,因为这里还需要判断自定义的骨骼的父节点的类型。
操作也是分自动和手动2种情况
(1)如果想使用自定义功能,在指定完biped骨骼之后,还是选择原骨骼的根节点,然后点击Select And Check按钮,这时候,工具会遍历根节点下面的所有节点,如果不是之前已经指定过的biped骨骼,那么统一都认为是自定义骨骼
(2)也可以手动指定一些骨骼,然后点击Select And Add按钮加入到列表里面去。这个功能是有去重的,所以如果之前已经加过的骨骼,是不会重复添加的。
(3)点击Clean按钮,可以清除所有已经指定的自定义骨骼,也可以双击列表里面的骨骼名称,删除单个骨骼。
在这里插入图片描述

3.创建新骨骼

在指定好biped部位的骨骼和自定义骨骼之后,就可以生成新的biped骨骼了
在这里插入图片描述

  在Bone Controller面板,在输入了需要生成的Biped名字之后,可以选择One Key Create来一键创建Biped和自定义bone,然后自动对齐他们的位置
  如果不想一键也可以分步式的手动生成,用Create Biped Only按钮来单独生成Biped和用Create Bones Only按钮生成自定义骨骼bones,然后用ResizeBones按钮手动对齐骨骼位置。
如果之前已经生成过了,在接着操作的时候,也可以通过选择新Biped根节点,然后点击SelectBiped按钮,来指定已经生成的biped骨骼。
在这里插入图片描述

这是已经生成完biped和自定义骨骼之后的模型状态,可以看到,新生成的骨骼和原模型是刚好对齐了。

4.蒙皮操作

在生成了骨骼之后,就可以进行蒙皮的操作了
在这里插入图片描述
  由于一个模型有可能是由多个网格部位组成的,所以这里可以单选或者多选需要复制的蒙皮网格,然后点击Add按钮,添加到列表里面去。也可以选择已经添加的网格,然后点Remove按钮移除。
  最后点击ReSkin按钮,工具会复制已经选择的蒙皮网格,并且读取它们的蒙皮信息,并转移到新生成的骨骼上面去。
在这里插入图片描述

这是蒙皮之后的结果,可以看到,新生成的网格模型,已经可以准确的跟随着新生成的骨骼运动了。

三、工具的原理

这个版本的工具,是我特意按照原理的思路,把步骤拆分的,从工具可以看出,整个过程分为了以下步骤:
1、原始骨骼数据收集
2、生成新的Biped
3、对齐骨骼
4、获取蒙皮信息
5、重新蒙皮
下面具体的来说一下这些步骤的实现:

1、原始骨骼数据收集

在收集数据之前,我们起码要知道,有哪些数据是需要收集的。
先来看看MaxScript创建Biped的语句:
biped.createNew <height_float> <angle_float> <wpos_point3> . . .
有3个数据是必须的:
1.骨骼高度
2.旋转角度
3.世界坐标
然后后面的省略号,是一些可选参数,实际上,都是在3DsMax里面的Figure Mode里面的
骨骼参数:
在这里插入图片描述

在这里插入图片描述

我们怎么去知道这些参数呢?我们只能从原始的bone骨骼里面去猜出这些参数。所以必须先让用户指定原始bone的根骨骼,然后通过遍历的方式,去读取这些骨骼。

1.获取某种关节数量

从已经指定的Biped部位,可以判断出每种骨骼部位的数量,比如Spine骨骼,判断一下有多少个Spine部位已经指定了骨骼的,那么Spine的数量就能获得了,其他的手指、脚趾也一样
在这里插入图片描述

2.Triangle Pelvis和Triangle Neck

这两个选项,会导致骨骼的树形结构变化
如果勾上了Triangle Pelvis, L Thigh和R Thigh会在Spine下一层
在这里插入图片描述

如果不勾Triangle Pelvis,L Thigh和R Thigh会在Spine同一层,都是在Pelvis下一层
在这里插入图片描述

如果勾上了Triangle Neck, L Clavicle和 R Clavicle会在和Neck同一层
在这里插入图片描述

如果不勾Triangle Neck, L Clavicle和 R Clavicle会在和Neck的下一层
在这里插入图片描述

知道了这个关系之后,我们收集骨骼信息的时候,就要特殊留意这些骨骼的父子关系,看看是属于哪一种的。

3.高度怎样获取

实际上高度是没有办法获取的,因为这里的高度,是字面意思,是人骨骼的头顶到脚底的高度。但我们的原始骨骼,是没有厚度的,所以只能算到最高的骨头的坐标位置,而不是透顶。
不过问题不大,因为下面还会用对齐骨骼来修改骨骼位置的,所以我是获取了biped骨骼的Head到Foot的距离,作为高度,等于是给骨骼一个大概的默认值。

4.关于旋转角度和坐标

因为下面还会再次对齐骨骼,所以位置和旋转都不重要,先随便给个默认值就行。

5.骨骼的存储

由于工具已经分成了biped部位和自定义骨骼的列表,所以我分别用了2个Struct结构体来存储biped和自定义骨骼的数据结构。

2、生成新的Biped

通过了上面的数据收集,我们已经得到了创建Biped所必须的参数了。
通过biped.createNew方法,就可以把Biped创建出来了。

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

有2点值得注意的地方:
1.想要整个Biped一起改名,比如从Bip001改成Bip002,并不是遍历所有骨骼逐个对象去改变name属性,而是通过获得Biped的controller,然后修改rootName,这样整个Biped所有节点的名字都会跟着一起变化。
2.这一个步骤创建的只是Biped的部分。实际上很多角色模型会在Biped的基础上再添加了一些bone类型的骨骼作为细节,这些bone骨骼在这一步并没有生成出。由于这些骨骼的位置是跟随着正常的Biped骨骼的,所以我们会在生成完Biped骨骼之后再生成。

3、对齐骨骼

这个步骤看着似乎很简单,不就是每个骨骼找到之前原始骨骼的同名字骨骼,然后复制一下位移旋转缩放信息吗?
实际上并不是这样的,这是因为:
1.Biped里面,有些骨骼是可以直接移动,有些骨骼是依靠父子连接关系和IK来移动的。所以如果对骨骼直接设置位置坐标,很多骨骼都不能生效的。能直接设置位置坐标的骨骼反而不多,只有根骨骼、颈部、左右肩膀、第一根Spine、手指和脚趾的第一关节。
2.导入后的bone骨骼,缩放都是1的,但Biped的骨骼缩放并不是1,不能按照bone的设置。
这样看来,除了旋转信息,好像也就没什么信息可以直接设置了。
不过问题并不是没法解决的。实际上上面2个问题是同一个问题。如果我们要手动的去适配骨骼的位置,正常的做法是,先进入Figure Mode,然后通过缩放,把父级骨骼放大缩小到合适的大小,已达到调整子骨骼位置的目的。如果用脚本来操作,其实也是一样的,只需要计算骨骼的缩放就行了。
计算方式是,过去父级骨骼的坐标和子骨骼的坐标,计算距离,这个距离就是父级骨骼的缩放值了。
不过并不是所有骨骼都是这样计算缩放,这里分成几种情况:
1.根骨骼不需要缩放
2.盆骨Pelvis不论它的父子结构怎样,它的缩放都是Pelvis离其中一根大腿Thigh的距离再乘以2
3.胸骨Spine的最后一根骨骼不需要设置缩放,因为它的子级骨骼是可以直接设置坐标,不需要靠父级的缩放来定位置。其他的子级可以直接设置坐标的骨骼也同理。
这里还需要注意一个地方,Biped物体是不能直接获取pos之类的信息的,必须先获取transform,再获取pos、rotation、scale.

4、获取蒙皮信息

对于一个Skin蒙皮的模型来说,需要先获取它的蒙皮骨骼列表。
这里有个需要注意的地方,Skin里面有2个骨骼的列表,一个是根据UI显示列表的顺序来排序,另外一个是蒙皮计算时的实际骨骼Id,我们要注意,需要获取的是实际骨骼Id,而不是UI显示排序的id。
所以我们要先通过skinOps.GetNumberBones方法获取蒙皮骨骼列表里面的数量,再通过skinOps.GetBoneName方法获取某个骨骼id的骨骼的名称,然后存起来。
接下来要逐个顶点获取信息
一个顶点蒙皮信息里面有2个信息需要获取:
1.一个顶点收到了多少根骨骼影响
2.一个顶点收到每根骨骼影响的权重是多少。
这里我也是使用Struct结构体去记录一个蒙皮网格的蒙皮骨骼列表和顶点蒙皮权重信息。

5、重新蒙皮

由于有了上一步的蒙皮信息,所以复制原有的蒙皮网格,然后添加Skin修改器,再把蒙皮信息赋值到新的蒙皮网格里面就可以了。

四、完整代码:

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

)
	
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值