Home Technical Talk

[MaxScript] Selecting UVs by proximity

Ai_
polycounter lvl 6
Offline / Send Message
Ai_ polycounter lvl 6
Hey Polycount! I got a (newbie) Maxscript question. The task seems fairly simplistic but I keep running into technical issues. Here's what I wanna do:
-make a cycle that takes every UV vertex, calculates its' distance to every other UV of the model;
-for every pair of UV vertices check distance between them;
-if some of the UV vertices are too close to each other (distance less than a certain amount), select them.
After some experimenting here's what I ended up with:
theobj = selection[1]
addModifier theobj (Unwrap_UVW())
uv = theobj.modifiers[#Unwrap_UVW]
closeuvs = #()
closeuvs.count = theobj.numtverts
texVertIndices = #{1 .. theobj.numtverts}	
texVerts = for texVertIndex in texVertIndices collect (getTVert theobj texVertIndex) --collecting all the vertices
for i = 1 to theobj.numtverts do
	(
        -- take UV coordinates of every vertex
	ivertX = texVerts[i].x
	ivertY = texVerts[i].y
        -- and compare them to coords of every other vertex
	for j = 1 to theobj.numtverts do
		(
		if j != i do
			(
			jvertX = texVerts[j].x
			jvertY = texVerts[j].y
			--calculate the shortest distance between the i vertex and the j vertex
			resX = jvertX - ivertX
			resY = jvertY - ivertY
			finX = resX^2
			finY = resY^2
			resdist = finX + finY
			findist = sqrt resdist
			--distance calculated
			if findist <= 0.25 then closeuvs[i] = 0
			else closeuvs[i] = 1 --vertices that should be selected are marked with 0
			)
		)
	
	)
resultuvs = for m in closeuvs where closeuvs[m] == 0 collect (getTVert theobj m) --collect close vertices into an array
uv.selectVerticesByNode resultuvs theobj --and select it
This code seems to check the UV distance just fine but if it finds any close uvs I'm still getting an error: "Runtime error: Mesh TVertex index out of range: 0"
I know I'm probably missing something super obvious but I can't seem to figure it out, maybe you tech-wizards can help me :)
Thank you!

Replies

  • monster
    Options
    Offline / Send Message
    monster polycounter
    So I didn't get the same error you have above. MaxScript usually tells you the line that it errored on, that's a good place to start.

    The error I see is that you are trying to select an array of Point3 values (resultsuvs). The select commands only work on bitArrays.

    There are several workflow improvements you can make to this script faster.

    1. I know it seems reasonable to store lots of information and then process that data. But memory is slow and the processor is fast. So it's always faster to check data as you loop through it instead of storing it and checking it later.
    2. Use the "Distance" function instead of doing the math manually.
    3. Use the UnwrapUVW functions for getting vertex counts and UV positions so that your script can run on EPoly or EMesh objects.
    4. When using an index loop use a saved variable instead of constantly accessing a property or function. Fast (for i = 1 to var) Slow (for i = 1 to array.count)
    5. Use the Where context instead of doing an if check when starting a loop.
    6. 0.25 is actually a pretty large threshold. It's about 1/4 the size of the 0-1 UV space. So in my example I have it set to 0.01.
    (
    	clearlistener()
    	t = timeStamp()
    	
    	threshold = 0.01
    	
    	theobj = selection[1]
    
    	max modify mode
    	uv = modPanel.getCurrentObject()
    	
    	if classof uv != Unwrap_UVW do
    	(
    		uv = Unwrap_UVW()
    		addModifier theobj uv
    	)
    
    	--GET NUMBER OF TVERTS
    	tvCount = uv.NumberVertices() 
    	
    	--UVs TO SELECT WHEN THE SCRIPT IS DONE
    	closeuvs = #{}
    	
    	--SAVE A COUPLE OF COMMANDS THAT WILL BE ACCESSED OFTEN
    	getVertexPosition = uv.getVertexPosition
    	frame = sliderTime
    
    	for i = 1 to tvCount do
    	(
    		-- TAKE UV COORDINATES OF EVERY VERTEX
    		iVert = getVertexPosition frame i
    		ivertX = iVert.x
    		ivertY = iVert.y
    
    		-- AND COMPARE THEM TO COORDS OF EVERY OTHER VERTEX
    		for j = 1 to tvCount where j != i do
    		(
    			jVert = getVertexPosition frame j
    			findist = distance [ivertX, ivertY] [jVert.x, jVert.y]
    			
    			--VERTS WITHIN THE THRESHOLD SHOULD BE ENABLED IN THE BIT ARRAY
    			if findist <= threshold then
    			(
    				--format "iVert[%] = %, % \tjVert[%] = %, % \tfindist: %\n" i ivertX ivertY j jVert.x jVert.y findist
    				closeuvs[i] = true
    				closeuvs[j] = true
    			)
    		)
    		
    	)
    	
    	uv.selectVertices  closeuvs
    	subobjectlevel = 1
    
    	format "%s\n" ((timeStamp()-t)/1000.0)
    	
    	max views redraw
    )
    
  • Ai_
    Options
    Offline / Send Message
    Ai_ polycounter lvl 6
    Wow, thank you so much, monster, that was really comprehensive!
    0.25 is obviously just a value for this example, for the same reason I didn't bother fixing all the various optimization problems.
    The error I see is that you are trying to select an array of Point3 values (resultsuvs). The select commands only work on bitArrays.
    Oh, I see, that was the main problem. I totally used the wrong data type. Thanks for clarifying it.
    2. Use the "Distance" function instead of doing the math manually.
    Well that's embarrassing lol. I did not even know that function was a thing :D
Sign In or Register to comment.