Created
September 8, 2026 12:23
-
-
Save unitycoder/8e2661a737333edc2264d361473f56a8 to your computer and use it in GitHub Desktop.
3ds max select similar polygons from current editable poly polygon selection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // chatgpt | |
| ( | |
| -- SETTINGS | |
| local tolerance = 0.001 | |
| local ignoreSize = false | |
| fn compareFloat a b = | |
| ( | |
| if a < b then -1 | |
| else if a > b then 1 | |
| else 0 | |
| ) | |
| fn getFaceSignature obj faceIndex ignoreSize = | |
| ( | |
| local verts = polyOp.getFaceVerts obj faceIndex | |
| local distances = #() | |
| -- Get every vertex-to-vertex distance. | |
| -- This describes the polygon shape regardless of rotation/orientation. | |
| for i = 1 to (verts.count - 1) do | |
| ( | |
| local p1 = polyOp.getVert obj verts[i] | |
| for j = (i + 1) to verts.count do | |
| ( | |
| local p2 = polyOp.getVert obj verts[j] | |
| append distances (distance p1 p2) | |
| ) | |
| ) | |
| qsort distances compareFloat | |
| -- Normalize if we only care about shape and not actual size. | |
| if ignoreSize and distances.count > 0 do | |
| ( | |
| local maxDistance = distances[distances.count] | |
| if maxDistance > 0.000001 do | |
| ( | |
| for i = 1 to distances.count do | |
| distances[i] /= maxDistance | |
| ) | |
| ) | |
| #(verts.count, distances) | |
| ) | |
| fn signaturesMatch sigA sigB tolerance = | |
| ( | |
| -- Different vertex count = different polygon. | |
| if sigA[1] != sigB[1] then | |
| return false | |
| local a = sigA[2] | |
| local b = sigB[2] | |
| if a.count != b.count then | |
| return false | |
| local epsilon = tolerance | |
| if a.count > 0 do | |
| ( | |
| epsilon = a[a.count] * tolerance | |
| if epsilon < 0.000001 do | |
| epsilon = 0.000001 | |
| ) | |
| for i = 1 to a.count do | |
| ( | |
| if abs(a[i] - b[i]) > epsilon then | |
| return false | |
| ) | |
| true | |
| ) | |
| if selection.count != 1 then | |
| ( | |
| messageBox "Select one Editable Poly object." | |
| ) | |
| else | |
| ( | |
| local obj = selection[1] | |
| if classOf obj.baseObject != Editable_Poly then | |
| ( | |
| messageBox "The selected object must be an Editable Poly." | |
| ) | |
| else | |
| ( | |
| local selectedFaces = polyOp.getFaceSelection obj | |
| if selectedFaces.numberSet != 1 then | |
| ( | |
| messageBox "Select exactly one polygon first." | |
| ) | |
| else | |
| ( | |
| local referenceFace = 0 | |
| for f in selectedFaces do | |
| referenceFace = f | |
| local referenceSignature = | |
| getFaceSignature obj referenceFace ignoreSize | |
| local result = #{} | |
| local faceCount = polyOp.getNumFaces obj | |
| for f = 1 to faceCount do | |
| ( | |
| local sig = getFaceSignature obj f ignoreSize | |
| if signaturesMatch referenceSignature sig tolerance do | |
| result[f] = true | |
| ) | |
| polyOp.setFaceSelection obj result | |
| subObjectLevel = 4 | |
| redrawViews() | |
| format "Selected % similar polygons.\n" result.numberSet | |
| ) | |
| ) | |
| ) | |
| ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment