Notifications
Clear all

[Closed] How to make it faster?

Ok I was right.

before time: 335

After comment out…
line 45
–setCommandPanelTaskMode mode:#create
line 64
–obj1.selectedverts = #{}
line 76
– obj1.selectedverts = #{}

after time: 299

After this you need to find the verts and not use #selection
capHolesByVert obj2 #selection

#selection this will make it slow too

1 Reply
(@polytools3d)
Joined: 11 months ago

Posts: 0

Please read post #33.

also i found that algorithm works wrong if we remove verts above plane only if cut was successful. we have to remove them anyway, but cap only if cut was happened.

1 Reply
(@polytools3d)
Joined: 11 months ago

Posts: 0

So you mean the correct function for Slicing would be something like:

fn slicePoly obj pos vector =
  (
  	local verts = obj.verts as bitArray
  	obj.selectedverts = #{}
  	sliced = slice obj #all (ray pos vector)
  	deleteVerts obj (for vert in verts where isPositiveDir (getVertPos obj vert) vector pos collect vert)
  	if sliced do polyop.capHolesByVert obj #selection
  )

here is what i finally have for the test ‘box’ and 100 chunks (cuts):

pure mxs:

chuncks:100 time: 12 454 2 = 468

mxs + (c++ sdk) extension where i combined slice, remove over plane verts, and cap in one function:

chuncks:100 time: 12 155 2 = 169 

full (c++ sdk):

chuncks:100 time: 10 111 1 = 123

time is:
first number is the time to make template chunks
second number is the fracturing time
third number is replacing baseobjects for template chunks

all operations a little faster for editable poly baseobject vs editable poly node.

yes… this is correct. try to cut a teapot. and you will see that spout in case of #all will be capped

1 Reply
(@polytools3d)
Joined: 11 months ago

Posts: 0

Well, you will be disappointed if you try with a tube. So the challenge to make it work with concave geometries remains open.

these are numbers for ‘teapot’ with 8 segments used:

mxs

chuncks:100 time: 100 1775 2 = 1877

extended mxs

chuncks:100 time: 55 492 2 = 549
#full sdk
chuncks:100 time: 42 471 2 = 515

bool PolyCut(MNMesh* pmesh, EPoly* epi, Point3 normal, Point3 pos, float threshold = 0.0f)
{
	BitArray verts(pmesh->numv);
	pmesh->VertexSelect(verts);
	BitArray edges(pmesh->nume);
	pmesh->EdgeSelect(edges);

	float offset = DotProd(pos, normal);
	bool result = pmesh->Slice(normal, offset, threshold, false, false);

	if (epi)
	{
		BitArray verts(pmesh->numv);
		for (int k=0; k < pmesh->numv; k++)
		{
			if (DotProd(pmesh->P(k) - pos, normal) < 0) verts.Set(k);
		}
		BitArray selverts;
		pmesh->getVertexSel(selverts);
		verts &= ~selverts;
		epi->EpfnPropagateComponentFlags(MNM_SL_VERTEX, MN_TARG, MNM_SL_VERTEX, MN_TARG, FALSE, FALSE, FALSE);
		epi->EpSetVertexFlags(verts, MN_TARG, false);
		epi->EpfnDelete(MNM_SL_VERTEX, MN_TARG, true);
	}
	if (result)
	{
		MNMeshBorder border;
		pmesh->GetBorder(border, MNM_SL_EDGE);
		pmesh->FillInBorders(&border);
	}
	return result;
}

this is c++ version (for who is interested) which gave me the best performance

3 Replies
(@polytools3d)
Joined: 11 months ago

Posts: 0

I suppose the only way to make it faster if as I suggested in the first post, building the geometry from scratch.
VoroFrag is pretty fast, keeps the normals, and has a bunch of other features.

(@denist)
Joined: 11 months ago

Posts: 0

am i missing something? how to cap with VoroFrag?

(@polytools3d)
Joined: 11 months ago

Posts: 0

How to cap what?

(
  	delete objects
  	vf = VoroFrag()
  	vf.numChunks = 200
  	addmodifier (tube()) vf
  )

Then just Detach All or you could also rebuild the elements manually.

With your permission guys (Juzwa, Swordslayer, denisT) I’ve updated the tool to create other geometries for testing.

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]
        	radiobuttons geo_rb "Geometry:" labels:#("Box", "Tube", "C", "Sphere", "Torus", "2D") columns:3 align:#left
        	 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 = case geo_rb.state of
        		(
        			1: Box lengthSegs:1 widthSegs:1 heightSegs:1 length:200 width:200 height:200
        			2: Tube heightsegs:1 capsegs:1 sides:24 radius1:40 radius2:60 height:200
        			3: C_Ext Back_Length:-100 Side_Length:-150 Front_Length:-200 Back_Width:20 Side_Width:20 Front_Width:20 height:200
        			4: Sphere radius:100 segs:24
        			5: Torus smooth:2 segs:24 sides:12 radius1:100 radius2:20
        			6: Box lengthSegs:1 widthSegs:1 heightSegs:1 length:200 width:200 height:10
        		)
        		obj.wirecolor = orange
        		_min = obj.min*0.9
        		_max = obj.max*0.9
    		converttopoly obj
    		obj.weldThreshold = 0.1
    		polyop.weldVertsByThreshold obj #all
 		if geo_rb.state == 6 do (_min.z=0;_max.z=0)
        		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 = #{}
        		sliced = slice obj #all (ray pos vector)
        		if verts.numberset > 1 do deleteVerts obj (for vert in verts where isPositiveDir (getVertPos obj vert) vector pos collect vert)
        		if sliced do 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)
        		)
        		select chunks
        	  )
        )
        createDialog NightmareFracture

try to cap teapot with cap modifier, convert it to mesh or poly, and try to apply VoroFrag

1 Reply
(@polytools3d)
Joined: 11 months ago

Posts: 0

I believe it is from the same developer as RayFire, so as it is free it might has bugs.
I see what you mean, perhaps it does not play well with intersecting geometry?
I’ve moved the Teapot’s handle, spout and lid appart and it seems to work fine.

all that we did before with editable poly was wrong.

everything is much faster, correct with normals, and solves ‘concave’ cap situation if we do it in editable mesh (or trimesh)

M is mesh we need to cut and cap

p is slicing plane

we need:

create mesh plane using plane p big enough to cut M

make subtraction M-P

it will slice M but not separate, select new verts, and make cap(selected faces!)

delete verts below plane

we can call meshop slice method with option ‘remove’, but it seem like it will be double work

weld selected verts and verts from cap

(optional) we can delete plane P or keep it for next cut.

that’s it

5 Replies
(@polytools3d)
Joined: 11 months ago

Posts: 0

You could use a box instead of a plane and avoid all the capping and vertex deleting.
Even though, I haven’t had a good experience with mesh operators. I don’t think this will be any faster but the contrary.

(@denist)
Joined: 11 months ago

Posts: 0

we have to compare meshop and polyop slice methods with things being equal… so it has to be the same TRI count to slice

(@polytools3d)
Joined: 11 months ago

Posts: 0

Where did that rule come from?
We are trying to improve this method using whatever can be used within MXS.

If you want to know if polyop.slice is faster than meshop.slice, that’s easy know.
If you want to know if mesh subtraction is faster than slicing that’s also easy to know.

The only possible optimization I see using this method is to test if the plane intersects the cluster before doing the slicing. But that may be more expensive than the slicing itself.

Using the build-in cap function doesn’t seem to work with all concave geometries, but at least works with convex objects.

Mesh subtraction will be slower I guess, so it remains open the question if meshop.slice will be any faster. But then you need to cap the cluster manually, and that will probably kill all performance gained by using meshop, moreover for concave geometries.

(@denist)
Joined: 11 months ago

Posts: 0

it’s not a rule. it’s a simple logic.

the way to find an intersection of a segment (edge in our case) and a plane was known B.C.
there is no any faster solution… if only some key data was smartly cached.

that’s why it makes sense to compare mesh and poly slice methods.

(@polytools3d)
Joined: 11 months ago

Posts: 0
(
 	delete objects
 	
 	pos = [0,0,50]
 	dir = [0.5,-0.5,0.5]
 	
 	obj1 = converttomesh (box lengthsegs:1 widthsegs:1 heightsegs:1 length:100 width:100 height:100 wirecolor:red)
 	obj2 = copy obj1 pos:[150,0,0] wirecolor:green
 	slicer1 = converttomesh (plane length:200 width:200 lengthsegs:1 widthsegs:1 pos:pos dir:-dir)
 	slicer2 = converttomesh (box lengthsegs:1 widthsegs:1 heightsegs:1 length:200 width:200 height:200 pos:(pos+[150,0,0]) dir:dir)
 	
 	-- Whats the benefit of doing this...? -----------------------------------------------------
 	
 	verts = #{1..obj1.numverts}
 	obj1 - slicer1
 	meshop.deleteverts obj1 (for v in verts where dot dir (getvert obj1 v - pos) > 0 collect v)
 	meshop.weldVertsByThreshold obj1 #selection 0.1
 
 	-- Instead of this...? ---------------------------------------------------------------------
 	obj2 - slicer2
 	
 	--------------------------------------------------------------------------------------------
 	
 	delete #(slicer1, slicer2)
 )

there is a benefit using plane instead of box. box is better.

Page 4 / 6