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崩潰,這我就不研究了,使用前備份一下文件就行。

 

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