Home Technical Talk

Triangulated Mesh Mess to Polyies from Nurbs.

polycounter lvl 18
Offline / Send Message
oXYnary polycounter lvl 18
I asked this in the Max plugin thread. But this might be more general and/or lost to someone who might otherwise see it if posted as own thread.

I have to take some medium high rez meshes. 10000-20000 tris and Convert into low poly models. They were initially created with Nurbs in sections. So its not one complete mesh, and Nurbs triangulates if you set no other options. The person I am getting these from has lost his nurb files and can only give me this triangulated mess.

I attempted using one of the max scripts that hides the longest edge to attempt to create polygons as so I can have a hell of an easier time working with edge loops and cleaner uv layout. Unfortunately, the way nurbs or at least these have been converted, the longest edge is not always the longest. Hell, even one of the submeshes is more than one object because nurbs split the portions versus making a continuous mesh. The picture below is one mesh with the subobject selected/converted. I realize that doesn't look bad. But thats that one subobject in that one mesh and there are about 20 different meshes in the scene.


edgepoly.gif

Is there another tool or triangle to edge plugin that works differently or methodology I should attempt? Most of these tools I think assume these were polygon models before. This is not the case.

Replies

  • frubes
    i use qaudrangulate to untriangulate stuff. It doesn't always work perfectly but i find its good for my needs.

    Check it out here:

    http://www.scriptspot.com/3ds-max/quadrangulate
  • renderhjs
    Offline / Send Message
    renderhjs sublime tool
    maybe open that script edit it and change it in a way that it only selects your longest edges instead of trying to remove them rightaway.
    That way you can check if the selection of the 'to be removed edges' is ok and make some tweaks, once the selection is final then hit ctrl+backspace to clear the selected edges and cleaning up the poly.
  • fast1
    frubes wrote: »
    i use qaudrangulate to untriangulate stuff. It doesn't always work perfectly but i find its good for my needs.

    Check it out here:

    http://www.scriptspot.com/3ds-max/quadrangulate

    thanks for the link.clear.gif
  • KikiAlex
    This is my script for this job, it has nothing to do with http://www.scriptspot.com/3ds-max/quadrangulate ,it works on selections,it only works on Editable Poly
    fn gaseste_daca_unghiu_dintre_tri_e_mic intrare index_1 index_2 =
    (
    test_1 = polyop.getFaceNormal intrare index_1
    test_2 = polyop.getFaceNormal intrare index_2
    rezultat = acos(dot (normalize test_1) (normalize test_2))
    return rezultat
    )
    
    --gaseste_daca_unghiu_dintre_tri_e_mic selection[1] 7 2
    
    fn bagi_un_edge_si_iti_spune_daca_e_bun obj index_e th =
    (
    	fete =polyop.GetEdgeFaces obj index_e
    	if (fete.Count >= 2) and ((polyop.getFaceVerts obj fete[1]).Count != 4) and ((polyop.getFaceVerts obj fete[2]).Count != 4) do
    		(	
    		iesire = gaseste_daca_unghiu_dintre_tri_e_mic obj fete[1] fete[2]
    		if (iesire <= th) do
    			(
    			return true
    			)
    		)
    	return false
    )
    
    
    --bagi_un_edge_si_iti_spune_daca_e_bun selection[1] 9 5
    
    fn bagi_o_selectie_raman_edgeuri_dintr_fete_paralele obj th =
    (
    	sel = polyop.getFaceSelection obj
    	sel2 = #()
    	for j in sel do
    	(
    		temp_sel = polyop.getFaceEdges obj j
    		for j in temp_sel do
    			(
    				if j != undefined do
    					(
    					append sel2 j
    					)
    			)
    	)
    	ce_iese = #()
    	for i in sel2 do
    		(
    			if (bagi_un_edge_si_iti_spune_daca_e_bun obj i th) do
    				(
    				if i != undefined do
    					(
    					append ce_iese i
    					)
    				)
    		)
    	return ce_iese
    )
    
    --print (bagi_o_selectie_raman_edgeuri_dintr_fete_paralele selection[1] 5)
    
    
    fn bagi_edgeuri_si_vezi_daca_au_acelas_sg_la_fete obj index_e =
    (
    	fete = polyop.GetEdgeFaces obj index_e
    	if (polyop.getFaceSmoothGroup obj fete[1]) == (polyop.getFaceSmoothGroup obj fete[2]) do
    		(
    			return true
    		)
    	return false
    )
    
    fn bagi_edgeuri_si_vezi_daca_au_acelas_mid_la_fete obj index_e =
    (
    	fete = polyop.GetEdgeFaces obj index_e
    	if (polyop.getFaceMatID obj fete[1]) == (polyop.getFaceMatID obj fete[2]) do
    		(
    			return true
    		)
    	return false
    )
    
    
    fn bagi_un_array_raman_duar_cu_acelas_smooth obj array_edgeuri =
    (
    	iesire_k = #()
    	for k in array_edgeuri do
    		(
    			if (bagi_edgeuri_si_vezi_daca_au_acelas_sg_la_fete obj k) do
    				(
    				append iesire_k k
    				)
    		)
    	return iesire_k
    )
    
    fn bagi_un_array_raman_duar_cu_acelas_mid obj array_edgeuri =
    (
    	iesire_k = #()
    	for k in array_edgeuri do
    		(
    			if (bagi_edgeuri_si_vezi_daca_au_acelas_mid_la_fete obj k) do
    				(
    				append iesire_k k
    				)
    		)
    	return iesire_k
    )
    
    
    
    fn bagi_selectie_scoti_op obj th sm  mid =
    (
    	if (sm == true) and (mid == false) do
    		(
    			rez = (bagi_un_array_raman_duar_cu_acelas_smooth obj (bagi_o_selectie_raman_edgeuri_dintr_fete_paralele obj th))
    			--polyop.SetEdgeSelection obj rez
    			return rez
    		)
    	if (sm == true) and (mid == true) do
    		(
    			rez = (bagi_un_array_raman_duar_cu_acelas_smooth obj (bagi_o_selectie_raman_edgeuri_dintr_fete_paralele obj th))
    			rez2 = bagi_un_array_raman_duar_cu_acelas_mid obj rez
    			--polyop.SetEdgeSelection obj rez2
    			return rez2
    		)
    	if (sm == false) and (mid == false) do
    		(
    			rez = (bagi_o_selectie_raman_edgeuri_dintr_fete_paralele obj th)
    			--polyop.SetEdgeSelection obj rez
    			return rez
    		)
    	if (sm == false) and (mid == true) do
    		(
    			rez = (bagi_un_array_raman_duar_cu_acelas_mid obj (bagi_o_selectie_raman_edgeuri_dintr_fete_paralele obj th))
    			--polyop.SetEdgeSelection obj rez
    			return rez
    		)
    	
    )
    
    
    fn fata_are_peste_2_pleaca_alea_scurte obj index_f array_edge scurte =
    	(
    		tdist = 0
    		e_ramas = undefined
    		edgurile_fete = (polyop.getFaceEdges obj index_f )
    		verifica = #()
    		for ef in edgurile_fete do
    			(
    				cp = (findItem array_edge ef) 
    				if (cp != 0) do
    					(
    					append verifica ef
    					)
    				if (verifica.Count > 1) then
    					(
    						for i in verifica do
    							(
    								arr = (polyop.getEdgeVerts obj i)
    								dis = (distance (in coordsys world polyop.getVert obj arr[1]) (in coordsys world polyop.getVert obj arr[2]))
    								--print dis
    								--print (findItem scurte i)
    								if (dis > tdist ) and ((findItem scurte i) == 0) then
    									(
    										e_ramas = i
    										tdist = dis
    									)
    								else
    									(
    										append scurte i
    									)
    							)
    					)
    			)
    			return e_ramas
    	)
    
    
    fn pastreaza_edgeuri_lungi obj th sg mID ramase=
    	(
    		scurte =#()
    		dupa_op = (bagi_selectie_scoti_op obj th sg mID)
    		fete_sel = polyop.getFaceSelection obj
    		for f in fete_sel do
    			(
    				de_tras = (fata_are_peste_2_pleaca_alea_scurte obj f dupa_op scurte)
    				if de_tras != undefined do
    					(
    					append ramase de_tras
    					)
    			)
    		--polyop.SetEdgeSelection obj (ramase as bitarray)
    		return ramase
    	)
    
    fn transforma_quad obj th sg Mid =
    (
    	undo "kiki2quad" on
    	(
    	ramase = #()
    	e_lungi = pastreaza_edgeuri_lungi obj.baseobject th sg mID ramase
    	de_sters = pastreaza_suprafata e_lungi selection[1].baseobject
    	polyop.SetEdgeSelection selection[1].baseobject (de_sters  as bitarray)
    	obj.Remove selLevel:#edge
    	ttp = Turn_TO_poly()
    	ttp.keepConvex = true
    	ttp.limitPolySize = true
    	ttp.MaxPolySize = 4
    	addModifier obj ttp
    	convertTo obj (Editable_poly)
    	)
    	
    )
    
    
    
    
    --print "XXXX"
    --print (bagi_un_array_raman_duar_cu_acelas_smooth selection[1].baseobject (bagi_o_selectie_raman_edgeuri_dintr_fete_paralele selection[1].baseobject 5))
    
    --bagi_selectie_scoti_op selection[1].baseobject 2 false !!ok
    
    --fata_are_peste_2_pleaca_alea_scurte (selection[1].baseobject) 1356 (bagi_selectie_scoti_op selection[1].baseobject 6 true)
    --fn obiect_de_curatat unghi_de_atac fii_atent_la_smooth_group fii_atent_la_material_id
    --pastreaza_edgeuri_lungi selection[1].baseobject 15 false  false
    --transforma_quad selection[1] 15 true  true
    fn pastreaza_suprafata edgeuri_condamnate obj =
    (
    	gratiate = #()
    	append gratiate 0 
    	for i = 1 to (polyop.GetNumFaces obj) do
    	(
    		edgeurile_fetei = (polyop.GetFaceEdges obj i)
    		martor = 0
    		for j in edgeurile_fetei do
    			(
    				if (findItem edgeuri_condamnate j) != 0 do
    					(
    					martor += 1
    					)
    			)
    		if (martor > 1) do
    			(
    				append gratiate i
    			)
    	)
    	
    	care_mor = #()
    	--print gratiate  
    	for e = 1 to edgeuri_condamnate.Count do
    		(
    			--print (findItem gratiate  edgeuri_condamnate[e])
    			if (findItem gratiate  edgeuri_condamnate[e]) == 0 do
    				(
    				append care_mor edgeuri_condamnate[e]
    				)
    		)
    	return care_mor
    )
    
    
    rollout tri2quad "tri2quad" width:245 height:104
    (
    	button ok_btn "select edges" pos:[7,69] width:99 height:32
    	spinner th_c "Search threshold" pos:[47,47] width:105 height:16 range:[0,360,24] type:#float scale:0.1
    	checkbox sm_grp "Look for Smoothing-Grups" pos:[7,3] width:203 height:20
    	checkbox mat_id "Look for Material-ID" pos:[7,24] width:203 height:20
    	button ok_c_ob "change object" pos:[128,69] width:99 height:32
    	
    	
    	on ok_btn pressed do
    		(
    			ramase = #()
    			e_lungi = pastreaza_edgeuri_lungi selection[1].baseobject th_c.Value sm_grp.State  mat_id.State ramase 
    			de_sters = pastreaza_suprafata e_lungi selection[1].baseobject
    			polyop.SetEdgeSelection selection[1].baseobject (de_sters as bitarray)
    			subObjectLevel = 2
    
    		)
    	
    	on ok_c_ob pressed do
    		(
    			transforma_quad selection[1] th_c.Value sm_grp.State  mat_id.State 
    		)
    )
    
    
    createdialog tri2quad
    
    
  • SyncViewS
    Offline / Send Message
    SyncViewS polycounter lvl 13
    Hi Andrew,
    here is my attempt at finding quad diagonals. It's very far from perfection and absolutely not optimized, but I hope it helps anyway. Just select a bunch of faces and press "Select!", it tries to find and select diagonal edges on most squared tri-couples. If no faces are selected, it works on the whole Editable Poly.
    rollout rolTest "Select Diags"
    (
        button btRun "Select!" width:90 align:#center offset:[0, -2]
    
        function getEdgeAngle oPoly iEdge01 iEdge02 =
        (
            if ((classOf oPoly) != Editable_Poly) then
                throw "Wrong input in function: getEdgeAngle() - Invalid Editable Poly"
    
            if ( ((classOf iEdge01) != Integer) or ((classOf iEdge02) != Integer) ) then
                throw "Wrong input in function: getEdgeAngle() - Invalid Edge Indexes"
    
            local baVertsFromEdge01 = polyOp.getVertsUsingEdge oPoly iEdge01
            local baVertsFromEdge02 = polyOp.getVertsUsingEdge oPoly iEdge02
    
            local baOrigin = baVertsFromEdge01 * baVertsFromEdge02
            local iOrigin = 0
    
            if (baOrigin.isEmpty == true) then
                throw "Wrong input in function: getEdgeAngle() - Edges do not share a vertex"
            else
                iOrigin = (baOrigin as Array)[1]
    
            local p3Origin = polyOp.getVert oPoly iOrigin
    
            local p3Vector01 = (polyOp.getVert oPoly ((baVertsFromEdge01 - baOrigin) as Array)[1]) - p3Origin
            local p3Vector02 = (polyOp.getVert oPoly ((baVertsFromEdge02 - baOrigin) as Array)[1]) - p3Origin
    
            return (acos(dot (normalize(p3Vector01)) (normalize(p3Vector02))))
        )
    
        function selQuadDiagonals oPoly =
        (
            if ((classOf oPoly) != Editable_Poly) then
                throw "Wrong input in function: selQuadDiagonals()"
    
            local baFaceSelection = polyOp.getFaceSelection oPoly
    
            if (baFaceSelection.isEmpty == true) then
                baFaceSelection = #{1..(polyOp.getNumFaces oPoly)}
    
            local baTriFaces = #{}
    
            for iFace in baFaceSelection do
                if ((polyOp.getFaceDeg oPoly iFace) == 3) then
                    baTriFaces[iFace] = true
    
            local baDiagonals = #{}
    
            for iTriFace in baTriFaces do
            (
                local baTriEdges = polyOp.getEdgesUsingFace oPoly iTriFace
    
                local aiEdgeIndex = #()
                local afAngleRatio = #()
    
                local aaEdgeData = #()
    
                for iTriEdge in baTriEdges do
                (
                    local baNearFace = (polyOp.getFacesUsingEdge oPoly iTriEdge) - #{iTriFace}
    
                    if (baNearFace.isEmpty == false) then
                        if ((polyOp.getFaceDeg oPoly (baNearFace as Array)[1]) != 3) then
                            baNearFace = #{}
    
                    if (baNearFace.isEmpty == true) then
                    (
                        local aiEdges01 = (baTriEdges - #{iTriEdge}) as Array
                        local fAngleRatio = abs( (90 - getEdgeAngle oPoly aiEdges01[1] aiEdges01[2]) )
    
                        append aaEdgeData #(fAngleRatio, 0)
                    )
                    else
                    (
                        local baNearFaceEdges = polyOp.getEdgesUsingFace oPoly baNearFace
    
                        local aiEdges01 = (baTriEdges - #{iTriEdge}) as Array
                        local aiEdges02 = (baNearFaceEdges - #{iTriEdge}) as Array
                        local fAngleRatio = abs( (90 - getEdgeAngle oPoly aiEdges01[1] aiEdges01[2]) + (90 - getEdgeAngle oPoly aiEdges02[1] aiEdges02[2]) )
    
                        append aaEdgeData #(fAngleRatio, iTriEdge)
                    )
                )
    
                local minRatio = 360
                local iDiagonal = 0
    
                for aData in aaEdgeData do
                (
                    if (aData[1] < minRatio) then
                    (
                        iDiagonal = aData[2]
                        minRatio = aData[1]
                    )
                )
    
                if (iDiagonal != 0) then
                    baDiagonals[iDiagonal] = true
            )
    
            setCommandPanelTaskMode #modify
            subObjectLevel = 2
    
            polyOp.setEdgeSelection oPoly baDiagonals
            forceCompleteRedraw()
        )
    
        on btRun pressed do
        (
            if ( (selection.count == 1) and (classOf selection[1] == Editable_Poly) ) then
            (
                selQuadDiagonals selection[1]
            )
        )
    
    ) -- End Rollout
    
    createDialog rolTest 96 27 style:#(#style_toolwindow, #style_border, #style_sysmenu)
    
  • oXYnary
    Offline / Send Message
    oXYnary polycounter lvl 18
    Thanks KikiAlex and SyncViewS. I attempted both your scripts. Obviously because of the way these were created (nurbs :P ), I wont get perfect results. But so you can compare.

    comparisontri.gif
  • ArtsyFartsy
    I spend about two weeks at some point trying to figure out the same thing and there's no good way to do it. After each method you'll always have to do a lot of additional touchups by hand. It's why NURBS are shit and nobody uses them anymore.

    Might be easier to just rebuild some of your geometry. Try selecting crossections (edges), separating them from the mesh, and then bridging them together through edit poly or loft.
Sign In or Register to comment.