Notifications
Clear all

[Closed] Relax along Z axis

I was searching for a solution how to relax along Z axis only and found this thread:
https://forums.cgsociety.org/t/zlax-relax-along-z-value-only/1246777

Unfortunately, none of the two options provided in the thread worked for me.
Could someone check the script and help with a working code?

  1. If you select an editable poly, then the script runs on all the verts
  2. If you are in sub-object then it runs on the selected verts only
9 Replies
fn relaxPolyVertsUsingAxis node verts: amount:0.5 iterations:10 keepBorder:off keepOuter:off axis:#z = 
(
	if verts == unsupplied or verts == #all do verts = #{1..node.numverts}
	if verts == #selected do verts = node.selectedverts as bitarray
	
	node.setSelection #vertex verts 	

	getvert = polyop.getvert	
	pp = for v in verts collect (getvert node v)
	
	node.relaxAmount = amount
	node.relaxIterations = iterations
	node.relaxHoldOuterPoints = keepOuter
	node.relaxHoldBoundaryPoints = keepBorder
	node.relax selLevel:#vertex	
	
	
	_axis = case axis of 
	(
		 #x: #{1} 
		 #y: #{2} 
		 #z: #{3} 
		#xy: #{1,2} 
		#yz: #{2,3} 
		#xz: #{1,3}
	default: #{1..3}		
	)

	
	k = 0
	for v in verts do 
	(
		k += 1
		p = getvert node v
		for i in _axis do pp[k][i] = p[i]
	)
	
	polyop.setvert node verts pp
	update node
)	

couple bugs were fixed…

Do I need to run relaxPolyVertsUsingAxis() with some parameters?
Didnt manage to run it

does this part mean this script supports relax along all these axis?

/************************ example setup *********/
delete objects
gc()

n = plane name:#relax_poly_test width:100 length:100 widthsegs:32 lengthsegs:32 
addmodifier n (Noisemodifier strength:[2,2,10] fractal:on roughness:1 scale:10)
converttopoly n

relaxPolyVertsUsingAxis n verts:#all amount:0.5 iterations:20 keepBorder:on keepOuter:off axis:#z
-- relaxPolyVertsUsingAxis n verts:#all amount:0.5 iterations:20 keepBorder:on keepOuter:off axis:#xy

you can specify relax parameters, axis to relax effective, and vertex selection … It works for editable poly, but it can be easily changed to work with editable mesh. And you are free to do it

ps. of course I could forget something but the idea is clear enough

I noticed that if I run relaxPolyVertsUsingAxis $ it uses the values defined at the top,

is there a reason why default values are defined in advance if you’re going to run the function with values anyway? eg relaxPolyVertsUsingAxis n verts:#all amount:0.5 iterations:20 keepBorder:on keepOuter:off axis:#z

optional arguments are defined with default values in case if you don’t need to change all of them every call… it’s a common practice

All right, my brain reached melt-down.

Time for some relaxation!
One hour later, I ended up with nothing more than a tiny UI

If anyone is in the mood to finish this one, I give you a big thank you in advance!

rollout Relaxer "Time to relax with denisT" width:210 height:200
(
	slider 'slider_amount' "Amount:" pos:[10,15] width:200 height:44 range:[0.05,1,0.5] align:#left
	editText 'amount_value' pos:[60,15] width:50 height:15 align:#left
	slider 'slider_iteration' "Iteration:" pos:[10,70] width:200 height:44 range:[1,100,10] align:#left
	editText 'iteration_value' pos:[60,70] width:50 height:15 align:#left
	
	label 'lbl_axis' "Smooth axis" pos:[10,120] width:40 height:15 align:#left
	checkbox 'chk_x' "x" pos:[60,120] width:29 height:15 align:#left
	checkbox 'chk_t' "y" pos:[100,120] width:29 height:15 align:#left
	checkbox 'chk_z' "z" pos:[140,120] width:29 height:15 align:#left

	checkbox 'chk_outer' "Keep outer" pos:[114,140] width:77 height:15 checked:true align:#left
	checkbox 'chk_border' "Keep border" pos:[12,140] width:82 height:15 checked:true align:#left

	button 'btn_relax' "Relax" pos:[51,168] width:80 height:21 align:#left	
	
	on slider_amount changed val do
	(
		-- the slider caption changes amount_value text to match slider_amount
	)
	on amount_value entered text do
	(
		-- if this changes, it changes the slider_amount value
	)

	
	
	on slider_iteration changed val do
	(
		-- the slider caption changes iteration_value text-field
	)
	
	on iteration_value entered text do
	(
		-- if this changes, it changes the slider_iteration value
	)
	
	on btn_relax pressed  do
		relaxPolyVertsUsingAxis $ verts:#all amount:0.5 iterations:20 keepBorder:on keepOuter:off axis:#z
)

fn relaxPolyVertsUsingAxis node verts: amount:0.1 iterations:10 keepBorder:off keepOuter:off axis:#z = 
(
	if verts == unsupplied or verts == #all do verts = #{1..node.numverts}
	if verts == #selected do verts = node.selectedverts as bitarray
	
	node.setSelection #vertex verts 	

	getvert = polyop.getvert	
	pp = for v in verts collect (getvert node v)
	
	node.relaxAmount = amount
	node.relaxIterations = iterations
	node.relaxHoldOuterPoints = keepOuter
	node.relaxHoldBoundaryPoints = keepBorder
	node.relax selLevel:#vertex	
	
	
	_axis = case axis of 
	(
		 #x: #{1} 
		 #y: #{2} 
		 #z: #{3} 
		#xy: #{1,2} 
		#yz: #{2,3} 
		#xz: #{1,3}
	default: #{1..3}		
	)

	
	k = 0
	for v in verts do 
	(
		k += 1
		p = getvert node v
		for i in _axis do pp[k][i] = p[i]
	)
	
	polyop.setvert node verts pp
	update node
)	

createdialog Relaxer style:#(#style_toolwindow, #style_sysmenu)
/************************ example setup ******
delete objects
gc()

n = plane name:#relax_poly_test width:100 length:100 widthsegs:32 lengthsegs:32 
addmodifier n (Noisemodifier strength:[2,2,10] fractal:off roughness:1 scale:10)
converttopoly n

*****************************************/


try(destroydialog PolyRelaxByAxis) catch()
rollout PolyRelaxByAxis "Relax by Axis" width:191
(

	fn relaxPolyVertsUsingAxis node verts: amount:0.5 iterations:10 keepBorder:off keepOuter:off axis:#z = 
	(
		old_sel = node.selectedverts as bitarray
		
		if verts == unsupplied or verts == #all do verts = #{1..node.numverts}
		if verts == #selected do verts = node.selectedverts as bitarray
		
		node.setSelection #vertex verts 	

		getvert = polyop.getvert	
		pp = for v in verts collect (getvert node v)
		
		node.relaxAmount = amount
		node.relaxIterations = iterations
		node.relaxHoldOuterPoints = keepOuter
		node.relaxHoldBoundaryPoints = keepBorder
		node.relax selLevel:#vertex	
		
		
		_axis = case axis of 
		(
			 #x: #{1} 
			 #y: #{2} 
			 #z: #{3} 
			#xy: #{1,2} 
			#yz: #{2,3} 
			#xz: #{1,3}
		default: #{1..3}		
		)

		
		k = 0
		for v in verts do 
		(
			k += 1
			p = getvert node v
			for i in _axis do pp[k][i] = p[i]
		)
		
		polyop.setvert node verts pp
		
		node.setSelection #vertex old_sel
		
		update node
	)	
	
	group "Relax: "
	(
		spinner amount_sp "Relax Value: " range:[0,1,0.5] type:#float scale:0.01 \
			fieldwidth:56 align:#right offset:[4,0] tooltip:"Relax Amount"
		spinner iterations_sp "Iterations: " range:[1,1000,10] type:#integer \
			fieldwidth:56 align:#right offset:[4,0] tooltip:"Relax Iterations"
		
		checkbox keep_boundary_ch "Keep Boundary" checked:on offset:[0,4] 
			tooltip:"Keep Boundary"
		checkbox keep_outer_corners_ch "Keep Outer Corners" checked:off offset:[0,0] 
			tooltip:"Keep Outer Corners"
	)
	group "Axis: "
	(
		radiobuttons axis_rb labels:#("X", "YZ", "Y", "XZ", "Z", "XY", "XYZ") default:7 columns:2 align:#left offset:[40,0] \
			offsets:#([0,0],[-41,0],[0,5],[-41,5],[0,10],[-41,10],[54,15])
	)
	group "Vertex: "
	(
		radiobuttons target_rb labels:#("All", "Selected") columns:2 align:#left offset:[40,0] offsets:#([0,0],[-5,0])
	)
	group ""
	(
		button relax_bt "Relax" width:173 align:#left offset:[-4,-7]
	)
	
	on relax_bt pressed do undo "Relax" on if iskindof (node = selection[1]) Editable_Poly do
	(
		axis = uiaccessor.getwindowtext axis_rb.hwnd[axis_rb.state] as name
		verts = uiaccessor.getwindowtext target_rb.hwnd[target_rb.state] as name
		
		relaxPolyVertsUsingAxis node verts:verts 	\
			amount:amount_sp.value 					\
			iterations:iterations_sp.value 			\
			keepBorder:keep_boundary_ch.state 		\
			keepOuter:keep_outer_corners_ch.state 	\
			axis:axis
	)
	
	on PolyRelaxByAxis close do
	(
	)
	on PolyRelaxByAxis open do
	(
	)
)

createdialog PolyRelaxByAxis

this is the UI of the tool might look like. I already showed in other my posts how to make it the real tool –
# save dialog position (and state)
# save/load settings on dialog open/close
# save/load settings between MAX sessions
# make it a macrobutton
# organize as one struct (one script, one file)

technically it should be a modifier.

If I have time I will show how to make it a Modifier

1 Reply
(@haider_of_sweden)
Joined: 11 months ago

Posts: 0

I think options are always good.
Making it a scripted modifier sounds like a very good idea since it is non-destructable – but the UI you made is also good because I believe it gives users an option to choose.