Notifications
Clear all

[Closed] How to make it faster?

	fn slicePoly obj pos vector = 
	(
		local verts = obj.verts as bitArray
		obj.selectededges = #{}
		if (slice obj #all (ray pos vector)) do
		(
			deleteVerts obj (for vert in verts where isPositiveDir (getvertpos obj vert) vector pos collect vert)
			cap obj #selection
		)
	)

cap obj #selection

also has to save some time…

1 Reply
(@polytools3d)
Joined: 11 months ago

Posts: 0

Not really, at least with small amount of clusters, but using the returned value from the Slice() method saves around 1% in 252 clusters compared with counting the vertices, so with larger amounts it migh save a little more.

try (destroyDialog ::NightmareFracture) catch()
rollout NightmareFracture "NightmareFracture" width:200
(
  	local obj, points
  
	spinner seed_sp "Seed: " type:#integer range:[0,1e9,1] fieldwidth:56 align:#right offset:[8,0]
	spinner number_sp "Number Cuts: " type:#integer range:[1,10000,100] fieldwidth:56 align:#right offset:[8,0]
  	button create_bt "Create Test Scene" width:192 align:#right offset:[8,0]
	checkbox disable_ref_ch "Disable Ref Messages" offset:[0,4]
	button fracture_bt "Fracture" width:192 align:#right offset:[8,0]
	
	label info_lb "time: 0" align:#left
	
  	on create_bt pressed do
  	(
		delete objects
		if seed_sp.value != 0 do seed seed_sp.value
  		obj = Box lengthSegs:1 widthSegs:1 heightSegs:1 length:200 width:200 height:200 wirecolor:orange
		_min = obj.min*0.9
		_max = obj.max*0.9
		points = for k=1 to number_sp.value collect (random _min _max)
		gc()
  	)

  	local getvertpos = polyOp.getVert
  	local deleteVerts = polyOp.deleteVerts
  	local deletefaces = polyOp.deletefaces
  	local cap = polyOp.capHolesByEdge
	local capHolesByVert = polyop.capHolesByVert
	local createPolygon  = polyop.createPolygon 
  	local slice = polyOp.slice
	local retriangulate = polyop.retriangulate
	local getvertsusingedge = polyop.getvertsusingedge
	local getfacecenter = polyop.getfacecenter
	local getfacesusingvert = polyop.getfacesusingvert  
	local getfacesusingedge = polyop.getfacesusingedge
	local getelementsusingedge = polyop.getelementsusingface
	  
  	fn isPositiveDir pos vector vectorPos = dot vector (pos - vectorPos) > 0
	fn slicePoly obj pos vector = 
	(
		local verts = #{1..obj.numverts}
		obj.selectedverts = #{}
		if (slice obj #all (ray pos vector)) do
		(
			_verts = #{}
			for vert in verts where isPositiveDir (getvertpos obj vert) vector pos do append _verts vert
			deleteVerts obj _verts
			capHolesByVert obj #selection
		)
	)
	on fracture_bt pressed do if obj != undefined AND points != undefined do undo off
  	(
  		local t1 = timeStamp()
  		local pointCount = points.count
  
  		setCommandPanelTaskMode mode:#create
		
		if disable_ref_ch.state do disablerefmsgs()
		with redraw off
		(
			local tempMesh = copy obj ishidden:on
			converttopoly tempMesh
	  
			local chunks = for p in points collect copy tempMesh prefix:#voro pivot:p --wirecolor:orange
			t2 = timeStamp()
			
			for p1 = 1 to pointCount - 1 do for p2 = p1 + 1 to pointCount while not keyboard.escpressed do
			(
				local pos = points[p1]
				local vec = (points[p2] - pos) / 2

				slicePoly chunks[p1] (pos + vec) vec
				slicePoly chunks[p2] (pos + vec) -vec
			)
	  
			delete tempMesh

			if disable_ref_ch.state do enablerefmsgs()
			t3 = timeStamp()
			info_lb.text = "time: " + (t3 - t1) as string
			format "chuncks:% time: % %
" pointCount (t2 - t1) (t3 - t1)
		)
		unhide chunks
  	)
)
createDialog NightmareFracture

here is a little redesigned UI for better testing

In the slicePoly() function, removing:

obj.selectedverts = #{}

and using:

capHolesByVert obj #all

gives me a 20-30% speed increase for 200 cuts seed 1.

	fn slicePoly obj pos vector = 
 	(
 		local verts = #{1..obj.numverts}
 		--obj.selectedverts = #{}
 		if (slice obj #all (ray pos vector)) do
 		(
 			_verts = #{}
 			for vert in verts where isPositiveDir (getvertpos obj vert) vector pos do append _verts vert
 			deleteVerts obj _verts
 			capHolesByVert obj #all
 		)
 	)
2 Replies
(@denist)
Joined: 11 months ago

Posts: 0
capHolesByVert obj #all

this is not correct actually. it has to be #selection. you can see what’s wrong trying to chop a teapot for example.
that’s also why concave geometry cannot be chopped

(@polytools3d)
Joined: 11 months ago

Posts: 0

Really? It might be wrong in theory but in practice I see no difference. Would need more testing though.

in the code above there are two steps of making chunks:

create node duplicates

chop duplicates

i’ve completely rewritten all the code on c++ sdk
and the result is not very impressive

create node duplicates is only 20% faster

chop duplicates is ~1.5-2.5 times faster (depending on number of cuts and source’s mesh polycount)

but it looks like the same fast(or slow) as the rayfire modifier. and for sure faster than IShatter. the mxs code above is faster than IShatter

so…

stop using maxscript: a dead language

don’t bury anything before you don’t really know what it is

1 Reply
(@polytools3d)
Joined: 11 months ago

Posts: 0

You may want to check out VoroFrag

the cool feature of the rayfire modifier i see is preserving normals (visually seamless cuts).
it’s not easy. it seems like to preserve normals we have to slice two times. first time without separation and the next one with. … by storing in between two slices new vertex normals, and applying them after final slice

1 Reply
(@polytools3d)
Joined: 11 months ago

Posts: 0

Yes, that’s cool.
Another good feature is to work with concave geometry. All methods showed here are only valid for convex geometry, which is very limited.

I don’t think you need to slice twice because by default the split property is false so you’re currently slicing without actually splitting into separate elements and the vertex delete is handling the unwanted verts (elements) ok.

Perhaps you could store the normal in a map channel for each new vert?

I know it’s not “politically correct”, but if speed is the most important, avoiding functions and replacing them by the code, you save between 5% and 10% of time.
That’s what I mean (erasing ‘fn isPositiveDir’ and ‘fn slicePoly’):


try (destroyDialog ::NightmareFracture) catch()
rollout NightmareFracture "NightmareFracture WITHOUT_FN" width:200
(
  	local obj, points
  
	spinner seed_sp "Seed: " type:#integer range:[0,1e9,1] fieldwidth:56 align:#right offset:[8,0]
	spinner number_sp "Number Cuts: " type:#integer range:[1,10000,100] fieldwidth:56 align:#right offset:[8,0]
  	button create_bt "Create Test Scene" width:192 align:#right offset:[8,0]
	checkbox disable_ref_ch "Disable Ref Messages" offset:[0,4]
	button fracture_bt "Fracture" width:192 align:#right offset:[8,0]
	
	label info_lb "time: 0" align:#left
	
  	on create_bt pressed do
  	(
		delete objects
		if seed_sp.value != 0 do seed seed_sp.value
  		obj = Box lengthSegs:1 widthSegs:1 heightSegs:1 length:200 width:200 height:200 wirecolor:orange
		_min = obj.min*0.9
		_max = obj.max*0.9
		points = for k=1 to number_sp.value collect (random _min _max)
		gc()
  	)

  	local getvertpos = polyOp.getVert
  	local deleteVerts = polyOp.deleteVerts
  	local deletefaces = polyOp.deletefaces
  	local cap = polyOp.capHolesByEdge
	local capHolesByVert = polyop.capHolesByVert
	local createPolygon  = polyop.createPolygon 
  	local slice = polyOp.slice
	local retriangulate = polyop.retriangulate
	local getvertsusingedge = polyop.getvertsusingedge
	local getfacecenter = polyop.getfacecenter
	local getfacesusingvert = polyop.getfacesusingvert  
	local getfacesusingedge = polyop.getfacesusingedge
	local getelementsusingedge = polyop.getelementsusingface

	on fracture_bt pressed do if obj != undefined AND points != undefined do undo off
  	(
  		local t1 = timeStamp()
  		local pointCount = points.count
  
  		setCommandPanelTaskMode mode:#create
		
		if disable_ref_ch.state do disablerefmsgs()
		with redraw off
		(
			local tempMesh = copy obj ishidden:on
			converttopoly tempMesh
	  
			local chunks = for p in points collect copy tempMesh prefix:#voro pivot:p --wirecolor:orange
			t2 = timeStamp()
			
			for p1 = 1 to pointCount - 1 do for p2 = p1 + 1 to pointCount while not keyboard.escpressed do
			(
				pos = points[p1]
				vec = (points[p2] - pos) / 2
				
				obj1 = chunks[p1]
				pos1 = pos + vec
				verts = #{1..obj1.numverts}
				obj1.selectedverts = #{}
				if (slice obj1 #all (ray pos1 vec)) do
					(
					_verts = #{}
					for vert in verts where (dot vec ((getvertpos obj1 vert) - pos1) > 0) do append _verts vert
					deleteVerts obj1 _verts
					capHolesByVert obj1 #selection
					)
					
				obj2 = chunks[p2]
				vec2 = -vec
				verts = #{1..obj2.numverts}
				obj2.selectedverts = #{}
				if (slice obj2 #all (ray pos1 vec2)) do
					(
					_verts = #{}
					for vert in verts where (dot vec2 ((getvertpos obj2 vert) - pos1) > 0) do append _verts vert
					deleteVerts obj2 _verts
					capHolesByVert obj2 #selection
					)

			)
	  
			delete tempMesh

			if disable_ref_ch.state do enablerefmsgs()
			t3 = timeStamp()
			info_lb.text = "time: " + (t3 - t1) as string
			format "chuncks:% time: % %
" pointCount (t2 - t1) (t3 - t1)
		)
		unhide chunks
  	)
)
createDialog NightmareFracture

Not sure where I got this code. But this is what I use to speed things up by shutting redraw on the command panels


fn FN_Stop_Command_Redraw = (
	WM_SETREDRAW=0xB
	commandHWND = (windows.getChildHWND #max "Command Panel")
	if commandHWND != undefined and classOf commandHWND==Array then commandHWND=commandHWND[1]
	else commandHWND = windows.getmaxhwnd()
	if commandHWND !=undefined do windows.sendmessage commandHWND WM_SETREDRAW 0 0
)

fn FN_Resume_Command_Redraw = (
	WM_SETREDRAW=0xB
	commandHWND = (windows.getChildHWND #max "Command Panel")
	if commandHWND != undefined and classOf commandHWND==Array then commandHWND=commandHWND[1]
	else commandHWND = windows.getmaxhwnd()
	if commandHWND !=undefined do windows.sendmessage commandHWND WM_SETREDRAW 1 0
)


1 Reply
(@polytools3d)
Joined: 11 months ago

Posts: 0

It is not a drawing issue what slows the code, but the Slicing function. Not even disabling the messages will save time.

As I mentioned before, just making sure that Slice() succeeded saves 80% over the already optimized code, which is not a trivial improvement.

However, there are still too many unnecessary calls and checks.

Using selectedverts would be slow then just passing a bit array of verts. (I think)

obj1.selectedverts

why setCommandPanelTaskMode mode:#create

Page 3 / 6