[Closed] 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 .
(this didn’t happen by the way I had a need for it doing something else, honestly )
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 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
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
newedges.count
)
resetMaxFile #noPrompt;
clearlistener();
s = CreateTheNightmare();
t = timestamp()
quadifier s 0.2 0.98
format "time:%
" (timestamp() - t)
)
or just use the optimize modifier ?
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
obj
)
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.
This method is not best solution (oldschool – from period when “Bomb” added to max) but do the job.
Another solid script is DETRIANGULATOR but is very slow and is not allways clean all “diagonals”.
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 !
basically this:
if PolyBoost.ValidEPbasemacro() do
PolyToolsModeling.Quadrify keyboard.shiftpressed keyboard.altpressed
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.
so graphite tool works… to protect material boundaries you can detach faces by id, apply quadifier, and weld them back.
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.
that script didn’t work properly, it added edges to one quad :surprised
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