Make each poly element planar on z axis for multiple objects

Make each poly element planar on z axis for multiple objects

patrickwongWA5QB
Observer Observer
1,031 Views
9 Replies
Message 1 of 10

Make each poly element planar on z axis for multiple objects

patrickwongWA5QB
Observer
Observer

Hi,

 

I am currently working on a script that can help me make every poly element of a particular materialID planar locally in a poly object that will loop over multiple objects. I have this so far:

PolyObj = selection as Array
	
for obj in PolyObj do
(
	poSetFaceSelection = polyop.setFaceSelection

	-- select material ID 1
	$.selectByMaterial 1

	-- sets the selected face indices as an array
	flattenFaces = getFaceSelection $ as Array
	print flattenfaces

	-- function to clear selection
	clearPolySel = polyop.SetFaceSelection $ #none

	-- cycles through the list of faces to flatten then makes planar in Z
	for i = 1 to flattenFaces.count do
	(
		clearPolySel
		poSetFaceSelection $ flattenFaces[i]
		$.MakePlanarIn #Z selLevel:#Face flag:1
	)
)

 

currently the script in the body of the main for loop works when applied to a single object:

	poSetFaceSelection = polyop.setFaceSelection

	-- select material ID 1
	$.selectByMaterial 1

	-- sets the selected face indices as an array
	flattenFaces = getFaceSelection $ as Array
	print flattenfaces

	-- function to clear selection
	clearPolySel = polyop.SetFaceSelection $ #none

	-- cycles through the list of faces to flatten then makes planar in Z
	for i = 1 to flattenFaces.count do
	(
		clearPolySel
		poSetFaceSelection $ flattenFaces[i]
		$.MakePlanarIn #Z selLevel:#Face flag:1
	)

 

I am currently trying to work out how to get it to work when having multiple objects.

what it should do is make elements that arent flat like this:

patrickwongWA5QB_0-1668138809653.png



making it flat but still keeping the averaged height of the element:

patrickwongWA5QB_1-1668138917421.png

 

any help regarding this would be much appreciated, thanks!

 

0 Likes
Accepted solutions (1)
1,032 Views
9 Replies
Replies (9)
Message 2 of 10

istan
Advisor
Advisor

I'd say using the "$" in your code is not the right approach..

0 Likes
Message 3 of 10

denisT.MaxDoctor
Advisor
Advisor

@patrickwongWA5QB wrote:

Hi,

 

I am currently working on a script that can help me make every poly element of a particular materialID planar

... making it flat but still keeping the averaged height of the element

 


I'm guessing what you're asking is "how to make a face element z-planar about its bounding box center"

 

 

 

 

fn getPolyFacesByMatID obj id:1 =
(
	faces = #{}
	for f=1 to obj.numfaces where (id == polyop.getFaceMatID obj f) do append faces f
	faces
)	

fn collectPolyFaceElements obj faces: =
(
	if faces == unsupplied or faces == #all then 
		faces = #{1..(polyop.getnumfaces obj)}
	else if faces == #selected do 
		faces = obj.selectedfaces as bitarray
	
	elems = #()
	for f in faces where faces[f] do
	(
		ff = polyop.getelementsusingface obj f
		append elems ff
		faces -= ff
	)
	elems
)

fn makePolyFacesPlanarZ obj faces = 
(
	vv = polyop.getVertsUsingFace obj faces
	center = [0,0,0]
	pos = for v in vv collect
	(
		p = polyop.getvert obj v
		center += p
		p
	)
	center /= vv.numberset
	k = 0
	for v in vv do 
	(
		p = pos[k += 1]
		p.z = center.z
		polyop.setvert obj v p   
	)
	pos
)

/*

obj = selection[1]

faces = getPolyFacesByMatID obj
elems = collectPolyFaceElements obj faces:faces
for faces in elems do makePolyFacesPlanarZ obj faces
update obj

*/

 

 

 

 

now we can do it for multiple selection ... 

 

 

 

mapped fn planarPolyFacesByID obj id:1 = if iskindof obj Editable_Poly do
(
	faces = getPolyFacesByMatID obj id:1
	elems = collectPolyFaceElements obj faces:faces
	for faces in elems do makePolyFacesPlanarZ obj faces
	--format "% >> %\n" obj elems
	update obj
)

/*
planarPolyFacesByID objects id:1
--planarPolyFacesByID selection
*/

 

 

 

 

 

0 Likes
Message 4 of 10

denisT.MaxDoctor
Advisor
Advisor

some additional conditions are possible... for example, what if we want to make faces planar in the object coordinate space? well... we can do it too, but it will be another subject. 

0 Likes
Message 5 of 10

denisT.MaxDoctor
Advisor
Advisor

Can we use editable_poly's built-in MakePlanarIn method? Yes, we can... but we still have to find the elements, specify the sublevel, and select our faces (or apply a custom flag). Usually, when we modify a selection for our needs, it's a good practice to revert the original selection back after the operation. That's why I prefer to use my own planar method to make things more manageable and without having to change the current face selection.

0 Likes
Message 6 of 10

patrickwongWA5QB
Observer
Observer
Thank you very much for the detailed reply! how should i be using this? i tried just pasting all your code into a new maxscript and ran it and nothing happens to the object. Thanks!
0 Likes
Message 7 of 10

denisT.MaxDoctor
Advisor
Advisor

run all my code, select one or more poly objects, and run:

planarPolyFacesByID selection id:1
0 Likes
Message 8 of 10

patrickwongWA5QB
Observer
Observer

ive pasted everything like this:

fn getPolyFacesByMatID obj id:1 =
(
	faces = #{}
	for f=1 to obj.numfaces where (id == polyop.getFaceMatID obj f) do append faces f
	faces
)	

fn collectPolyFaceElements obj faces: =
(
	if faces == unsupplied or faces == #all then 
		faces = #{1..(polyop.getnumfaces obj)}
	else if faces == #selected do 
		faces = obj.selectedfaces as bitarray
	
	elems = #()
	for f in faces where faces[f] do
	(
		ff = polyop.getelementsusingface obj f
		append elems ff
		faces -= ff
	)
	elems
)

fn makePolyFacesPlanarZ obj faces = 
(
	vv = polyop.getVertsUsingFace obj faces
	center = [0,0,0]
	pos = for v in vv collect
	(
		p = polyop.getvert obj v
		center += p
		p
	)
	center /= vv.numberset
	k = 0
	for v in vv do 
	(
		p = pos[k += 1]
		p.z = center.z
		polyop.setvert obj v p   
	)
	pos
)

/*

obj = selection[1]

faces = getPolyFacesByMatID obj
elems = collectPolyFaceElements obj faces:faces
for faces in elems do makePolyFacesPlanarZ obj faces
update obj

*/

mapped fn planarPolyFacesByID obj id:1 = if iskindof obj Editable_Poly do
(
	faces = getPolyFacesByMatID obj id:1
	elems = collectPolyFaceElements obj faces:faces
	for faces in elems do makePolyFacesPlanarZ obj faces
	--format "% >> %\n" obj elems
	update obj
)


planarPolyFacesByID objects id:1
--planarPolyFacesByID selection

 

and then when i press Ctrl+E to run it i get this:

 

getPolyFacesByMatID()
collectPolyFaceElements()
makePolyFacesPlanarZ()
planarPolyFacesByID()
-- Error occurred in anonymous codeblock; filename: ; position: 1317; line: 67
-- Argument count error: planarPolyFacesByID wanted 1, got 4
-- MAXScript callstack:
--	thread data: threadID:29428
--	------------------------------------------------------
--	[stack level: 0]
--	In planarPolyFacesByID(); filename: ; position: 1318; line: 67
--		Parameters:
--			obj: $objects
--			id: 1
--		Locals:
--			elems: undefined
--			faces: undefined
--			obj: $Editable_Spline:Maproom_Satellite+Terrain @ [0.000000,0.000000,0.000000]
--			id: 1
--		Externals:
--			collectPolyFaceElements: Global:collectPolyFaceElements : collectPolyFaceElements()
--			getPolyFacesByMatID: Global:getPolyFacesByMatID : getPolyFacesByMatID()
--			owner: undefined
--	------------------------------------------------------
--	[stack level: 1]
--	called from top-level
OK

 

sorry about the noob question but im very new to maxscripting. Thanks!

0 Likes
Message 9 of 10

denisT.MaxDoctor
Advisor
Advisor
Accepted solution
try(destroydialog PlanarFacesRol) catch()
rollout PlanarFacesRol "Planar with denisT" width:191
(
	fn getPolyFacesByMatID obj id:1 =
	(
		faces = #{}
		for f=1 to obj.numfaces where (id == polyop.getFaceMatID obj f) do append faces f
		faces
	)	

	fn collectPolyFaceElements obj faces: =
	(
		if faces == unsupplied or faces == #all then 
			faces = #{1..(polyop.getnumfaces obj)}
		else if faces == #selected do 
			faces = obj.selectedfaces as bitarray
		
		elems = #()
		for f in faces where faces[f] do
		(
			ff = polyop.getelementsusingface obj f
			append elems ff
			faces -= ff
		)
		elems
	)

	fn makePolyFacesPlanar obj faces axis:3 = 
	(
		vv = polyop.getVertsUsingFace obj faces
		center = [0,0,0]
		pos = for v in vv collect
		(
			p = polyop.getvert obj v
			center += p
			p
		)
		center /= vv.numberset
		k = 0
		for v in vv do 
		(
			p = pos[k += 1]
			if iskindof axis Number do p[axis] = center[axis]
			polyop.setvert obj v p   
		)
		update obj
		pos
	)
	
	group "Poly Objects: "
	(
		radiobuttons nodes_list_rb labels:#("All", "Selected") columns:1 align:#left offset:[20,0]
	)
	group "Faces: "
	(
		radiobuttons faces_list_rb labels:#("All", "Selected", "By Material ID") columns:1  align:#left offset:[20,0]
		spinner matid_sp range:[1,255,1] type:#integer fieldwidth:42 align:#right offset:[4,-20] enabled:(faces_list_rb.state == 3)
	)
	group ""
	(
		radiobuttons planar_axis_rb "Axis: " labels:#("X", "Y", "Z") columns:3 default:3 align:#left offset:[0,-6] offsets:#([20,0],[10,0],[0,0])
		checkbox by_elements_cb "By Face Elements" checked:on offset:[0,4]
		
		button make_planar_bt "Make Faces Planar" width:172 align:#left offset:[-4,2]
	)
	
	on faces_list_rb changed state do
	(
		matid_sp.enabled = (state == 3)
	)
	
	on make_planar_bt pressed do undo "Make Faces Planar" on 
	(
		nodes = case nodes_list_rb.state of
		(
			1: objects
			2: selection
	  default: selection
		)
		
		for node in nodes where iskindof node Editable_Poly do 
		(
			faces = case faces_list_rb.state of 
			(
				1: #{1..node.numfaces}
				2: node.selectedfaces as bitarray
				3: getPolyFacesByMatID node id:matid_sp.value
			)
			
			elems = if by_elements_cb.state then collectPolyFaceElements node faces:faces else #(faces)
			for faces in elems do makePolyFacesPlanar node faces axis:planar_axis_rb.state
		)
	)
	
	on PlanarFacesRol open do
	(
	)
)
createdialog PlanarFacesRol

 

Learn MaxScript! Helps a lot!!!
😎

0 Likes
Message 10 of 10

patrickwongWA5QB
Observer
Observer
This is wonderful, thank you very much for your help! Will learn more!
0 Likes