Notifications
Clear all

[Closed] Break and Weld UV's on 100k tris meshes

And here is the compact version which has a little penalty in speed but looks clearer, as Denis suggested.

(
 fn BreakAndWeldAllUvwVerts obj =
 (
 	mesh = snapshotasmesh obj
 	
 	setnumtverts obj (obj.numfaces*3)
 	buildtvfaces obj
 
 	verts = for j = 1 to obj.numverts collect #()
 	idx = deepcopy verts
 
 	for j = 1 to obj.numfaces do
 	(
 		f1 = getface obj j
 		f2 = gettvface mesh j
 		f3 = [j*3,j*3-1,j*3-2]
 
 		for i = 1 to 3 do
 		(
 			p = gettvert mesh f2[i]
 			if (k = finditem verts[f1[i]] p) == 0 then
 			(
 				append verts[f1[i]] p
 				append idx[f1[i]] f3[i]
 			)
 			else f3[i] = idx[f1[i]][k]
 			
 			settvert obj f3[i] p
 		)
 		settvface obj j f3
 	)
 )
 gc()
 st = timestamp(); sh = heapfree
 BreakAndWeldAllUvwVerts $
 format "faces:% time:% ram:%
" $.numfaces (timestamp()-st) (sh-heapfree)
 )

Hey Jorge
You said that second for-loop causes slowdown
I don’t know if mapped fn can helps here but still…
I mean about this concept. Maybe it can replace “for i = 1 to 3 do ()”

verts = #()
 idx = #()
 a = #(1,2,3)
 
 mapped fn test a &verts &idx =
 (
 	verts[a] = "v" + a as string
 	idx[a] = "i" + a as string
 )
 test a &verts &idx
2 Replies
(@polytools3d)
Joined: 11 months ago

Posts: 0

Thank you Branko for bringing this up. I’ve tried mapping the inner loop as well as the main loop and both options were slower and used more memory.

The “compact” version, is not a lot slower as is, but I was losing half of the optimization I did. So I went from 1000 down to 500 and then up to 750 (aprox.)

Anyway, for 100K mesh 250ms is nothing if you like the clearer code better.

(@gazybara)
Joined: 11 months ago

Posts: 0

Great result you achive here. Then mapped fn have same performance issue as for-loop.
Good to know that. Also adding items like I did maybe is not good way. Append fn probably produce faster result.

see some suggestions in red... i don't have max right now to test it.

Almost no difference (6 ms in a 100K mesh). On a fresh session I got:

#55 faces:99380 time:560 ram:16968168L
#56 faces:99380 time:715 ram:16968200L
#60 faces:99380 time:709 ram:16968168L

I am not sure the 560ms version could be much faster, as profiling it show that around 300 ms goes just to the get/set vertex and face operations, and the other 260 are for the if statements, append and finditem.

here is another optimization… the speed is almost the same as the best but memory is used better, and code in better organized:

fn breakAndWeldUVWs node: =
(
	converttomesh node
	tverts = for v=1 to node.numtverts collect gettvert node v 
	mesh = snapshotasmesh node
	meshop.applyuvwmap node #face  
		
	verts = for v=1 to node.numverts collect #()
	index = deepcopy verts
	for f=1 to node.numfaces do
	(
		f1 = getface node f
		f2 = gettvface node f
		f3 = gettvface mesh f
		for i=1 to 3 do
		(
			if (k = finditem verts[f1[i]] tverts[f3[i]]) == 0 then
			(
				append verts[f1[i]] tverts[f3[i]]
				append index[f1[i]] f2[i]
				settvert node f2[i] tverts[f3[i]]
			)
			else f2[i] = index[f1[i]][k]
		)
		settvface node f f2
	)
	--meshop.deleteisomapvertsall node -- it's what we have to do finally
	node.numfaces
)

gc light:on
t1 = timestamp()
m1 = heapfree
num = breakAndWeldUVWs node:objects[1]
format "faces:% time:% memory:%
" num (timestamp() - t1) (m1 - heapfree) 

i do convert to mesh to make the function undoable… and we also have to delete isolate map verts

Yes Denis, that used less memory and I forgot to delete the isolated vertices.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

our appends take 80% of memory and performance. so probably the current algorithm reached the bounds

Ok, here is the final one with converttomesh and delete dead vertices.

(
 	
 	/*
 	
 	Version 0.1 | 02.18.14
 		Original
 
 	Version 0.2 | 02.18.14
 		Speed & Memory optimizations
 	
 	Version 0.3 | 02.19.14
 		Improved Algorithm - 2X faster
 	
 	Version 0.4 | 02.20.14
 		Add converttomesh and clean dead vertices (Thanks denisT)
 	
 	/////////////////////////////////////////////////////////////////////////////////////////////////
 	
 	Description:
 	
 	This script will break all UVW vertices on the selected mesh and then weld those UVW
 	vertices that are on the exact same Geometry and UVW position.
 
 	/////////////////////////////////////////////////////////////////////////////////////////////////
 	
 	*/	
 
 	fn BreakAndWeldAllUvwVerts obj =
 	(
 		converttomesh obj
 		mesh = snapshotasmesh obj
 		
 		setnumtverts obj (obj.numfaces*3)
 		buildtvfaces obj
 
 		verts = for j = 1 to obj.numverts collect #()
 		idx = deepcopy verts
 		
 		for j = 1 to obj.numfaces do
 		(
 			f1 = getface obj j
 			f2 = gettvface mesh j
 			
 			i3 = j*3
 			i2 = i3-1
 			i1 = i3-2
 			
 			v1 = gettvert mesh f2[1]
 			v2 = gettvert mesh f2[2]
 			v3 = gettvert mesh f2[3]
 			
 			k1 = finditem verts[f1[1]] v1
 			k2 = finditem verts[f1[2]] v2
 			k3 = finditem verts[f1[3]] v3
 
 			if k1 == 0 then
 			(
 				append verts[f1[1]] v1
 				append idx[f1[1]] i1
 			)
 			else i1 = idx[f1[1]][k1]
 
 			if k2 == 0 then
 			(
 				append verts[f1[2]] v2
 				append idx[f1[2]] i2
 			)
 			else i2 = idx[f1[2]][k2]
 
 			if k3 == 0 then
 			(
 				append verts[f1[3]] v3
 				append idx[f1[3]] i3
 			)
 			else i3 = idx[f1[3]][k3]
 			
 			settvert obj i1 v1
 			settvert obj i2 v2
 			settvert obj i3 v3
 			
 			settvface obj j [i1,i2,i3]
 		)
 		
 		meshop.deleteisomapvertsall obj
 
 	)
 	
 	gc()
 	st = timestamp(); sh = heapfree
 	BreakAndWeldAllUvwVerts $
 	format "faces:% time:% ram:%
" $.numfaces (timestamp()-st) (sh-heapfree)
 	
 )
1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

why do we do convert to mesh? the only reason is to make our “mapping works” undoable. honestly i’ve picked the most sure operation. but who can find most cheaper mesh operation that forces the mesh holds its stage (per se, makes mapping operations undoable)

couple comments:
#1 some mesh operations might be slower if the mesh selected
#2 some mesh operations might be slower if command panel is in #modify mode

it’s because of some notification messages sent by mesh to the system in one ore another situation

2 Replies
(@polytools3d)
Joined: 11 months ago

Posts: 0

Yes, and that was introduced with this

converttomesh obj

Other than that, the algorithm works on the fly and selection doesn’t affect it, neither does the modify panel.

(@denist)
Joined: 11 months ago

Posts: 0

here is my numbers:

--both selected and not selected in #create mode:
faces:49690 time:632 memory:7045248L
--not selected in #modify mode:
faces:49690 time:705 memory:7052448L
--selected in #modify mode:
faces:49690 time:819 memory:7058616L
--selected in #modify mode in subobject mode :
faces:49690 time:881 memory:7062520L

Yes Denis, as I mentioned that was introduced by the mesh convertion. If you comment the following line you would get the same results selected or not, in modify panel or not. I get ±5ms for each test for a 100K mesh.

converttomesh obj

I added it because you suggested it to make the function undoable.

ok. after all please tell me what is the practical use of all we cooked here?

Page 5 / 6