MAXScript学习笔记(3) 功能:分离元素

一.分离一个特定元素(Detach Element)

要对一组相同的物体(Editable_Poly)进行分离物体里面某一个部分的功能。

本来以为Editable_Poly里面会有相关的Element的API,结果全是点(Vert)线(Edge)面(Face),只有一个getElementsUsingFace

而它的参数是 faceList,问题是在polyop里我还找不到getFace的函数....

也就是说这个界面上的基本操作实际上是封装了一层的,api层至多到Face层级,没有更高的层级了。

搜索了一番,找到了两个有用的函数

fn getElements obj=
	(
		try
		(
			f=obj.numfaces
			eles=#()
			done=#()
			for i=1 to f do
			(
				if (finditem done i)==0 then
				(
					case (classof obj) of
					(
						editable_mesh:(faces=(meshop.getElementsUsingFace obj #(i)) as array)
						editable_poly:(faces=(polyop.getElementsUsingFace obj #(i)) as array)
					)
					append eles faces
					join done faces
				)
			)
		)
		catch(
			eles=undefined
		)
		return eles
	)

参考:https://www.maxforums.org/forum/thread/maxscript_mesh_elements/1

	function detachElements nin_Object = 
	( 
		naOut = #()
		if classof nin_Object == Editable_Poly do
		( 
			suspendediting()
			try
			(
				undo off
				(
					with redraw off
					(
						while polyOp.getNumFaces nin_Object != 0 do 
						(
							elementSel  = (polyOp.getElementsUsingFace nin_Object #{1})
							baseName  = nin_Object.name
							newName   = (uniqueName baseName)
						
							polyOp.detachFaces nin_Object elementSel asNode:true name:newName
							detachedObj = (getNodeByName newName)
							append naOut detachedObj
						)
					
						for o in naOut do
						(
							baseName  = (substring o.name 1 (o.name.count-3))
							uniquePart  = (substring o.name (o.name.count-2) o.name.count)
							finalName   = (baseName + "_" + uniquePart)
							o.name    = finalName
							centerPivot o
						)
					)
				)
			)
			catch(messageBox "error: detach objects")
			resumeediting()
			
			delete nin_Object
		)
		naOut as array
	)

参考:http://www.scriptspot.com/forums/3ds-max/general-scripting/edit-poly-modifier-quick-detach

接下来又是二次开发的工作了,我要把Element相关的操作封装到一个ElementOp里面

-------------------------------------------------------------------------------------------------

二、按材质分离元素

本来以为是分离就好了,结果还要合并相同材质的物体

结果1:将窗户的玻璃和外框分离,并放在一个组里,每个窗户变成一个组,里面有两个子物体

结果2:在上面的基础上,将全部的玻璃合并在一个物体里,外框合并在一个物体里

整个过程学到了Element操作,材质操作,分离合并,从门外汉入门了一些。

把整个ms贴出来吧,使用的是最下面的函数。

print "-------------------------- ElementOp.ms ---------------------------------"

struct ElementOpClass
(
  fn GetElements obj=
	(
    print ("->ElementOp.GetElements():"+(obj as string))
		try
		(
			f=obj.numfaces
			eles=#()
			done=#()
			for i=1 to f do
			(
				if (finditem done i)==0 then
				(
					case (classof obj) of
					(
						editable_mesh:(faces=(meshop.GetElementsUsingFace obj #(i)) as array)
						editable_poly:(faces=(polyop.GetElementsUsingFace obj #(i)) as array)
					)
					append eles faces
					join done faces
				)
			)
		)
		catch(
			eles=undefined
		)
		return eles
	),
  fn DetachElement obj ele=
  (
    newName   = (uniqueName obj.name)
    polyOp.detachFaces obj ele asNode:true name:newName
    detachedObj = (getNodeByName newName)
    centerPivot detachedObj --没有这句话的话,新的物体的轴心还是在原来的物体的轴心的位置
    return detachedObj
	),
	fn RenameElement o = --
  (
    baseName  = (substring o.name 1 (o.name.count-3))
    uniquePart  = (substring o.name (o.name.count-2) o.name.count)
    finalName   = (baseName + "_" + uniquePart)
    o.name    = finalName
  ),
	fn RenameElements objs = --
  (
		if objs == undefined do (
			print "RenameElements objs == undefined"
			return undefined
		)
    for o in objs do
		(
      RenameElement o
		)
  ),
  --ElementOp.DetachAllElements $
	fn DetachAllElements obj = 
	( 
    print ("->ElementOp.DetachAllElements():"+(obj as string))
    naOut = #()
    if classof obj != Editable_Poly do convertToPoly obj
		if classof obj == Editable_Poly do
		( 
			-- suspendediting()
			-- try
			-- (
				-- undo off
				(
					with redraw off
					(
						while polyOp.getNumFaces obj != 0 do 
						(
              elementSel  = (polyOp.GetElementsUsingFace obj #{1})
              detachedObj=DetachElement obj elementSel
							append naOut detachedObj
						)
						for o in naOut do
						(
              RenameElement o
						)
					)
				)
			-- )
			-- catch(messageBox "error: detach objects")
			-- resumeediting()
			delete obj
		)
		naOut as array
	),
	fn DetachElements_Inner obj indexes isCombine:true isGroup:true=(
		print ("->Elements.DetachElements():"+(obj as string))
		if classof obj != Editable_Poly do (
			convertToPoly obj
		)
		local eleList=GetElements obj
		print eleList
		local newObjs=#(obj)
		if isCombine then 
		(
			local newEle=#()
			if indexes!= undefined do 
			(
				for i in indexes do
				(
						ele=eleList[i]
						print (ele as string)
						join newEle ele
				)
				local detachedObj=DetachElement obj newEle
				append newObjs detachedObj
			)
		)
		else
		(
			if indexes!= undefined do
			(
				for i in indexes do
				(
					local detachedObj=DetachElement obj eleList[i]
					append newObjs detachedObj
				)
			)
		)
		local oriName=obj.name
		obj.name=obj.name+"000" --保持命名一致

		for o in newObjs do
		(
			RenameElement o
		)

		if isGroup then 
		(
			g1=group newObjs name:oriName
			setGroupOpen g1 true
			return g1
		)
		return newObjs
	),
	--ElementOp.DetachElements $ #(1,2,3)
	--ElementOp.DetachElements $ #(1,2,3) isCombine:false
	--ElementOp.DetachElements $ #(1,2,3) isGroup:false
	--ElementOp.DetachElements $ #(1,2,3) isGroup:false isAttachAll:true
	fn DetachElements objList indexes isCombine:true isGroup:true isAttachAll:false=
	(
		if objList == undefined do (
			print "DetachElements objList == undefined"
			return undefined
		)
		newObjList=#()
		for obj in objList do
		(
			print ("->Elements.DetachElements():"+(obj as string))
			newObj=DetachElements_Inner obj indexes isCombine:isCombine isGroup:isGroup
			append newObjList newObj
			--exit
		)
		if newObjList.count > 1 and isCombine == true and isGroup==false and isAttachAll == true do
		(
			print "attachAll"
		)
		print (newObjList as string)
	),
	--ElementOp.DetachByMaterial $
	fn DetachByMaterial_Inner obj isGroup:true=
	(
		if obj == undefined do (return undefined)
		if classof obj != Editable_Poly do (
			convertToPoly obj
		)
		oldName=obj.name
		m=obj.material
		if classof m == MultiMaterial do
		(
			newObjs=#()
			for i=1 to m.numsubs do
			(
				mId=m.MaterialIDList[i]
				obj.selectByMaterial mId
				m_faces = getFaceSelection obj
				detachedObj=DetachElement obj m_faces
				subM=m.MaterialList[i]
				detachedObj.material=subM
				print ("detachedObj Material"+(subM as string ))
				append newObjs detachedObj
			)
			RenameElements newObjs
			delete obj
			if isGroup do
			(
				g=group newObjs name:oldName
				setGroupOpen g true
				return g
			)
			return newObjs
		)
		return undefined
	),
	fn FindObjectsByMaterial objList m =
	(
		items=#()
		for obj in objList do
		(
			if isDeleted obj do continue
			if obj.material == m do append items obj
		)
		return items
	),
	--ElementOp.AttachObjects $
	fn AttachObjects objList =
	(
		print objList
		if objList == undefined do (
			print "AttachObjects objList == undefined"
			return undefined
		)
		if classof objList != Array and classof objList !=ObjectSet do (
			format "skip classof:%\n" (classof objList)
			return objList
		)
		if objList.count < 2 do return objList

		objList=objList as Array --记得要转换 不然会出错

		first = objList[1]
		format "first:%\n" first
		format "objList1:%\n" objList.count
		-- deleteItem objList first
		-- while objList.count > 0 
		for i =2 to objList.count do
		(
			obj = objList[i]
			format "obj:%\n" obj
			if obj == undefined do continue
			polyop.attach first obj --ObjectSet的情况下,会自动把删除的模型去掉
			i-=1
			format "count:%\n" objList.count 
		)
		format "objList:%\n" objList 
		CenterPivot first
	),
	fn CollectMaterials objList=
	(
		mList=#()
		for obj in objList do
		(
			m=obj.material
			i = findItem mList m
			if i == 0 do append mList m
		)
		format "materialList:%\n" mList
		return mList
	),
	--ElementOp.AttachByMaterial $
	fn AttachByMaterial objList=
	(
		if objList == undefined do (
			print "AttachByMaterial objList == undefined"
			return undefined
		)
		newObjList=#()
		mList=CollectMaterials objList
		for m in mList do
		(
			subList=FindObjectsByMaterial objList m
			format "subList:%\n" subList
			newObj=AttachObjects subList
			-- append newObjList newObj
		)
		return newObjList
	),
	--ElementOp.DetachByMaterial $
	--ElementOp.DetachByMaterial $ isGroup:false
	--ElementOp.DetachByMaterial $ isCombineByMat:true
	fn DetachByMaterial objList isGroup:true isCombineByMat:false=
	(
		if objList == undefined do (
			print "DetachElements objList == undefined"
			return undefined
		)

		if isCombineByMat do isGroup=false 

		newObjList=#()
		objList=objList as Array --记得要转换 不然会出错
		for obj in objList do
		(
			print ("->Elements.DetachElements():"+(obj as string))
			newObj=DetachByMaterial_Inner obj isGroup:isGroup
			join newObjList newObj
			--exit
		)
		print (newObjList as string)
		if newObjList.count > 1 and isCombineByMat ==true and isGroup == false do
		(
			print "attachAll"
			newObjList=AttachByMaterial newObjList
			print (newObjList as string)
		)
		
	)
)
ElementOp=ElementOpClass()

大小写上,我自己的约定是 struct和function是大写开头的,虽然写着写着有时候自己也写成了小写,后面会再替换一下,javascript和java的函数名都是小写开头的,c#的是大写开头的,但是这些语言有()作为函数的调用,这里没有,还是区分一些 不然两个并列的字符串 感觉像是两个变量一样。

命名上函数名都是动词+名词,变量名都是名称。

实际使用环境中,这些窗户是分别在不同楼层中的,要按楼层分别处理。

然后还有楼梯、栏杆的分离合并操作。

另外就是一般的代码操作都能回退,这些操作完后如果回退,可能会导致3dmax崩溃,这我就不研究了,使用前备份一下文件就行。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章