the quadifier challenge


so the poor ol’ artist is crying into his screen, some third party plugin from “klunk enterprises” has converted his treasured model into all tris and he hasn’t backed up in like a gazillion years. Can you fix it for me comes the plea :frowning: .

(this didn’t happen by the way I had a need for it doing something else, honestly :slight_smile: )

anyway the challenge is to quadify the mesh, the function should make sensible decisions with topology and material boundaries. Sorry if this has been done to death and to prove i,m not looking for someone to fix a problem i created :wink: here’s my attempt

   	fn CreateTheNightmare =
   		p = Sphere radius:50.0 smooth:on segs:32 isSelected:on
   		converttomesh p
   		meshop.autoEdge p #all 0.0
   		converttoPoly p
   	fn getTheEdgeDir obj ed =
   		verts = polyop.getVertsUsingEdge obj ed as array;
   		normalize ((polyop.getVert obj verts[2]) - (polyop.getVert obj verts[1]))
   	fn getTheFaceAngle obj face1 face2 =
   		dot (polyop.getfacenormal obj face1) (polyop.getfacenormal obj face2)
   	fn quadifier obj quad_tol planar_tol =
   		getfacedegfn 		= polyop.getfacedeg;
   		getEdgesUsingFacefn = polyop.getEdgesUsingFace;
   		getEdgesUsingVertfn = polyop.getEdgesUsingVert;
   		getfacesUsingEdgefn = polyop.getfacesUsingEdge;
   		getfacematidfn 		= polyop.getfacematid;
   -- get suitable candidates (in this case this will select all the edges) 	
   		numedges = polyop.getnumedges obj;
   		edges = for i = 1 to numedges where 
   			(faces = getfacesUsingEdgefn obj i as array).count == 2 and 
   				getfacedegfn obj faces[1] == 3 and	getfacedegfn obj faces[2] == 3 collect i;
   -- refine the selection
   		newedges = for ed in edges where
   			ebitarray = #{ed}
   			faces = getfacesUsingEdgefn obj ed as array;
   			verts = polyop.getvertsUsingEdge obj ed as array;	
   			f1edges = getEdgesUsingFacefn obj faces[1];
   			f2edges = getEdgesUsingFacefn obj faces[2];
   			v1edges = getEdgesUsingVertfn obj verts[1];
   			v2edges = getEdgesUsingVertfn obj verts[2];
   			e1 = (v1edges * f1edges - ebitarray) as array;
   			e2 = (v1edges * f2edges - ebitarray) as array;
   			ang1 = abs(dot (getTheEdgeDir obj e1[1]) (getTheEdgeDir obj e2[1]));
   			e1 = (v2edges * f1edges - ebitarray) as array;
   			e2 = (v2edges * f2edges - ebitarray) as array;
   			ang2 = abs(dot (getTheEdgeDir obj e1[1]) (getTheEdgeDir obj e2[1]));
   			matid1 = getfacematidfn obj faces[1];	
   			matid2 = getfacematidfn obj faces[2];		
   			ang1 < quad_tol and ang2 < quad_tol and getTheFaceAngle obj faces[1] faces[2] > planar_tol  and  matid1 == matid2;
   		) collect ed;	
   		polyop.setEdgeSelection obj newedges
   	resetMaxFile #noPrompt;
   	s = CreateTheNightmare();
   	t = timestamp()
   	quadifier s 0.2 0.98 
   	format "time:%
" (timestamp() - t)

or just use the optimize modifier ?


There’s a button on the Graphite Toolbar which does this :wink:


this is what i was using for many years. with specific modifications for some specific case (keep face id or sm group zones for example, quadify every element separately, etc.)

mapped fn quadPolyObj obj = if iskindof obj GeometryClass do
	local new = snapshot obj isselected:off
	new.transform = matrix3 1
	resetXForm new
	converttomesh new
	local pbomb = Bomb detonation:0 minFragmentSize:2 maxFragmentSize:2 falloff:100
	bindSpaceWarp new pbomb
	local mesh = snapshotasmesh new
	delete pbomb
	meshop.autoEdge mesh mesh.edges 180
	new.mesh = mesh
	new.objectoffsetpos = -obj.objectoffsetpos
	new.transform = inverse (obj.objecttransform*(inverse obj.transform))
	resetXForm new
	converttopoly new
	local threshold = new.edgeWeldThreshold
	new.edgeWeldThreshold = 0.00001
	polyop.weldEdgesByThreshold new new.edges
	new.edgeWeldThreshold = threshold
	instancereplace obj new
	delete new
	delete mesh

this is not my idea, and as i said for this long time of using i forgot whose it is. i just optimized and polished it.
in most cases it works very well.


does the graphite tool protect material boundaries ? quick test says no but I’m not up on graphite and there maybe settings I’m missing.

that’s well wacky denis and quick too ! :slight_smile:


i killed the Graphite Toolbar on my machine… so what was it?


basically this:

if PolyBoost.ValidEPbasemacro() do
 	PolyToolsModeling.Quadrify keyboard.shiftpressed keyboard.altpressed


do you know what shift and alt do?


so graphite tool works… to protect material boundaries you can detach faces by id, apply quadifier, and weld them back.


but of course in Modifier Panel and for selected objects only… :slight_smile:


Selection related stuff:

<bool>Quadrify <bool>withinSel <bool>selectOnly
 When withinSelis set to true, applies to the current sub-object selection only.
 When selectOnly is set to true, does not remove but only selects the edges to be removed.


there is a slight issue with the graphite & denis method, I didn’t want all quads. Also the graphite tool doesn’t respect the topology in that though the edge is still there it makes it easier to “see” the shape with it.


Similar concept for this script


that script didn’t work properly, it added edges to one quad :surprised


well… but i use my script for more than seven years for sure.


This method is not best solution (oldschool - from period when “Bomb” added to max) but do the job.:slight_smile:
Another solid script is DETRIANGULATOR but is very slow and is not allways clean all “diagonals”.


that method you use Denis can be very destructive on some meshes for example

so cannot be trusted on detached meshes.


There is a Quadrify Mesh modifier that have some more options than the Quadrify Graphite Tool


is there ?


If I remember right, the bomb trick, relies on the correct order/indices of the mesh.
For better results, create an object, select a random part and detach, repeat process, then attach all.

I can see 2 types of solution:
. Find the correct topology/pattern just once by analyzing only a few faces, and then apply it to the rest of the mesh.
. Analyze everything.

I don’t know of any tool that solves this problem, flawlessly, or close.


This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.