Break and Weld UV's on 100k tris meshes


#1

Hello !

So i have those many CAD objects imported as meshes in max.
I’d like to use uv’s generated by the CAD software as they are pretty good already but they also have some issues.

First, a lot of map vertices are welded together even if the vertices on the mesh aren’t spatially at the same place.
I’ve found a way to fix this by breaking all uv vertices and reweld them.
But this action takes forever on a huge mesh (50k vertices,100k tris). Canceled after 20min just for breaking.
Do you think there would be a smarter way to do this via maxscript ?
I was thinking that, for instance, there’s no need for the weld to look into a treshold as vertex are directly on top of each others.
Thanks for any hints.


#2

a small sample file may help


#3

Ok. I took a small part ot the mesh and duplicated to match the 100k
https://dl.dropboxusercontent.com/u/13762052/polycount/cad_unwrap_test.obj
You can see that this duplicated part has only one uv element which is a total non sense. I don’t even get how max authorize this.
Anyway, as i said, the workaround i’ve found is to break all points and weld them. Not really an issue for a small mesh. I guess i could split big meshes in small parts, taking care to not destroy the edited normals.


#4

what do you use to break and weld back map vertices? unwrap_uvw?
using just pure mxs it shouldn’t take more than ~2-3 secs for 50K verts mesh


#5

Yeah,this what i do, considering there’s an unwrap on the object


obj = selection[1]
myUV = obj.modifiers[1] 
myUV.unwrap6.selectVerticesByNode #{1..obj.numverts} obj
myUV.breakSelected() 
myUV.setWeldThreshold 0.0001
myUV.weldSelected() 

It obviously doesn’t take 3 sec D:


#6
fn FakeDetach msh elementFaces = ( meshop.detachFaces msh elementFaces )	

fn ForAllElements msh theFunction =
(
	faces = msh.faces as bitarray;
	while not faces.isEmpty do
	(	
		elemfaces = meshop.getElementsUsingFace msh #((faces as array)[1]); -- this is what slows us down and also requires the gc() call or else we'll run out of memory
		theFunction msh elemfaces;
		faces = faces - elemfaces;
		gc();
	)
)	

ForAllElements $ FakeDetach

this will do what you want takes about 4mins on the sample file


#7

though the quickest way to get the result is to use explode in the mesh edit geometry panel, set the angle to 180 and use to elements.


#8

Ok sorry, the sample file isn’t representative. Each object is watertight, made of 1 element. I cant parse elements to detach them.
I’ve reuploaded the obj. It’s a small part, only 2,5k point, but same principle, with “corrupted” uvs.


#9

The following code should break all UVW vertices. Welding them is a different thing and I am unsure of how would you accomplish that.

Looks like the source mapping, in the model you uploaded, is highly corrupted and there are many UVW vertices placed on the exact same positions, so welding all of them at once with a threshold will weld vertices that probably belong to different UVW shells.

The code can be easily adapted to work with Editable Poly and with different mapping channels.
(
    
    fn BreakAllUvwVerts obj =
    (
        if obj.modifiers.count == 0 and classof obj == editable_mesh do
        (
            m = snapshotasmesh obj
            meshop.breakVerts m #{1..m.numverts}
            
            numtverts = getnumtverts m
            
            setnumtverts obj numtverts
            buildtvfaces obj
    
            for j = 1 to numtverts do settvert obj j (gettvert m j)
            for j = 1 to m.numfaces do settvface obj j (gettvface m j)
            )
    )
    
    st = timestamp(); sh = heapfree
    BreakAllUvwVerts $
    format "time:% ram:%
" (timestamp()-st) (sh-heapfree)
    
    )

#10

honestly i don’t believe that this can fix the mapping.


#11

Well it does, I did the sequence several times on different imports and it always worked. The “re-weld” doesn’t weld points that aren’t physically at the same place, fixing the 1st issue.
Then I have to re run a break on open edges to actually separate all elements.
Then i run a script to fix the texel ratio, then a bit of manual stitching
I needed it to be faster as i have hundreds of objects. In the end it’s still faster than redoing the unwrap manually from scratch.

   Thanks Polytools, i've already seen you using that snapshot voodoo magic. Tbh i'm not sure to get what it does, but it's fast. Do you think that welding wouldnt work as the unwrap weld ? I just need it to not weld points that arent at the same physical place.

#12

@Clanker,
I am not sure of the whole process you are doing or what results you are looking for so my comment is purely related to the file you uploaded and the script you posted.

 So, if I import the .OBJ file and run your script, I am not getting anything good (from my point of view). But perhaps I am missing part of the process you do, and so my comments about this are useless.
 
 The first script I posted was to just break the UVW vertices, as I didn’t know is the welding you use in your script worked for you. Now that you mention that your script does indeed work as you need, I added the weld part to the original script. So here it is, this script should break all the UVW vertices, and then weld those which are at the same location. In short, you should get the same result as with the snippet you posted but faster.
 
 I think there is still room for optimization, but it performs pretty well compared it with the Unwrap UVW modifier break/weld functions.

If it works for what you need I am not sure it would worth it to keep working on optimizations.
 
 I got these results:
 faces:99380 time:2839 ram:25872632L

Edit: Minor improvement in memory ussage speed.
faces:99380 time:2559 ram:19112856L

(
   	
   fn BreakAndWeldAllUvwVerts obj weld:false =
   (
   	
   	if obj.modifiers.count != 0 do return -1
   	if classof obj != editable_mesh do return -1
   	
   	m = snapshotasmesh obj
   	meshop.breakVerts m #{1..m.numverts}
   
   	numtverts = getnumtverts m
   	
   	setnumtverts obj numtverts
   	buildtvfaces obj
   
   	for j = 1 to numtverts do settvert obj j (gettvert m j)
   	for j = 1 to m.numfaces do settvface obj j (gettvface m j)
   	
   	if weld == true do
   	(
   		tverts = for j = 1 to numtverts collect (gettvert m j)
   		setnumtverts obj numtverts
   		buildtvfaces obj
   		
   		for j = 1 to numtverts do settvert  obj j tverts[j]
   		
   		for j = 1 to m.numfaces do
   		(
   			face = gettvface m j
   			v1 = face[1]
   			v2 = face[2]
   			v3 = face[3]
   
   			if (found = finditem tverts (gettvert m v1)) != 0 do v1 = found
   			if (found = finditem tverts (gettvert m v2)) != 0 do v2 = found
   			if (found = finditem tverts (gettvert m v3)) != 0 do v3 = found
   
   			settvface obj j [v1,v2,v3]
   		)
   	)
   
   )
   
   gc()
   st = timestamp(); sh = heapfree
   BreakAndWeldAllUvwVerts $ weld:true
   format "faces:% time:% ram:%
" $.numfaces (timestamp()-st) (sh-heapfree)
   
   )

#13

faces:99380 time:2839

these are the right numbers


#14

Here is a compact Break&Weld version that runs a little bit faster

(
  	
  fn BreakAndWeldAllUvwVerts obj =
  (
  	if obj.modifiers.count != 0 do return -1
  	if classof obj != editable_mesh do return -1
  	
  	m = snapshotasmesh obj
  	meshop.breakVerts m #all
  
  	numtverts = getnumtverts m
  	
  	setnumtverts obj numtverts
  	buildtvfaces obj
  	
  	tverts = for j = 1 to numtverts collect (gettvert m j)
  	for j = 1 to numtverts do settvert obj j tverts[j]
  	
  	for j = 1 to m.numfaces do
  	(
  		face = gettvface m j
  		v1 = finditem tverts (gettvert m face[1])
  		v2 = finditem tverts (gettvert m face[2])
  		v3 = finditem tverts (gettvert m face[3])
  		settvface obj j [v1,v2,v3]
  	)
  )
  	
  )

#15

this is not a first time when i see it in your very nice codes…


	meshop.breakVerts m #all
 

it could mike it nicer


#16

Thank you Denis. You haven’t seen it in my codes because I had no idea of that shortcut Are this things documented somewhere?


#17

No it doesn’t do the same thing as unwrap weld.
But your first script already speeds up the workflow *2, so many thanks. I’m not sure i really need the weld, as time required is more acceptable, except if you take it as a challenge. But if you have better things to do,don’t worry.

So, i'll try to be clear.

The issue on source mesh : some map vertices are welded together even if the points on the mesh aren't at the same place.

When using the unwrap weld, map vertices corresponding to points physically at the same place are welded (logical). 
However, previously welded uv corresponding to points that are NOT at the same place are now broken. 

So, now UV shells that shares the same mesh points will still be welded. But I can now select open edges an break. Voilà, now all my elements are separated. 

I don't think i can perform thoses 2 actions at the same time. I need to fix the first issue before selecting open edges on the source mesh (mess!)

You can try to weld in the unwrap after running your first script, and see that you can move more elements apart. With the second script you cannot.

Anyway, thanks again for your time.

#18

Well, no matter how I test it, I allways get exactly the same result using the Unwrap weld or the script I posted. So it does do the same thing as the Unwrap weld on my end.

 This leads me to think we might not be using the same Max version. I am on 2011 and I suppose you are on 2012+, which introduced new methods for welding the uvw verts.

When using the unwrap weld, map vertices corresponding to points physically at the same place are welded (logical).
Yes, that would be the logical way of doing it, and that was what confused me, because I didn’t understand why would you like to weld all the uvw vertices at the same place.

     So what you need is to weld all UVW vertices that are at the same UVW and GEO positions and that belongs to the same GEO element.

#19

Ah yeah i’m on 2012, should have specified that. And now you say that, i remember a thread with someone complaining about this new weld behavior. But actually i think it makes more sense.

And yes, that’s what i’d need, tho i have only 1 GEO element per object :slight_smile:


#20

i didn’t know about logical weld as well. now i understand how break-and-weld can help.