-- Title : uvHelpV201 -- UV helper tools, minimize UV distorition -- Copyright : © 2004 MicroCAN, All rights reserved -- Author : Carl van Heezik -- Version : 2.01 -- Changes : Aug xx, 2004 complete new stable algorithm -- Sep 10, 2004 bring up edit window -- restore subObjectLevel -- edgeScale global -- Homepage : www.microcan.nl --------------------------------------------------------------------------------------------- -- MODIFY THIS AT YOUR OWN RISK MacroScript uvHelpV2 ButtonText: "uvHelp" Category: "uvHelp" Tooltip: "minimize UV distortion" -- Needs Icon ( -- update quad menu, the script needs the Unwrap_UVW modifier on isVisible return ((classof(modPanel.GetcurrentObject())) == Unwrap_UVW) on isEnabled return ((classof(modPanel.GetcurrentObject())) == Unwrap_UVW) -- the main script body on execute do ( global versionText = "uvHelp V2.01" global dialog global setDefaults -- dialog dimensions and position global width global height global left global top global edgeScale -- V2.01 global lockScale -- V2.01 global iterations -- V2.01 global bringUpDialog -- default values if (setDefaults == undefined) then ( setDefaults = false width = 218 height = 190 left = 0 top = 100 edgeScale = 1 -- V2.01 lockScale = false -- V2.01 iterations = 100 -- V2.01 bringUpDialog = false -- V2.01 ) -- define the dialog layout rollout rolloutAbout "About" rolledUp:true ( group "About" ( label labelVersion "Version: " label labelBuild "Build: Sep 10,2004" label labelCopyright1 "Copyright © 2004 MicroCAN" label labelCopyright2 "Carl van Heezik" label labelCopyright3 "All rights reserved." label labelEmpty2 label labelWebsite "www.microcan.nl" ) on rolloutAbout open do -- V2.01 ( labelVersion.text = "Version: " + versionText ) ) rollout rolloutMain versionText rolledUp:false ( group "Parameters" ( spinner iterateSpinner "Iterations " fieldWidth:50 range:[1,5000,iterations] type:#integer checkbox lockCheckbox "Lock scale " checked:lockScale across:2 spinner scaleSpinner "Scale" fieldWidth:50 range:[0.0001,1000,edgeScale] type:#float scale:0.0001 enabled:false checkbox bringUpCheckbox "Open UVW editor " checked:bringUpDialog ) label facesLabel " " align:#center button undistortButton "Undistort UV" width:100 align:#center tooltip:"undistort UV" on iterateSpinner changed value do -- V2.01 ( iterations = value ) on lockCheckbox changed state do ( lockScale = state -- V2.01 scaleSpinner.enabled = state ) on scaleSpinner changed value do -- V2.01 ( edgeScale = value ) on bringUpCheckbox changed state do -- V2.01 ( bringUpDialog = state ) fn redrawView = ( try ( local unwrap = modPanel.GetcurrentObject() undistortButton.enabled = isKindOf unwrap Unwrap_UVW if (undistortButton.enabled) then ( local faces = unwrap.getSelectedPolygons() as array undistortButton.enabled = (faces.count > 0) if (undistortButton.enabled) then ( facesLabel.text = faces.count as string + " faces" ) else ( facesLabel.text = " " ) ) ) catch() ) on rolloutMain open do ( redrawView() registerRedrawViewsCallback redrawView ) on rolloutMain close do ( unregisterRedrawViewsCallback redrawView ) on rolloutMain resized s do ( width = s.x height = s.y ) on rolloutMain moved p do ( left = p.x top = p.y ) fn undistortUv = ( local unwrap = modPanel.GetcurrentObject() if (isKindOf unwrap Unwrap_UVW) do ( local aMesh = $.mesh local faces = unwrap.getSelectedPolygons() as array local flatFaces = #() local faceIndex local face local uvFace local faceIndices local pointsInFace local f local v local i local n local edgeLength = 0 local uvEdgeLength = 0 -- variables for computing the face centroid local centroid -- variables for computing face the normal local vector1 local vector2 local normal local rotateAxis local angle local rotateAngle local rotation local swap local rotateVector local uvVertices = #() local uvShare = #() local uvDelta = #() local uvIndices = #() local delta local oldLevel = subObjectLevel -- V2.01 bringUpDialog = bringUpCheckbox.checked progressStart "uvHelp undistort" -- convert faces to flat faces (z = 0) flatFaces.count = faces.count uvIndices.count = faces.count uvVertices.count = unwrap.numberVertices() uvDelta.count = uvVertices.count uvShare.count = uvVertices.count for i = 1 to uvShare.count do ( if getProgressCancel() then ( progressEnd() return false ) uvShare[i] = 0 ) for f = 1 to faces.count do ( -- update progress bar if not (progressUpdate ((f * 100) / faces.count)) then ( progressEnd() return false ) faceIndex = faces[f] pointsInFace = unwrap.numberPointsInFace faceIndex face = #() face.count = pointsInFace flatFaces[f] = face uvFace = #() uvFace.count = pointsInFace faceIndices = #() faceIndices.count = pointsInFace uvIndices[f] = faceIndices -- copy face vertices and compute centroid centroid = [0,0,0] for v = 1 to pointsInFace do ( i = unwrap.getVertexGeomIndexFromFace faceIndex v face[v] = getVert aMesh i centroid = centroid + face[v] i = unwrap.getVertexIndexFromFace faceIndex v faceIndices[v] = i uvFace[v] = unwrap.getVertexPosition (0 as time) i uvVertices[i] = copy uvFace[v] uvVertices[i].z = 0.0 uvShare[i] = uvShare[i] + 1 ) -- compute edge length for v = 1 to pointsInFace do ( -- compute edge length n = v + 1 if (n > pointsInFace) then ( n = 1 ) edgeLength = edgeLength + distance face[v] face[n] uvEdgeLength = uvEdgeLength + distance uvFace[v] uvFace[n] ) if pointsInFace != 0 then ( centroid = centroid / pointsInFace ) -- compute rotation vector1 = face[1] - face[2]; vector2 = face[3] - face[2]; normal = normalize (cross vector2 vector1) rotateAxis = normalize (cross z_axis normal) rotateAngle = acos (dot normal z_axis) rotation = quat rotateAngle rotateAxis -- move centroid to origin and rotate to z = 0 plane for v = 1 to pointsInFace do ( face[v] = ((face[v] - centroid ) * rotation) face[v].z = 0.0 ) ) if (edgeLength > 0) then ( edgeScale = uvEdgeLength / edgeLength ) if lockCheckbox.checked then ( edgeScale = scaleSpinner.value ) else ( scaleSpinner.value = edgeScale ) -- scale all faces for f = 1 to faces.count do ( face = flatFaces[f] pointsInFace = face.count if not (progressUpdate ((f * 100) / faces.count)) then ( progressEnd() return false ) for v = 1 to pointsInFace do ( face[v] = face[v] * edgeScale ) ) for n = 1 to iterateSpinner.value do ( -- clear the delta for i = 1 to uvDelta.count do ( uvDelta[i] = [0,0,0] ) for f = 1 to faces.count do ( if getProgressCancel() then ( progressEnd() return false ) faceIndices = uvIndices[f] pointsInFace = faceIndices.count face = flatFaces[f] faceIndex = faces[f] uvFace = #() uvFace.count = pointsInFace centroid = [0,0,0] -- read the current UV face for v = 1 to pointsInFace do ( i = faceIndices[v] uvFace[v] = uvVertices[i] centroid = centroid + uvFace[v] ) if pointsInFace != 0 then ( centroid = centroid / pointsInFace ) -- format "uvFace % centroid %\n" uvFace centroid -- move to origin and compute avarage rotation rotateVector = [0,0,0] for v = 1 to pointsInFace do ( uvFace[v] = uvFace[v] - centroid -- compute rotation vector1 = normalize face[v] vector2 = normalize uvFace[v] normal = normalize (cross vector2 vector1) rotateAngle = acos(dot vector1 vector2) if normal.z < 0 then ( rotateAngle = -rotateAngle ) rotation = quat rotateAngle z_axis rotateVector = rotateVector + normalize (x_axis * rotation) ) vector1 = x_axis vector2 = normalize rotateVector normal = normalize (cross vector2 vector1) rotateAngle = acos(dot vector1 vector2) if normal.z < 0 then ( rotateAngle = -rotateAngle ) rotation = quat rotateAngle z_axis -- compute new UV face for v = 1 to pointsInFace do ( uvFace[v] = face[v] * rotation + centroid i = faceIndices[v] -- debug face -- unwrap.setFaceVertex uvFace[v] faceIndex v true uvDelta[i] = uvDelta[i] + uvFace[v] - uvVertices[i] ) ) for i = 1 to uvDelta.count do ( if (uvShare[i] > 0) then ( uvVertices[i] = uvVertices[i] + (uvDelta[i] / uvShare[i]) ) ) if not (progressUpdate ((n * 100) / iterateSpinner.value)) then ( progressEnd() return false ) ) undo "uvHelp: Undistort UV" on ( for i = 1 to uvDelta.count do ( if not (progressUpdate ((i * 100) / uvDelta.count)) then exit if (uvShare[i] > 0) then ( unwrap.setVertexPosition (0 as time) i uvVertices[i] ) ) ) progressEnd() if bringUpDialog then -- V2.01 ( unwrap.edit() -- V2.01 ) subObjectLevel = oldLevel -- V2.01 redrawViews() return true ) ) -- the real action is done when you press the button on undistortButton pressed do ( undistortUv() ) ) -- create the dialog if dialog != undefined then ( closeRolloutFloater dialog ) dialog = newRolloutFloater versionText width height left top addRollout rolloutMain dialog addRollout rolloutAbout dialog ) )