Center Islands to Main 0-1 UV Space

Center Islands to Main 0-1 UV Space

rartidiello
Enthusiast Enthusiast
976 Views
10 Replies
Message 1 of 11

Center Islands to Main 0-1 UV Space

rartidiello
Enthusiast
Enthusiast

Hi,

I have a mesh with the UVs shifted. Thousands of Islands that after being packed, are shifted (adding/subtracting whole units) into different UV quadrants. I need a script that moves all islands to the main UV Space as it was packed originally. Island by island move them by whole units until they are in the 0-1 range (subtract the whole part of its position so it is U: 0,xxx V: 0,xxx).

Thanks.

0 Likes
Accepted solutions (1)
977 Views
10 Replies
Replies (10)
Message 2 of 11

denisT.MaxDoctor
Advisor
Advisor

Could you provide a picture of the desired result?

0 Likes
Message 3 of 11

rartidiello
Enthusiast
Enthusiast

yes sure,

rartidiello_0-1729118702270.png

 

0 Likes
Message 4 of 11

denisT.MaxDoctor
Advisor
Advisor
delete objects
--seed 0

/****************************** MAKE example mesh *************************/

mm = for k=1 to 100 collect (circle radius:(random 1 10) pos:(random -[100,100,0] [100,100,10]))
ms = mm[1]

converttomesh ms 
	
for k=2 to 100 do meshop.attach ms mm[k]
meshop.applyuvwmap ms #planar	
update ms


/***************************** PACK TV elements ***************************/

fn shiftMeshTvElement node tverts =
(
	u = 1e9
	v = 1e9

	pp = for tv in tverts collect
	(
		p = gettvert node tv
		if p.x < u do u = p.x
		if p.y < v do v = p.y
		p
	)
	shift = [u,v,0]

	k = 1
	for tv in tverts do
	(
		settvert node tv (pp[k] - shift) 
		k += 1
	)
)

fn getAllMeshTvElements node =
(
	numf = node.numfaces
	numt = getnumtverts node
	
	local faces = #{1..numf}
	
	local verts = for v = 1 to numt collect #()
	local undone = #{1..numt} 
	
	local elements = #()

	for k in faces do
	(
		f = gettvface node k

		append verts[f[1]] k
		append verts[f[2]] k
		append verts[f[3]] k		
	)

	for i in faces do
	(		
		element = #(i)
		tverts = #()
		for j in element where faces[j] do
		(
			faces[j] = false
			f = gettvface node j 
			
			for k=1 to 3 do 
			(
				v = f[k]
				if undone[v] do 
				(
					join element verts[v]
					undone[v] = false 
					append tverts v 
				)
			)
		)
		append elements (tverts as bitarray)
	)
	elements
)

tvs = getAllMeshTvElements ms
for tv in tvs do shiftMeshTvElement ms tv 
0 Likes
Message 5 of 11

rartidiello
Enthusiast
Enthusiast

I'm sorry but I don't think this script is moving the UV islands by whole units until they are in the main 0-1 UV space.

rartidiello_0-1729155605826.png

 

0 Likes
Message 6 of 11

denisT.MaxDoctor
Advisor
Advisor

The script finds all uv elements, calculates the bounding boxes of each element, and shifts the entire element by a given offset... that is 99% of the work. All you have to do is figure out how it works and add another 1% to make it work the way you want it to.

0 Likes
Message 7 of 11

rartidiello
Enthusiast
Enthusiast

I haven't make it work properly on my side😓. First the script is working for Editable Mesh and I needed it for Editable Poly(which I didn't specify) but even for Editable mesh it is not working as I need. For example in this sample Sphere.

rartidiello_0-1729600266713.png

rartidiello_3-1729600946781.png

 

it does this, and ignoring the peaks it is moving the islands to the origin (0.0.0) and not preserving their relative position on each quadrant.

rartidiello_1-1729600341781.png

this is the expected result.

rartidiello_2-1729600451116.png

 

 

 

 

0 Likes
Message 8 of 11

denisT.MaxDoctor
Advisor
Advisor
Accepted solution

delete objects
--seed 0

/****************************** MAKE example poly *************************/

mm = for k=1 to 100 collect (circle radius:(random 0.1 1) pos:(random -[100,100,0] [100,100,10]))
ms = mm[1]

converttopoly ms 
	
for k=2 to 100 do polyop.attach ms mm[k]
polyop.applyuvwmap ms #planar	
update ms
select ms

/***************************** PACK TV elements ***************************/


fn shiftPolyMapElement node tverts channel:1 =
(
	fn roundFloor value tolerance:0.000001 = 
	(
		d = (value as float)/tolerance
		v = if (d - (v1 = floor d)) > ((v2 = ceil d) - d) then v2 else v1 
		floor (v*tolerance)
	)

	u = 1e9
	v = 1e9

	pp = for tv in tverts collect
	(
		p = polyop.getmapvert node channel tv
		if p.x < u do u = p.x
		if p.y < v do v = p.y
		p
	)

	shift = [roundFloor u, roundFloor v,0]
	k = 1
	for tv in tverts do
	(
		polyop.setmapvert node channel tv (pp[k] - shift) 
		k += 1
	)
)

fn getAllPolyMapElements node channel:1 =
(
	numf = polyop.getnummapfaces node channel
	numt = polyop.getnummapverts node channel
	
	local faces = #{1..numf}
	
	local verts = for v = 1 to numt collect #()
	local undone = #{1..numt} 
	
	local elements = #()

	for k in faces do
	(
		num = polyop.getfacedeg node k
		f = polyop.getmapface node channel k
		for i=1 to num do append verts[f[i]] k		
	)

	for i in faces do
	(		
		element = #(i)
		tverts = #()
		for j in element where faces[j] do
		(
			faces[j] = false
			num = polyop.getfacedeg node j
			f = polyop.getmapface node channel j 
			
			for k=1 to num do 
			(
				v = f[k]
				if undone[v] do 
				(
					join element verts[v]
					undone[v] = false 
					append tverts v 
				)
			)
		)
		append elements (tverts as bitarray)
	)
	elements
)

tvs = getAllPolyMapElements $
for tv in tvs do shiftPolyMapElement $ tv 
0 Likes
Message 9 of 11

rartidiello
Enthusiast
Enthusiast

This is working perfect, thanks!

0 Likes
Message 10 of 11

denisT.MaxDoctor
Advisor
Advisor

I'll let the poorly learned lesson slide this time. But next time, I'll be stricter, and there will be no leniency!
☝️ 😎

 

In any case, try to understand how things work and the differences between the previous and final solutions.

0 Likes
Message 11 of 11

rartidiello
Enthusiast
Enthusiast

Yes! I will definetly check the differences in the solutions! Thanks for the nudge! 🙌

0 Likes