// =========================================================================== // Copyright 2018 Autodesk, Inc. All rights reserved. // // Use of this software is subject to the terms of the Autodesk license // agreement provided at the time of installation or download, or which // otherwise accompanies this software in either electronic or hard copy form. // =========================================================================== // =========================================================================== // // Procedure Name: // textureStackSimilarUVShells // // Description: // Stack similar UV Shells based on border identical. // // Input Arguments // None. // // Return Value: // None. // // =========================================================================== proc string[] getBorderUVPairs(string $borderUVs[], string $borderEdges[]) { string $borderUVPairs[]; // Get uv pairs which in border. for($borderEdge in $borderEdges) { $uvPairsStr = `polyEvaluate -uvEdgePairs $borderEdge`; $uvPairs = stringToStringArray($uvPairsStr[0], " "); for($j = 0; $j < size($uvPairs); $j=$j+2) { $uv1 = $uvPairs[$j]; $uv2 = $uvPairs[$j+1]; if(stringArrayFind($uv1, 0, $borderUVs) >= 0) { $borderUVPairs[size($borderUVPairs)] = $uv1; $borderUVPairs[size($borderUVPairs)] = $uv2; } } } // Reorder uv pairs to make them next to each other, // like [1,2,2,7,7,5,5,3,3,4,4,6..] for($j = 0; $j < size($borderUVPairs); $j=$j+2) { $tail = $borderUVPairs[$j+1]; for($jj = $j + 2; $jj < size($borderUVPairs); $jj=$jj+2) { $a = $borderUVPairs[$jj]; $b = $borderUVPairs[$jj+1]; if($a == $tail) { $borderUVPairs[$jj] = $borderUVPairs[$j+2]; $borderUVPairs[$jj+1] = $borderUVPairs[$j+3]; $borderUVPairs[$j+2] = $a; $borderUVPairs[$j+3] = $b; } else if($b == $tail) { $borderUVPairs[$jj] = $borderUVPairs[$j+2]; $borderUVPairs[$jj+1] = $borderUVPairs[$j+3]; $borderUVPairs[$j+2] = $b; $borderUVPairs[$j+3] = $a; } } } return $borderUVPairs; } proc float calculateDistance(float $u1, float $v1, float $u2, float $v2) { return sqrt(($u2 - $u1)*($u2 - $u1) + ($v2 - $v1)*($v2 - $v1)); } proc int checkShellsMatch(string $matchLens[], string $matchTriLens[], string $matchCrosses[], float $Lens[], float $triLens[], float $crosses[],float $scaleRatio, int $shift) { $size = size($Lens); for($i = 0; $i < $size; $i++) { float $matchLensFloat = $matchLens[$i]; float $matchTriLensFloat = $matchTriLens[$i]; float $matchCrossesFloat = $matchCrosses[$i]; int $shiftI = ($i + $shift < $size) ? ($i + $shift) : ($i + $shift - $size); $diffLen = ($matchLensFloat - $Lens[$shiftI]*$scaleRatio)/($matchLensFloat + $Lens[$shiftI]*$scaleRatio); $diffStrLen = ($matchTriLensFloat - $triLens[$shiftI]*$scaleRatio)/($matchTriLensFloat + $triLens[$shiftI]*$scaleRatio); $diffCross = $matchCrossesFloat - $crosses[$shiftI]; if( abs($diffLen) > 0.05 || abs($diffStrLen) > 0.05 || abs($diffCross) > 0.1) { return false; } } return true; } proc float[] shiftFloatArray(float $array[]) { $tail = $array[size($array)-1]; for ($i = size($array)-1; $i > 0; $i--) { $array[$i] = $array[$i-1]; } $array[0] = $tail; return $array; } proc matchTwoShells(float $mAu, float $mAv, float $mBu, float $mBv, float $tAu, float $tAv, float $tBu, float $tBv, float $scaleRatio) { float $moveU = ($mAu - $tAu); float $moveV = ($mAv - $tAv); polyEditUV -u $moveU -v $moveV; vector $vm = <<($mBu-$mAu), ($mBv-$mAv)>>; vector $vt = <<($tBu-$tAu), ($tBv-$tAv)>>; float $angle = rad_to_deg(`angle $vm $vt`); vector $cross = cross($vm, $vt); float $sign = $cross.z; if($sign > 0) $angle = -$angle; polyEditUV -a $angle -pu $mAu -pv $mAv; polyEditUV -pu $mAu -pv $mAv -su $scaleRatio -sv $scaleRatio; } proc float[] reverseFloatArray(float $array[]){ float $reversed[]; int $arraySize = `size $array`; for ($n = 0; $n < $arraySize; $n++){ $reversed[( $arraySize - 1 - $n )] = $array[$n]; } return $reversed; } global proc textureStackSimilarUVShells() { $sel = `ls -sl`; $shells = texGetShells(); if(size($shells) < 2) return; int $shellsUVNbs[]; // Save border UV numbers of each shell string $shellsUs[]; // Save border Us of each shell string $shellsVs[]; // Save border Vs of each shell string $shellsLens[]; // Save border edges length of each shell string $shellsTriLens[]; // Save border triangle edges length of each shell string $shellsCrosses[]; // Save border vector corsses of each shell float $shellsPerimeters[]; // Save perimeters of each shell global string $gMainProgressBar; progressBar -e -bp -max (size($shells)) $gMainProgressBar; for($i = 0; $i < size($shells); $i++) { progressBar -e -s 1 $gMainProgressBar; eval("select -r " + $shells[$i]); int $ufo[] = `polySelectConstraint -uvc 1 -q -ufo`; int $bo = `polySelectConstraint -uvc 1 -q -border`; int $ubs = `polySelectConstraint -uvc 1 -q -uvBorderSelection`; int $uv = `polySelectConstraint -uvc 1 -q -uv`; polySelectConstraint -uvc 1 -type 0x0010 -ufo 0 -bo 1 -uvBorderSelection 0 -uv 0 -mode 2; $borderUVs = `ls -sl`; $borderUVs = `filterExpand -ex true -sm 35 $borderUVs`; $borderEdges = `polyListComponentConversion -te`; select -r $borderEdges; polySelectConstraint -uvc 1 -t 0x8000 -ufo 0 -bo 1 -ubs 0 -uv 0 -m 2; polySelectConstraint -uvc 1 -t 0 -ufo $ufo[0] -bo $bo -ubs $ubs -uv $uv -m 1; $borderEdges = `ls -sl`; $borderEdges = `filterExpand -ex true -sm 32 $borderEdges`; // Get border UV pairs string $borderUVPairs[] = getBorderUVPairs($borderUVs, $borderEdges); // Get ordered UVs in border. // [1,2,2,7,7,5,5,3,3,4,4,6..] -> [1,2,7,5,3,4] string $borderOrderedUVs[]; float $Us[]; float $Vs[]; for($j = 0; $j < size($borderUVPairs); $j=$j+2) { float $uv[] = `polyEditUV -q -u -v $borderUVPairs[$j]`; $borderOrderedUVs[size($borderOrderedUVs)] = $borderUVPairs[$j]; $Us[size($Us)] = $uv[0]; $Vs[size($Vs)] = $uv[1]; } int $nbUVs = size($borderOrderedUVs); float $lens[]; float $triLens[]; float $crosses[]; float $perimeter = 0; for($j = 0; $j < $nbUVs; $j++) { int $previous = $j - 1; int $next = $j + 1; if($j == 0) { $previous = $nbUVs-1; } else if($j == ($nbUVs - 1)) { $next = 0; } $preLen = calculateDistance($Us[$j], $Vs[$j], $Us[$previous], $Vs[$previous]); $lens[$j] = $preLen; $perimeter += $preLen; $triLens[$j] = calculateDistance($Us[$previous], $Vs[$previous], $Us[$next], $Vs[$next]); $nextLen = calculateDistance($Us[$j], $Vs[$j], $Us[$next], $Vs[$next]); vector $va = <<($Us[$previous]-$Us[$j]), ($Vs[$previous]-$Vs[$j])>>; if( $preLen > 0) { float $nvax = $va.x/$preLen; float $nvay = $va.y/$preLen; $va = <<$nvax, $nvay>>; } vector $vb = <<($Us[$next]-$Us[$j]), ($Vs[$next]-$Vs[$j])>>; if( $nextLen > 0) { float $nvbx = $vb.x/$nextLen; float $nvby = $vb.y/$nextLen; $vb = <<$nvbx, $nvby>>; } vector $cr = cross($va, $vb); float $z = $cr.z; // If two uv strings is reverse, they have opposite cr.z value. $crosses[$j] = $z; } if($perimeter < 1e-4) // This shell too small continue; // Find match or save data $matched = false; $toMatchNb = size($shellsUVNbs); for($j = 0; $j < $toMatchNb; $j++) { $matchUVNbs = $shellsUVNbs[$j]; if($matchUVNbs != $nbUVs) // Border UV number not match, try next mesh continue; $matchUs = stringToStringArray($shellsUs[$j], " "); $matchVs = stringToStringArray($shellsVs[$j], " "); $matchLens = stringToStringArray($shellsLens[$j], " "); $matchTriLens = stringToStringArray($shellsTriLens[$j], " "); $matchCrosses = stringToStringArray($shellsCrosses[$j], " "); float $matchPerimeter = $shellsPerimeters[$j]; int $shift = 0; // $matchUVNbs*2 since consider reverse direction. for($jj = 0; $jj < ($matchUVNbs*2); $jj++) { if($jj == $matchUVNbs) { $borderOrderedUVs = texReverseStringArray($borderOrderedUVs); $Us = reverseFloatArray($Us); $Vs = reverseFloatArray($Vs); $lens = reverseFloatArray($lens); $lens = shiftFloatArray($lens); $triLens = reverseFloatArray($triLens); $crosses = reverseFloatArray($crosses); for($k = 0; $k < $matchUVNbs; $k++) { $crosses[$k] = -$crosses[$k]; } $shift = 0; } float $scaleRatio = $matchPerimeter/$perimeter; if(checkShellsMatch($matchLens, $matchTriLens, $matchCrosses, $lens, $triLens ,$crosses, $scaleRatio, $shift)) { $matched = true; // MATCH!!! int $nextShift = ($shift == ($matchUVNbs - 1))?0:$shift+1; eval("select -r "+$shells[$i]); matchTwoShells($matchUs[0], $matchVs[0], $matchUs[1], $matchVs[1], $Us[$shift], $Vs[$shift], $Us[$nextShift], $Vs[$nextShift], $scaleRatio); break; } $shift++; } if($matched) break; } if(!$matched) { // Save data $shellsUVNbs[$toMatchNb] = $nbUVs; $shellsUs[$toMatchNb] = floatArrayToString($Us, " "); $shellsVs[$toMatchNb] = floatArrayToString($Vs, " "); $shellsLens[$toMatchNb] = floatArrayToString($lens, " "); $shellsTriLens[$toMatchNb] = floatArrayToString($triLens, " "); $shellsCrosses[$toMatchNb] = floatArrayToString($crosses, " "); $shellsPerimeters[$toMatchNb] = $perimeter; } } progressBar -e -endProgress $gMainProgressBar; select -r $sel; }