// =========================================================================== // 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. // =========================================================================== // smoothParamSurface - reparameterize a surface to get smoother parameter // distribution in both directions // // Usage: // smoothParamSurface(int , int ); // // where: is a toggle turning history on or off // is the number of output patches per input patch // in the U direction. // // How it works: // 1. Extracts isoparms in V direction, rebuilds as uniform // 2. Lofts these splines in U using chord length option // // Usage hints: // - Using a larger number of samples increases accuracy, but can get // slow. Try with 1 first, then increase as needed. // - history on means the original surface can be tweaked and the changes // will be seen on the reparameterized surface, but the cost is the storage // of a large number of intermediate curves used to generate the reparameterized // surface. // // // proc int getNurbsSurfaceKnots(string $srfName, float $uKnots[], float $vKnots[] ) // // Description : // Get surface knots in U and V { // create info Node. string $infoNode ; if( catch( $infoNode = `createNode surfaceInfo` ) ) { return 1; // failed } // connect surface on to the info node. string $outAttr = $srfName + ".local" ; string $inAttr = $infoNode + ".is" ; connectAttr $outAttr $inAttr ; // read the knots. $uKnots = `getAttr ($infoNode + ".knotsU")`; $vKnots = `getAttr ($infoNode + ".knotsV")`; // delete surface info node. delete $infoNode ; // worked return 0; } proc int getNurbsSurfaceSmoothParam( string $srf, int $ch, int $samplesPerSpan) // // Description : // Compute reparam surface by computing points // regularly spaced in U and V on the surface, fitting curves // and then lofting a surface through the curves. // { int $i; // loop counter // number of spans int $nspansU = eval("getAttr " + $srf + ".spansU"); // degree int $degreeU = eval("getAttr " + $srf + ".degreeU"); // knots float $uKnots[]; float $vKnots[]; if(getNurbsSurfaceKnots($srf, $uKnots, $vKnots)) { return 1; // failed } // first and last knot values to use int $firstU = $degreeU - 1; int $lastU = $nspansU + $firstU; // loop over knot values int $uIndex, $vIndex; int $uSample, $vSample; int $uSampleMax, $vSampleMax; float $u; string $allCurves; // check if periodic in U. If so, dont need to evaluate last U // isoparm on surface since it is coincident with the first int $formInU = eval("getAttr " + $srf + ".formU"); // loop over U spans for($uIndex = $firstU; $uIndex < $lastU; $uIndex++) { // maximum number of samples for this span $uSampleMax = ($formInU == 2 || $uIndex < $lastU-1) ? $samplesPerSpan - 1 : $samplesPerSpan; // parameter interval for this span float $uInterval = $uKnots[$uIndex+1] - $uKnots[$uIndex]; // loop over U samples for($uSample = 0; $uSample <= $uSampleMax; $uSample++) { // get value of U $u = $uKnots[$uIndex] + $uSample*$uInterval/float($samplesPerSpan); // make sure rouding errors dont take it off the end if($uIndex == ($formInU == 2 || $lastU-1) && $uSample == $uSampleMax) { $u = $uKnots[$lastU]; } // extract this isoparm string $dup[] = eval("duplicateCurve -ch " + $ch + " -rn 0 -local 0 " + $srf + ".u[" + $u + "]"); int $nspans = eval("getAttr " + $dup[0] + ".spans"); // rebuild isoparm with uniform knots - replace original extracted isoparm string $reb[] = eval("rebuildCurve -ch " + $ch + " -rpo 1 -rt 0 -kr 1 -kcp 0 -kep 1 -kt 0 -s " + $nspans + " -d 3 -tol 0.05 " + $dup[0]); $allCurves += " " + $reb[0]; } } //print ("All curves are: " + $allCurves + "\n"); // now loft the curves using reparam option string $loftCmd = "loft -ch " + $ch + " -d 3 -u 0"; if($formInU == 2) $loftCmd += " -c on "; $loftCmd += $allCurves; //print("Loft command is " + $loftCmd + "\n"); // close flag - check basic surface first... string $outsrf[] = eval($loftCmd); print (`format -s $outsrf[0] (uiRes("m_smoothParamSurface.kCreatedReparamSurface"))` ); // delete all input curves if no history requested if(0 == $ch) { eval("delete " + $allCurves); } // return the surface name?? return 0; } global proc smoothParamSurface(int $ch, int $samplesPerSpan) { if($ch>=1) { print (uiRes("m_smoothParamSurface.kSettingConstructionHistoryOn")); $ch = 1; } if($ch<=0) { print (uiRes("m_smoothParamSurface.kSettingConstructionHistoryOff")); $ch = 0; } // always need at least one sample per span if($samplesPerSpan < 1) $samplesPerSpan = 1; // Run filter to select only the NURBS surfaces global int $gSelectNurbsSurfacesBit ; string $srfList[] = `filterExpand -ex true -sm $gSelectNurbsSurfacesBit`; int $len = size($srfList) ; if( $len == 0 ) { print (uiRes("m_smoothParamSurface.kNoSurfaceSelected")) ; return; } // Work on all surfaces for($srfNum = 0; $srfNum < $len; $srfNum++) { string $srf = $srfList[$srfNum] ; // do the smoothParam if(getNurbsSurfaceSmoothParam($srf, $ch, $samplesPerSpan)) { print (`format -s $srf (uiRes("m_smoothParamSurface.kFailedToReparameterizeSurface"))` ); break; } } }