@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 didnt 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)
)
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]
)
)
)
this is not a first time when i see it in your very nice codes…
meshop.breakVerts m #all
it could mike it nicer
Thank you Denis. You haven’t seen it in my codes because I had no idea of that shortcut Are this things documented somewhere?
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.
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 didnt 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.
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
i didn’t know about logical weld as well. now i understand how break-and-weld can help.
here is a version that kinda works. it’s not fast, it’s not memory friendly. but it can be optimized:
fn breakTVerts node:selection[1] =
(
converttomesh node
mesh = snapshotasmesh node
meshop.breakverts mesh #all
setnumtverts node mesh.numtverts
buildtvfaces node
tverts = for v=1 to mesh.numtverts collect
(
p = (gettvert mesh v) as point4
settvert node v p
p
)
tfaces = for f=1 to mesh.numfaces collect
(
vv = getface node f
tt = gettvface mesh f
for k=1 to 3 do tverts[tt[k]][4] = vv[k]
settvface node f tt
tt
)
#(tfaces, tverts)
)
fn weldTVVerts node:selection[1] data: =
(
vv = for v=1 to data[2].count collect finditem data[2] data[2][v]
for f=1 to node.numfaces do
(
v1 = data[1][f][1]
v2 = data[1][f][2]
v3 = data[1][f][3]
k1 = vv[v1]
k2 = vv[v2]
k3 = vv[v3]
settvface node f [k1,k2,k3]
)
meshop.deleteisomapvertsall node
node.numfaces
)
t1 = timestamp()
data = breakTVerts()
t2 = timestamp()
num = weldTVVerts data:data
t3 = timestamp()
format "faces:% time:%
" num #(t2-t1, t3-t2, t3-t1)
the weak place in the algorithm is a search… we definitely shouldn’t search every vertex against all other.
Yeah !
faces:96190 time:#(2163, 396265, 398428)
well 6,7 min instead of 45. That’s already a huge improvement.
Thank you very much !
With this effortless simple optimization it runs 2X faster for 50K mesh.
vv = for v=1 to data[2].count collect
(
if (found = finditem data[2] data[2][v]) < v do data[2][v] = ()
found
)
– faces:49690 time:#(414, 87874, 88288)
– faces:49690 time:#(399, 45416, 45815)
after changing my algorithm to use bsearch i have !!!
faces:79504 time:#(9481, 5361, 14842)
I think I would approach this a bit differently and fix the UVs at load time when the initial mesh is built with a custom importer either scripted or sdk. Obviously sdk would be best but I think a scripted routine may well have the edge over fixing the current mesh.
Having that option in the .OBJ import plugin would be great, but developing a custom plugin seems a bit too much, thought modifying one you already have is not a bad idea.
To me, in this case, it can be done efficiently with mxs. Of course, everything you can do with the SDK could be 10-100 times faster and more memory friendly, but sometimes it is a matter of balance, IMHO.
In the end, what we are trying to find is an efficient algorithm to fix the UVs. Where you implement it (plugin, script, at import time, in a macro…) is a different thing.